From 60844359acf10405a7994b2b1f90997abcefe951 Mon Sep 17 00:00:00 2001 From: mage2-team <mage2-team@magento.com> Date: Sat, 2 Feb 2013 10:31:43 -0800 Subject: [PATCH] 2.0.0.0-dev40 * Implemented ability to customize all the main directory paths for the application, i.e. locations of `var`, `etc`, `media` and other directories * Implemented ability to pass application configuration data from the environment * Magento Web API changes: * Added SOAP V2 API coverage from Magento 1.x * Improved integration testing framework to develop Web API tests. Covered SOAP V2 API with positive integration tests. * Changed `Mage_Webapi` module front name from `api` to `webapi` * Improvements for product creation UI: * Implemented AJAX suggestions popup and categories tree popup for convenient assignment of categories * Moved selection of Bundle and Grouped sub-products to the "General" tab, implemented popup grids for them * Made "Weight" checkbox to be selected by default for a Configurable product * Implemented integration test to measure and control PHP memory leak on application reinitialization * Changed format of configuration files for static tests that search for obsolete Magento 1.x code * Bug fixes: * Fixed Web API WSDL incompatibility with C# and Java * Fixed issue, that Magento duplicated custom options field for a product, if creating them via a multi-call to API * Fixed `shoppingCartPaymentList` method in Web API, which was throwing exception "Object has no 'code' property" * Fixed invalid Wishlist link and several invalid links in Checkout on frontend store view * Made Stock Status in 'quantity_and_stock_status' attribute editable again for a Configurable product * Fixed issue, that it was not possible to save Customer after first save, because "Date Of Birth" format was reported by Magento to be incorrect * Fixed fatal error in Code Sniffer exemplar test * Fixed wrong failures of `Varien_Db_Adapter_Pdo_MysqlTest::testWaitTimeout()` integration test in developer mode * Fixed issue, that mass-action column in backend grids moved to another position in single store mode --- .gitignore | 1 - .htaccess | 5 - CHANGELOG.markdown | 25 + app/Mage.php | 106 +- app/bootstrap.php | 32 +- .../core/Mage/Adminhtml/Block/Api/Buttons.php | 88 + .../Mage/Adminhtml/Block/Api/Editroles.php | 69 + .../Mage/Adminhtml/Block/Api/Grid/Role.php | 81 + .../core/Mage/Adminhtml/Block/Api/Role.php | 37 + .../Adminhtml/Block/Api/Role/Grid/User.php | 182 ++ .../core/Mage/Adminhtml/Block/Api/Roles.php | 48 + .../Mage/Adminhtml/Block/Api/Tab/Roleinfo.php | 69 + .../Adminhtml/Block/Api/Tab/Rolesedit.php | 122 + .../Adminhtml/Block/Api/Tab/Rolesusers.php | 54 + .../Zend.php => Adminhtml/Block/Api/User.php} | 51 +- .../Mage/Adminhtml/Block/Api/User/Edit.php | 58 + .../Adminhtml/Block/Api/User/Edit/Form.php | 45 + .../Block/Api/User/Edit/Tab/Main.php | 153 + .../Block/Api/User/Edit/Tab/Roles.php | 119 + .../Adminhtml/Block/Api/User/Edit/Tabs.php | 65 + .../Mage/Adminhtml/Block/Api/User/Grid.php | 106 + .../Adminhtml/Block/Catalog/Category/Tree.php | 2 +- .../Product/Edit/Tab/Options/Option.php | 4 +- .../Edit/Tab/Options/Type/Abstract.php | 2 +- .../Catalog/Product/Edit/Tab/Super/Group.php | 236 -- .../Product/Frontend/Product/Watermark.php | 4 +- .../Catalog/Product/Helper/Form/Category.php | 48 +- .../Block/Catalog/Product/Options/Ajax.php | 2 +- .../Block/Customer/Edit/Renderer/Newpass.php | 4 +- .../Block/Customer/Edit/Renderer/Region.php | 2 +- .../core/Mage/Adminhtml/Block/Html/Date.php | 74 - .../core/Mage/Adminhtml/Block/Html/Select.php | 70 - .../core/Mage/Adminhtml/Block/Messages.php | 72 - .../Adminhtml/Block/Notification/Baseurl.php | 6 +- .../core/Mage/Adminhtml/Block/Page/Footer.php | 2 +- .../core/Mage/Adminhtml/Block/Page/Head.php | 6 +- .../Block/Promo/Quote/Edit/Tab/Labels.php | 8 +- .../Quote/Edit/Tab/Main/Renderer/Checkbox.php | 2 +- .../Block/Promo/Widget/Chooser/Daterange.php | 2 +- .../Adminhtml/Block/Rating/Edit/Tab/Form.php | 8 +- .../Block/Sales/Order/Create/Messages.php | 2 +- .../Block/Sales/Order/View/Messages.php | 2 +- .../Block/System/Currency/Rate/Services.php | 2 +- .../Block/System/Email/Template/Edit.php | 7 +- .../core/Mage/Adminhtml/Model/Extension.php | 402 --- .../controllers/Api/RoleController.php | 217 ++ .../controllers/Api/UserController.php | 190 ++ .../controllers/Catalog/ProductController.php | 18 +- .../adminhtml/api/role_users_grid_js.phtml | 105 + .../view/adminhtml/api/roleinfo.phtml | 47 + .../Adminhtml/view/adminhtml/api/roles.phtml | 31 +- .../view/adminhtml/api/rolesedit.phtml | 143 + .../view/adminhtml/api/rolesusers.phtml | 8 +- .../adminhtml/api/user_roles_grid_js.phtml | 85 + .../view/adminhtml/api/userinfo.phtml | 52 + .../view/adminhtml/api/usernroles.phtml | 11 +- .../Mage/Adminhtml/view/adminhtml/catalog.xml | 208 +- .../adminhtml/catalog/product-variation.js | 2 +- .../view/adminhtml/catalog/product.js | 573 ---- .../product/composite/fieldset/grouped.phtml | 2 +- .../view/adminhtml/catalog/product/edit.phtml | 72 +- .../catalog/product/edit/options.phtml | 6 +- .../edit/super/attribute-js-template.phtml | 4 +- .../edit/super/attribute-template.phtml | 6 +- .../catalog/product/edit/super/config.phtml | 13 +- .../catalog/product/tab/inventory.phtml | 2 +- .../view/adminhtml/catalog/type-switcher.js | 8 +- .../Mage/Adminhtml/view/adminhtml/main.xml | 1 - .../view/adminhtml/page/js/components.phtml | 27 +- .../adminhtml/resetforgottenpassword.phtml | 89 - app/code/core/Mage/Api/Controller/Action.php | 61 + app/code/core/Mage/Api/Exception.php | 53 + app/code/core/Mage/Api/Helper/Data.php | 359 +++ app/code/core/Mage/Api/Model/Acl.php | 103 + app/code/core/Mage/Api/Model/Acl/Resource.php | 38 + app/code/core/Mage/Api/Model/Acl/Role.php | 37 + .../core/Mage/Api/Model/Acl/Role/Generic.php | 38 + .../core/Mage/Api/Model/Acl/Role/Group.php | 38 + .../core/Mage/Api/Model/Acl/Role/Registry.php | 76 + .../core/Mage/Api/Model/Acl/Role/User.php | 38 + app/code/core/Mage/Api/Model/Config.php | 294 ++ .../core/Mage/Api/Model/Resource/Abstract.php | 105 + app/code/core/Mage/Api/Model/Resource/Acl.php | 145 + .../core/Mage/Api/Model/Resource/Acl/Role.php | 59 + .../Model/Resource/Acl/Role/Collection.php | 45 + .../Model/Resource/Permissions/Collection.php | 45 + .../core/Mage/Api/Model/Resource/Role.php | 76 + .../Api/Model/Resource/Role/Collection.php | 69 + .../core/Mage/Api/Model/Resource/Roles.php | 151 + .../Api/Model/Resource/Roles/Collection.php | 67 + .../Model/Resource/Roles/User/Collection.php | 59 + .../core/Mage/Api/Model/Resource/Rules.php | 87 + .../Api/Model/Resource/Rules/Collection.php | 69 + .../core/Mage/Api/Model/Resource/User.php | 435 +++ .../Api/Model/Resource/User/Collection.php | 45 + app/code/core/Mage/Api/Model/Role.php | 58 + app/code/core/Mage/Api/Model/Roles.php | 181 ++ app/code/core/Mage/Api/Model/Rules.php | 69 + app/code/core/Mage/Api/Model/Server.php | 161 + .../Mage/Api/Model/Server/Adapter/Soap.php | 241 ++ .../Api/Model/Server/Adapter/Soap/Wsi.php | 104 + .../Mage/Api/Model/Server/Handler/Soap.php | 60 + .../Api/Model/Server/Handler/Soap/Wsi.php | 182 ++ .../Mage/Api/Model/Server/HandlerAbstract.php | 416 +++ app/code/core/Mage/Api/Model/Session.php | 207 ++ app/code/core/Mage/Api/Model/User.php | 254 ++ app/code/core/Mage/Api/Model/Wsdl/Config.php | 140 + .../core/Mage/Api/Model/Wsdl/Config/Base.php | 136 + .../Mage/Api/Model/Wsdl/Config/Element.php | 272 ++ .../Api/controllers/Soap/WsiController.php | 42 + .../Mage/Api/controllers/SoapController.php | 42 + app/code/core/Mage/Api/etc/adminhtml.xml | 62 + app/code/core/Mage/Api/etc/adminhtml/menu.xml | 39 + .../core/Mage/Api/etc/adminhtml/system.xml | 50 + app/code/core/Mage/Api/etc/api.xml | 260 ++ app/code/core/Mage/Api/etc/config.xml | 107 + app/code/core/Mage/Api/etc/wsdl.xml | 242 ++ app/code/core/Mage/Api/etc/wsi.xml | 381 +++ .../core/Mage/Api/locale/de_DE/Mage_Api.csv | 16 + .../core/Mage/Api/locale/en_US/Mage_Api.csv | 16 + .../core/Mage/Api/locale/es_ES/Mage_Api.csv | 16 + .../core/Mage/Api/locale/fr_FR/Mage_Api.csv | 16 + .../core/Mage/Api/locale/nl_NL/Mage_Api.csv | 16 + .../core/Mage/Api/locale/pt_BR/Mage_Api.csv | 16 + .../core/Mage/Api/locale/zh_CN/Mage_Api.csv | 16 + .../Api/sql/api_setup/install-1.6.0.0.php | 208 ++ app/code/core/Mage/Backend/Block/Abstract.php | 10 +- .../Block/Catalog/Product/Tab/Container.php | 70 + .../Mage/Backend/Block/Store/Switcher.php | 8 +- .../Mage/Backend/Block/System/Config/Edit.php | 6 +- .../Mage/Backend/Block/System/Config/Form.php | 9 +- .../Block/System/Config/Form/Field.php | 10 +- .../System/Config/Form/Field/Heading.php | 2 +- .../Block/System/Config/Form/Fieldset.php | 2 +- .../Mage/Backend/Block/System/Config/Tabs.php | 9 +- app/code/core/Mage/Backend/Block/Template.php | 6 +- .../Block/Widget/Form/Element/Dependence.php | 2 +- .../Mage/Backend/Block/Widget/Grid/Column.php | 36 +- .../Widget/Grid/Column/Filter/Abstract.php | 2 +- .../Block/Widget/Grid/Column/Multistore.php | 8 +- .../Widget/Grid/Column/Renderer/Abstract.php | 2 +- .../Widget/Grid/Column/Renderer/Button.php | 45 + .../Widget/Grid/Column/Renderer/Currency.php | 13 +- .../Widget/Grid/Column/Renderer/Grip.php | 42 + .../Backend/Block/Widget/Grid/ColumnSet.php | 8 +- .../Block/Widget/Grid/Massaction/Abstract.php | 5 +- .../Backend/Model/Config/Backend/Baseurl.php | 176 +- .../Mage/Backend/etc/adminhtml/system.xml | 39 +- .../Backend/view/adminhtml/widget/grid.phtml | 4 + .../adminhtml/widget/grid/serializer.phtml | 2 +- .../Product/Edit/Tab/Attributes/Extend.php | 8 +- .../Catalog/Product/Edit/Tab/Bundle.php | 2 +- .../Product/Edit/Tab/Bundle/Option.php | 18 +- .../Product/Edit/Tab/Bundle/Option/Search.php | 40 +- .../Edit/Tab/Bundle/Option/Search/Grid.php | 84 +- .../Edit/Tab/Bundle/Option/Selection.php | 6 +- .../view/adminhtml/css/bundle-product.css | 84 + .../view/adminhtml/js/bundle-product.js | 206 ++ .../Mage/Bundle/view/adminhtml/layout.xml | 10 +- .../view/adminhtml/product/edit/bundle.phtml | 44 +- .../product/edit/bundle/option.phtml | 180 +- .../product/edit/bundle/option/search.phtml | 13 +- .../edit/bundle/option/selection.phtml | 252 +- app/code/core/Mage/Captcha/Helper/Data.php | 22 +- app/code/core/Mage/Captcha/Model/Zend.php | 18 +- app/code/core/Mage/Captcha/etc/config.xml | 2 +- .../Backend/Grid/ColumnSet.php | 6 +- .../Product/Grouped/AssociatedProducts.php | 44 + .../Grouped/AssociatedProducts/Grid.php | 137 + .../core/Mage/Catalog/Model/Api/Resource.php | 135 + .../core/Mage/Catalog/Model/Category/Api.php | 524 +++ .../Mage/Catalog/Model/Category/Api/V2.php | 165 + .../Catalog/Model/Category/Attribute/Api.php | 109 + .../Model/Category/Attribute/Api/V2.php | 36 + .../Category/Attribute/Backend/Image.php | 1 - app/code/core/Mage/Catalog/Model/Config.php | 1 + .../core/Mage/Catalog/Model/Product/Api.php | 528 +++ .../Mage/Catalog/Model/Product/Api/V2.php | 308 ++ .../Catalog/Model/Product/Attribute/Api.php | 526 +++ .../Model/Product/Attribute/Api/V2.php | 99 + .../Model/Product/Attribute/Backend/Media.php | 70 +- .../Model/Product/Attribute/Media/Api.php | 421 +++ .../Model/Product/Attribute/Media/Api/V2.php | 53 + .../Model/Product/Attribute/Set/Api.php | 287 ++ .../Model/Product/Attribute/Set/Api/V2.php | 36 + .../Model/Product/Attribute/Tierprice/Api.php | 185 ++ .../Product/Attribute/Tierprice/Api/V2.php | 91 + .../Mage/Catalog/Model/Product/Link/Api.php | 349 ++ .../Catalog/Model/Product/Link/Api/V2.php | 119 + .../Mage/Catalog/Model/Product/Option/Api.php | 331 ++ .../Catalog/Model/Product/Option/Api/V2.php | 81 + .../Model/Product/Option/Value/Api.php | 226 ++ .../Model/Product/Option/Value/Api/V2.php | 104 + .../Mage/Catalog/Model/Product/Type/Api.php | 54 + .../Catalog/Model/Product/Type/Api/V2.php | 36 + .../Model/Product/Type/Configurable.php | 10 - .../Grouped/AssociatedProductsCollection.php | 70 + app/code/core/Mage/Catalog/etc/api.xml | 828 +++++ app/code/core/Mage/Catalog/etc/wsdl.xml | 2326 +++++++++++++ app/code/core/Mage/Catalog/etc/wsi.xml | 2866 +++++++++++++++++ .../view/adminhtml/js/grouped-product.js | 182 ++ .../adminhtml/product/grouped/container.phtml | 32 +- .../adminhtml/product/grouped/grouped.phtml | 64 + .../view/adminhtml/product/product.css | 9 + .../Block/Adminhtml/Form/Field/Stock.php | 35 +- .../CatalogInventory/Model/Stock/Item/Api.php | 75 + .../Model/Stock/Item/Api/V2.php | 89 + .../core/Mage/CatalogInventory/etc/api.xml | 81 + .../core/Mage/CatalogInventory/etc/wsdl.xml | 102 + .../core/Mage/CatalogInventory/etc/wsi.xml | 133 + .../view/frontend/form.mini.phtml | 1 + .../core/Mage/Checkout/Model/Api/Resource.php | 218 ++ .../Checkout/Model/Api/Resource/Customer.php | 213 ++ .../Checkout/Model/Api/Resource/Product.php | 128 + .../core/Mage/Checkout/Model/Cart/Api.php | 366 +++ .../core/Mage/Checkout/Model/Cart/Api/V2.php | 47 + .../Mage/Checkout/Model/Cart/Coupon/Api.php | 97 + .../Checkout/Model/Cart/Coupon/Api/V2.php | 38 + .../Mage/Checkout/Model/Cart/Customer/Api.php | 232 ++ .../Checkout/Model/Cart/Customer/Api/V2.php | 70 + .../Mage/Checkout/Model/Cart/Payment/Api.php | 200 ++ .../Checkout/Model/Cart/Payment/Api/V2.php | 45 + .../Mage/Checkout/Model/Cart/Product/Api.php | 330 ++ .../Checkout/Model/Cart/Product/Api/V2.php | 76 + .../Mage/Checkout/Model/Cart/Shipping/Api.php | 117 + .../Checkout/Model/Cart/Shipping/Api/V2.php | 38 + app/code/core/Mage/Checkout/etc/api.xml | 536 +++ app/code/core/Mage/Checkout/etc/wsdl.xml | 805 +++++ app/code/core/Mage/Checkout/etc/wsi.xml | 1018 ++++++ .../core/Mage/Cms/Helper/Wysiwyg/Images.php | 4 +- .../Mage/Cms/Model/Wysiwyg/Images/Storage.php | 2 +- .../Extension/Custom/Edit/Tab/Local.php | 2 +- .../core/Mage/Connect/Model/Extension.php | 12 +- app/code/core/Mage/Core/Block/Template.php | 95 +- .../Core/Controller/Varien/Router/Base.php | 23 +- app/code/core/Mage/Core/Helper/Data.php | 7 +- app/code/core/Mage/Core/Model/App.php | 182 +- .../core/Mage/Core/Model/App/Emulation.php | 2 +- app/code/core/Mage/Core/Model/App/Options.php | 133 - app/code/core/Mage/Core/Model/Cache.php | 26 +- app/code/core/Mage/Core/Model/Config.php | 253 +- .../core/Mage/Core/Model/Config/Options.php | 325 -- .../core/Mage/Core/Model/Design/Fallback.php | 84 +- .../Model/Design/Fallback/CachingProxy.php | 137 +- .../core/Mage/Core/Model/Design/Package.php | 96 +- app/code/core/Mage/Core/Model/Dir.php | 311 ++ app/code/core/Mage/Core/Model/Encryption.php | 29 +- .../Core/Model/Layout/Argument/Processor.php | 5 - .../core/Mage/Core/Model/Layout/Merge.php | 2 +- .../Core/Model/Layout/ScheduledStructure.php | 15 - app/code/core/Mage/Core/Model/Logger.php | 28 +- app/code/core/Mage/Core/Model/Magento/Api.php | 49 + .../core/Mage/Core/Model/Magento/Api/V2.php | 19 +- app/code/core/Mage/Core/Model/Observer.php | 2 +- app/code/core/Mage/Core/Model/Store.php | 167 +- app/code/core/Mage/Core/Model/Store/Api.php | 96 + .../Model/Store/Api/V2.php} | 10 +- app/code/core/Mage/Core/Model/Store/Group.php | 18 +- app/code/core/Mage/Core/Model/Theme.php | 3 +- .../Mage/Core/Model/Theme/Registration.php | 49 - .../core/Mage/Core/Model/Theme/Service.php | 6 +- app/code/core/Mage/Core/Model/Translate.php | 17 +- app/code/core/Mage/Core/etc/api.xml | 103 + app/code/core/Mage/Core/etc/config.xml | 20 +- app/code/core/Mage/Core/etc/wsdl.xml | 105 + app/code/core/Mage/Core/etc/wsi.xml | 148 + .../core/Mage/Customer/Model/Address/Api.php | 143 + .../Mage/Customer/Model/Address/Api/V2.php | 163 + .../core/Mage/Customer/Model/Api/Resource.php | 90 + .../core/Mage/Customer/Model/Customer/Api.php | 196 ++ .../Mage/Customer/Model/Customer/Api/V2.php | 50 + .../core/Mage/Customer/Model/Group/Api.php | 53 + .../core/Mage/Customer/Model/Group/Api/V2.php | 36 + app/code/core/Mage/Customer/etc/api.xml | 179 + app/code/core/Mage/Customer/etc/wsdl.xml | 354 ++ app/code/core/Mage/Customer/etc/wsi.xml | 507 +++ .../Editor/Toolbar/HandlesHierarchy.php | 7 +- .../Theme/Selector/List/Abstract.php | 10 +- .../Theme/Selector/List/Available.php | 6 +- .../Adminhtml/Theme/Selector/StoreView.php | 7 +- .../Controller/Varien/Router/Standard.php | 56 +- .../core/Mage/DesignEditor/Model/State.php | 3 +- .../core/Mage/Directory/Model/Country/Api.php | 54 + .../Mage/Directory/Model/Country/Api/V2.php | 36 + .../core/Mage/Directory/Model/Region/Api.php | 62 + .../Mage/Directory/Model/Region/Api/V2.php | 36 + app/code/core/Mage/Directory/etc/api.xml | 85 + app/code/core/Mage/Directory/etc/wsdl.xml | 90 + app/code/core/Mage/Directory/etc/wsi.xml | 119 + .../Product/Edit/Tab/Downloadable/Links.php | 2 +- .../core/Mage/Downloadable/Model/Link/Api.php | 277 ++ .../Downloadable/Model/Link/Api/Uploader.php | 129 + .../Mage/Downloadable/Model/Link/Api/V2.php | 67 + .../Downloadable/Model/Link/Api/Validator.php | 286 ++ app/code/core/Mage/Downloadable/etc/api.xml | 156 + app/code/core/Mage/Downloadable/etc/wsdl.xml | 193 ++ app/code/core/Mage/Downloadable/etc/wsi.xml | 220 ++ app/code/core/Mage/GiftMessage/Model/Api.php | 187 ++ .../core/Mage/GiftMessage/Model/Api/V2.php | 113 + app/code/core/Mage/GiftMessage/etc/api.xml | 92 + app/code/core/Mage/GiftMessage/etc/wsdl.xml | 123 + app/code/core/Mage/GiftMessage/etc/wsi.xml | 161 + .../Block/Adminhtml/Types/Edit/Attributes.php | 2 +- .../Block/Adminhtml/Import/Edit/Before.php | 8 +- .../Model/Import/Entity/Product.php | 12 +- .../core/Mage/Index/Model/Lock/Storage.php | 13 +- app/code/core/Mage/Install/Helper/Data.php | 61 - app/code/core/Mage/Install/Model/Config.php | 13 +- .../core/Mage/Install/Model/Installer.php | 8 +- .../Mage/Install/Model/Installer/Config.php | 125 +- .../Mage/Install/Model/Installer/Console.php | 59 +- .../Install/controllers/IndexController.php | 4 +- .../Install/controllers/WizardController.php | 18 - app/code/core/Mage/Install/etc/install.xml | 12 +- .../Adminhtml/Oauth/Admin/TokenController.php | 2 +- .../Oauth/AuthorizedTokensController.php | 2 +- .../Adminhtml/Oauth/ConsumerController.php | 2 +- .../core/Mage/Oauth/etc/adminhtml/menu.xml | 12 +- app/code/core/Mage/Page/Block/Html.php | 4 +- app/code/core/Mage/Page/Block/Html/Header.php | 59 +- .../System/Config/Fieldset/Global.php | 2 +- .../Adminhtml/System/Config/Fieldset/Hint.php | 2 +- .../System/Config/Fieldset/Store.php | 2 +- .../System/Config/Payflowlink/Info.php | 4 +- app/code/core/Mage/Paypal/Model/Observer.php | 2 +- .../Mage/Paypal/Model/Report/Settlement.php | 37 +- .../Adminhtml/Paypal/ReportsController.php | 2 +- .../Billing/Agreement/View/Tab/Info.php | 2 +- .../Adminhtml/Recurring/Profile/Edit/Form.php | 2 +- .../core/Mage/Sales/Model/Api/Resource.php | 122 + app/code/core/Mage/Sales/Model/Order.php | 10 +- app/code/core/Mage/Sales/Model/Order/Api.php | 267 ++ .../core/Mage/Sales/Model/Order/Api/V2.php | 36 + .../Mage/Sales/Model/Order/Creditmemo/Api.php | 258 ++ .../Sales/Model/Order/Creditmemo/Api/V2.php | 58 + .../Mage/Sales/Model/Order/Invoice/Api.php | 326 ++ .../Mage/Sales/Model/Order/Invoice/Api/V2.php | 106 + .../core/Mage/Sales/Model/Order/Shipment.php | 11 + .../Mage/Sales/Model/Order/Shipment/Api.php | 352 ++ .../Sales/Model/Order/Shipment/Api/V2.php | 122 + app/code/core/Mage/Sales/etc/api.xml | 375 +++ app/code/core/Mage/Sales/etc/wsdl.xml | 1346 ++++++++ app/code/core/Mage/Sales/etc/wsi.xml | 1686 ++++++++++ .../Catalog/Product/Edit/Tab/Tag.php | 6 +- .../Catalog/Product/Edit/Tab/Tag/Customer.php | 11 +- .../Block/Adminhtml/Customer/Edit/Tab/Tag.php | 9 +- app/code/core/Mage/Tag/Model/Api.php | 245 ++ app/code/core/Mage/Tag/Model/Api/V2.php | 109 + app/code/core/Mage/Tag/etc/api.xml | 138 + app/code/core/Mage/Tag/etc/wsdl.xml | 189 ++ app/code/core/Mage/Tag/etc/wsi.xml | 262 ++ .../System/Design/Theme/Edit/Tab/Css.php | 28 +- .../Usa/Block/Adminhtml/Dhl/Unitofmeasure.php | 2 +- .../Adminhtml/Role/Edit/Tab/Resource.php | 6 +- .../Dispatcher/Rest/Presentation.php | 188 +- .../Dispatcher/Rest/Presentation/Request.php | 127 + .../Dispatcher/Rest/Presentation/Response.php | 160 + .../core/Mage/Webapi/Controller/Front.php | 8 +- .../core/Mage/Webapi/Controller/Request.php | 2 + .../Mage/Webapi/Controller/Request/Rest.php | 8 +- .../Request/Rest/Interpreter/Json.php | 2 +- .../Request/Rest/Interpreter/Xml.php | 2 +- .../Mage/Webapi/Controller/Request/Soap.php | 2 +- .../Router/{RouteAbstract.php => Route.php} | 2 +- .../Webapi/Controller/Router/Route/Rest.php | 2 +- .../Webapi/Model/Authorization/Config.php | 2 +- .../Model/Authorization/Config/Reader.php | 5 +- .../core/Mage/Webapi/Model/Config/Rest.php | 8 +- .../core/Mage/Webapi/Model/Config/Soap.php | 6 +- .../core/Mage/Webapi/Model/ConfigAbstract.php | 10 +- .../core/Mage/Webapi/Model/Soap/Server.php | 2 +- .../core/Mage/Webapi/etc/adminhtml/menu.xml | 6 +- app/code/core/Mage/Webapi/etc/config.xml | 7 +- app/design/adminhtml/default/basic/boxes.css | 45 + .../iphone/Mage_CatalogSearch/form.mini.phtml | 16 +- .../modern/Mage_CatalogSearch/form.mini.phtml | 13 +- dev/shell/install.php | 3 +- .../Magento/Test/Annotation/AppIsolation.php | 119 +- .../framework/Magento/Test/Bootstrap.php | 113 +- .../framework/Magento/Test/Helper/Api.php | 170 + .../framework/Magento/Test/Helper/Eav.php | 49 + .../framework/Magento/Test/ObjectManager.php | 22 - .../Test/TestCase/ControllerAbstract.php | 13 +- .../Workaround/Cleanup/StaticProperties.php | 135 + .../Cleanup/TestCaseProperties.php} | 4 +- .../Test/Workaround/Segfault.php} | 13 +- dev/tests/integration/framework/bootstrap.php | 8 +- .../testsuite/Magento/Test/BootstrapTest.php | 60 +- .../Magento/Test/ClearPropertiesTest.php | 118 - .../Magento/Test/ObjectManagerTest.php | 18 +- .../Cleanup/TestCasePropertiesTest.php | 87 + .../Cleanup}/_files/DummyTestCase.php | 29 +- .../Block/Catalog/Category/TreeTest.php | 2 +- .../Block/Notification/BaseurlTest.php | 18 +- .../Mage/Adminhtml/Block/Page/HeadTest.php | 32 + .../Block/Promo/Quote/Edit/Tab/LabelsTest.php | 33 + .../Block/Rating/Edit/Tab/FormTest.php | 33 + .../Sales/Order/Create/Form/AbstractTest.php | 2 + .../Block/Widget/Form/ContainerTest.php | 6 +- .../Catalog/CategoryControllerTest.php | 3 +- .../Product/AttributeControllerTest.php | 12 +- .../Backend/Block/System/Config/FormStub.php | 1 - .../Backend/Block/System/Config/FormTest.php | 4 +- .../Block/Widget/Grid/MassactionTest.php | 67 +- .../Mage/Backend/Block/Widget/GridTest.php | 66 +- .../Backend/Block/_files/backend_theme.php | 29 + .../Model/Config/Backend/BaseurlTest.php | 148 + .../Mage/Backend/Utility/Controller.php | 2 +- .../Mage/Captcha/Model/ObserverTest.php | 18 +- .../Catalog/Model/Category/Api/V2Test.php | 79 + .../Mage/Catalog/Model/Category/ApiTest.php | 502 +++ .../Model/Category/Attribute/ApiTest.php | 104 + .../Model/Category/_files/category_data.php | 104 + .../Filter/Price/AlgorithmAdvancedTest.php | 1 - .../Product/Api/Attribute/TierPriceTest.php | 87 + .../Product/Api/AttributeSetCRUDTest.php | 235 ++ .../Model/Product/Api/AttributeTest.php | 57 + .../Model/Product/Api/BackorderStatusTest.php | 77 + .../Model/Product/Api/ConfigurableTest.php | 62 + .../Product/Api/DownloadableLinkCRUDTest.php | 127 + .../Model/Product/Api/Helper/Configurable.php | 192 ++ .../Model/Product/Api/Helper/Simple.php | 124 + .../Catalog/Model/Product/Api/ImageTest.php | 185 ++ .../Catalog/Model/Product/Api/SimpleTest.php | 458 +++ .../Catalog/Model/Product/Api/TagCRUDTest.php | 103 + .../Model/Product/Api/TestCaseAbstract.php | 182 ++ .../Model/Product/Api/_files/AttributeSet.php | 40 + .../Api/_files/AttributeSet_rollback.php | 12 +- .../Model/Product/Api/_files/CustomOption.php | 34 + .../Product/Api/_files/CustomOptionValue.php | 44 + .../Api/_files/CustomOptionValue_rollback.php | 26 + .../Api/_files/CustomOption_rollback.php | 25 + .../Api/_files/DownloadableWithLinks.php | 66 + .../_files/DownloadableWithLinks_rollback.php | 25 + .../Model/Product/Api/_files/LinkCRUD.php | 41 + .../Product/Api/_files/LinkCRUD_rollback.php | 26 + .../Api/_files/ProductAttributeData.php | 148 + .../Model/Product/Api/_files/ProductData.php | 147 + .../Api/_files/ProductWithOptionCrud.php | 71 + .../_files/ProductWithOptionCrud_rollback.php | 27 + .../Model/Product/Api/_files/TagCRUD.php | 41 + .../Product/Api/_files/TagCRUD_rollback.php | 26 + .../Product/Api/_files/_data/files/book.pdf | 0 .../Product/Api/_files/_data/files/image.jpg | Bin 0 -> 157486 bytes .../_files/_data/files/images/test.bmp.jpg | Bin 0 -> 6966 bytes .../_files/_data/files/images/test.jpg.jpg | Bin 0 -> 1621 bytes .../_files/_data/files/images/test.php.jpg | 41 + .../_files/_data/files/images/test.png.jpg | Bin 0 -> 2801 bytes .../Product/Api/_files/_data/files/song.mp3 | 0 .../Product/Api/_files/_data/files/test.txt | 1 + .../_data/product_configurable_all_fields.php | 38 + .../_data/simple_product_all_fields_data.php | 82 + .../Api/_files/_data/simple_product_data.php | 42 + .../simple_product_inventory_use_config.php | 63 + ...simple_product_manage_stock_use_config.php | 59 + .../simple_product_special_chars_data.php | 65 + .../Api/_files/_data/xml/AttributeSet.xml | 85 + .../Api/_files/_data/xml/CustomOption.xml | 147 + .../_files/_data/xml/CustomOptionTypes.xml | 69 + .../_files/_data/xml/CustomOptionValue.xml | 86 + .../Product/Api/_files/_data/xml/LinkCRUD.xml | 134 + .../Product/Api/_files/_data/xml/TagCRUD.xml | 80 + .../attribute_set_with_configurable.php | 83 + .../Api/_files/store_on_new_website.php | 64 + .../_files/store_on_new_website_rollback.php | 27 + .../Mage/Catalog/Model/Product/ApiTest.php | 116 + .../Model/Product/Attribute/ApiTest.php | 343 ++ .../Product/Attribute/Backend/MediaTest.php | 5 +- .../Model/Product/Attribute/Media/ApiTest.php | 176 + .../Attribute/Tierprice/Api/V2Test.php | 84 + .../Product/Attribute/Tierprice/ApiTest.php | 103 + .../Attribute/_files/select_attribute.php | 55 + .../Catalog/Model/Product/Link/ApiTest.php | 208 ++ .../Catalog/Model/Product/Option/ApiTest.php | 407 +++ .../Catalog/Model/Product/Type/ApiTest.php | 54 + .../Mage/Catalog/_files/categories.php | 6 + .../Mage/Catalog/_files/product_simple.php | 4 + .../controllers/_files/attribute_system.php | 6 +- .../attribute_system_with_applyto_data.php | 6 +- .../_files/attribute_user_defined.php | 4 +- .../Model/Stock/Item/ApiTest.php | 53 + .../controllers/ResultControllerTest.php | 1 - .../Mage/Checkout/Model/Cart/AbstractTest.php | 42 + .../Cart/Api/_files/license_agreement.php | 38 + .../Mage/Checkout/Model/Cart/ApiTest.php | 445 +++ .../Checkout/Model/Cart/Coupon/ApiTest.php | 105 + .../Checkout/Model/Cart/Customer/ApiTest.php | 116 + .../Checkout/Model/Cart/Payment/ApiTest.php | 91 + .../Checkout/Model/Cart/Product/ApiTest.php | 142 + .../Checkout/Model/Cart/Shipping/ApiTest.php | 116 + .../Checkout/_files/discount_10percent.php | 42 + .../testsuite/Mage/Checkout/_files/quote.php | 34 + .../Checkout/_files/quote_with_address.php | 46 + .../_files/quote_with_address_saved.php | 32 + .../_files/quote_with_ccsave_payment.php | 38 + .../_files/quote_with_check_payment.php | 44 + .../quote_with_check_payment_rollback.php | 10 +- .../Mage/Cms/Helper/Wysiwyg/ImagesTest.php | 41 + .../Cms/Model/Wysiwyg/Images/StorageTest.php | 10 + .../Mage/Core/Block/AbstractTest.php | 40 +- .../Mage/Core/Block/TemplateTest.php | 68 - .../Mage/Core/Controller/RequestHttpTest.php | 10 +- .../Core/Controller/Varien/ActionTest.php | 10 +- .../Mage/Core/Model/App/AreaTest.php | 24 - .../testsuite/Mage/Core/Model/AppTest.php | 43 +- .../Mage/Core/Model/Config/OptionsTest.php | 151 - .../Mage/Core/Model/ConfigFactoryTest.php | 9 +- .../testsuite/Mage/Core/Model/ConfigTest.php | 272 +- .../Mage/Core/Model/Design/FallbackTest.php | 63 +- .../Core/Model/Design/PackageFallbackTest.php | 17 +- .../Core/Model/Design/PackageMergingTest.php | 21 +- .../Model/Design/PackagePublicationTest.php | 146 +- .../Mage/Core/Model/Design/PackageTest.php | 111 +- .../Core/Model/Email/Template/FilterTest.php | 48 +- .../Mage/Core/Model/Email/TemplateTest.php | 30 +- .../Mage/Core/Model/Email/_files/themes.php | 29 + .../Mage/Core/Model/Layout/MergeTest.php | 61 +- .../Mage/Core/Model/LayoutArgumentTest.php | 111 - .../Mage/Core/Model/LayoutDirectivesTest.php | 241 ++ .../testsuite/Mage/Core/Model/LayoutTest.php | 302 +- .../Mage/Core/Model/Magento/ApiTest.php | 42 + .../Mage/Core/Model/ObserverTest.php | 30 +- .../Mage/Core/Model/Store/ApiTest.php | 68 + .../Model/Store/GroupTest.php} | 38 +- .../testsuite/Mage/Core/Model/StoreTest.php | 39 +- .../Mage/Core/Model/Theme/CollectionTest.php | 2 - .../testsuite/Mage/Core/Model/ThemeTest.php | 13 +- .../Mage/Core/Model/TranslateTest.php | 22 +- .../test/default/Mage_Core/layout.xml | 220 -- .../test/default/Mage_Core/test.phtml | 2 +- .../Mage/Core/Model/_files/design/themes.php | 33 + .../fallback/pub/{js => lib}/mage/script.js | 0 .../action_for_anonymous_parent_block.xml} | 20 +- .../layout_directives_test/arguments.xml | 39 + .../arguments_complex_values.xml | 59 + .../arguments_object_type.xml | 41 + .../arguments_object_type_updaters.xml | 54 + .../arguments_url_type.xml | 55 + .../get_block.xml} | 10 +- .../get_block_exception.xml | 31 + .../_files/layout_directives_test/move.xml | 48 + .../move_alias_broken.xml | 32 + .../move_broken.xml} | 11 +- .../layout_directives_test/move_new_alias.xml | 32 + .../move_the_same_alias.xml | 32 + .../_files/layout_directives_test/remove.xml | 38 + .../layout_directives_test/remove_broken.xml | 33 + .../_files/layout_directives_test/render.xml | 47 + .../sort_after_after.xml | 38 + .../sort_after_previous.xml | 39 + .../sort_before_after.xml | 38 + .../sort_before_before.xml | 39 + .../custom}/local.xml | 10 +- .../custom/prohibited.filename.xml | 39 + .../custom => local_config}/local.xml | 10 +- .../z.xml | 10 +- .../a.xml | 10 +- .../b.xml | 12 +- .../no_local_config/custom/local.xml | 39 + .../custom/local.xml | 29 - .../Core/Model/_files/sort_special_cases.xml | 84 - .../Model/_files/valid_layout_updates.xml | 73 - .../testsuite/Mage/Core/Utility/Theme.php | 211 -- .../media_for_change.php} | 46 +- .../Core/_files/media_for_change_rollback.php | 29 + .../Mage/Customer/Model/Address/ApiTest.php | 232 ++ .../Mage/Customer/Model/Customer/ApiTest.php | 166 + .../Mage/Customer/Model/Group/ApiTest.php | 46 + .../Mage/Customer/_files/customer_address.php | 4 +- .../_files/customer_two_addresses.php | 4 +- .../Mage/Customer/_files/two_customers.php | 45 + .../Mage/Directory/Model/Country/ApiTest.php | 43 + .../Mage/Directory/Model/Region/ApiTest.php | 43 + .../Attribute/Edit/Main/AbstractTest.php | 2 + .../Mage/GiftMessage/Model/ApiTest.php | 167 + .../Model/Export/Entity/ProductTest.php | 2 - .../Mage/Index/Model/Process/FileTest.php | 6 +- .../Mage/Install/IndexControllerTest.php | 39 + .../Install/Model/Installer/ConfigTest.php | 70 + .../controllers/WizardControllerTest.php | 48 +- .../Mage/Newsletter/Model/QueueTest.php | 7 +- .../testsuite/Mage/Page/Block/HtmlTest.php | 81 + .../Paypal/ReportsControllerTest.php | 47 + .../Paypal/Model/Report/SettlementTest.php | 63 + .../Sales/Model/Order/Api/_files/customer.php | 65 + .../Order/Api/_files/customer_rollback.php | 25 + .../Order/Api/_files/multiple_invoices.php | 50 + .../Api/_files/multiple_invoices_rollback.php | 25 + .../Sales/Model/Order/Api/_files/order.php | 78 + .../Model/Order/Api/_files/order_rollback.php | 28 + .../Order/Api/_files/order_with_shipping.php | 71 + .../_files/order_with_shipping_rollback.php | 31 + .../Model/Order/Api/_files/product_simple.php | 48 + .../Api/_files/product_simple_rollback.php | 24 + .../Order/Api/_files/product_virtual.php | 46 + .../Api/_files/product_virtual_rollback.php | 24 + .../Sales/Model/Order/Api/_files/shipment.php | 35 + .../Order/Api/_files/shipment_rollback.php | 32 + .../Mage/Sales/Model/Order/ApiTest.php | 221 ++ .../Sales/Model/Order/Creditmemo/ApiTest.php | 357 ++ .../Mage/Sales/Model/Order/CreditmemoTest.php | 2 +- .../Sales/Model/Order/Invoice/ApiTest.php | 319 ++ .../Mage/Sales/Model/Order/InvoiceTest.php | 2 +- .../Mage/Sales/Model/Order/OrderTest.php | 2 +- .../Sales/Model/Order/Shipment/ApiTest.php | 279 ++ .../Mage/Sales/Model/Order/ShipmentTest.php | 2 +- .../testsuite/Mage/Sales/_files/invoice.php | 35 + .../Mage/Sales/_files/invoice_verisign.php | 36 + .../testsuite/Mage/Sales/_files/order.php | 13 +- .../Model/Resource/Catalog/ProductTest.php | 1 - .../Mage/Tag/Model/Api/_files/tag.php | 29 + .../testsuite/Mage/Tag/Model/ApiTest.php | 81 + .../Block/Adminhtml/Dhl/UnitofmeasureTest.php | 37 + .../Block/Adminhtml/FormTestAbstract.php | 4 +- .../Block/Adminhtml/Role/Edit/FormTest.php | 2 +- .../Adminhtml/Role/Edit/Tab/MainTest.php | 6 +- .../Adminhtml/Role/Edit/Tab/ResourceTest.php | 6 +- .../Block/Adminhtml/User/Edit/FormTest.php | 2 +- .../Adminhtml/User/Edit/Tab/MainTest.php | 8 +- .../Block/Adminhtml/User/Edit/TabsTest.php | 10 +- .../Webapi/Block/Adminhtml/User/EditTest.php | 10 +- .../Mage/Webapi/Helper/ConfigTest.php | 2 +- .../testsuite/Mage/Webapi/Helper/DataTest.php | 26 +- .../Mage/Webapi/Model/Acl/RoleTest.php | 8 +- .../Mage/Webapi/Model/Acl/RuleTest.php | 8 +- .../Mage/Webapi/Model/Acl/UserTest.php | 8 +- .../Config/Reader/Rest/RouteGeneratorTest.php | 4 +- .../Mage/Webapi/Model/Config/RestTest.php | 32 +- .../Webapi/Model/Config/Soap/DataTest.php | 2 +- .../Mage/Webapi/Model/Config/SoapTest.php | 32 +- .../Webapi/Model/Resource/Acl/RoleTest.php | 10 +- .../Webapi/Model/Resource/Acl/RuleTest.php | 6 +- .../Webapi/Model/Soap/AutoDiscoverTest.php | 43 +- .../Model/Soap/Security/UsernameTokenTest.php | 43 +- .../Mage/Webapi/Model/Soap/ServerTest.php | 14 +- .../empty_property_description/class.php | 2 +- .../autodiscovery/empty_var_tags/class.php | 2 +- .../empty_var_tags/data_type.php | 2 +- .../invalid_deprecation_policy/class.php | 2 +- .../autodiscovery/no_resources/class.php | 2 +- .../reference_to_invalid_type/class.php | 2 +- .../file_with_classes.php | 4 +- .../resource_with_invalid_interface.php | 8 +- .../_files/resource_with_invalid_name.php | 2 +- .../Mage/Widget/Model/WidgetTest.php | 7 +- .../testsuite/Mage/Widget/_files/themes.php | 33 + .../Mage/Wishlist/Block/AbstractTest.php | 4 +- .../testsuite/Magento/Di/GeneratorTest.php | 12 +- .../Magento/Filesystem/Adapter/LocalTest.php | 29 +- .../integration/testsuite/MemoryUsageTest.php | 192 ++ .../Varien/Db/Adapter/Pdo/MysqlTest.php | 60 +- .../Varien/Image/Adapter/InterfaceTest.php | 2 +- .../integrity/modular/AclConfigFilesTest.php | 2 - .../integrity/modular/TemplateFilesTest.php | 6 +- dev/tests/performance/run_scenarios.php | 26 +- .../CodingStandard/Tool/CodeSniffer.php | 10 + .../CodingStandard/Tool/CodeSnifferTest.php | 5 + .../testsuite/Js/_files/blacklist/ee.txt | 2 - .../static/testsuite/Legacy/ConfigTest.php | 3 + .../testsuite/Legacy/EmailTemplateTest.php | 3 +- .../static/testsuite/Legacy/LayoutTest.php | 3 +- .../testsuite/Legacy/ObsoleteCodeTest.php | 285 +- .../Legacy/_files/obsolete_classes.php | 843 ++--- .../Legacy/_files/obsolete_constants.php | 86 +- .../Legacy/_files/obsolete_methods.php | 806 ++--- .../Legacy/_files/obsolete_properties.php | 102 +- .../testsuite/Legacy/_files/words_core.xml | 3 + .../testsuite/Php/Exemplar/CodeStyleTest.php | 2 +- .../static/testsuite/Php/LiveCodeTest.php | 2 +- .../testsuite/Php/_files/blacklist/common.txt | 11 +- .../testsuite/Php/_files/whitelist/common.txt | 30 +- .../Magento/Test/Helper/ObjectManager.php | 2 + .../Mage/Captcha/Helper/DataTest.php | 118 +- .../testsuite/Mage/Captcha/Model/ZendTest.php | 15 +- .../Product/Attribute/Backend/MediaTest.php | 4 + .../Model/Product/Type/ConfigurableTest.php | 4 +- .../Mage/Core/Block/AbstractTest.php | 40 +- .../Mage/Core/Block/TemplateTest.php | 104 + .../Block/_files/template_test_assign.phtml | 3 +- .../Mage/Core/Model/App/OptionsTest.php | 69 - .../testsuite/Mage/Core/Model/AppTest.php | 67 +- .../testsuite/Mage/Core/Model/CacheTest.php | 150 +- .../Mage/Core/Model/Config/OptionsTest.php | 114 - .../testsuite/Mage/Core/Model/ConfigTest.php | 32 +- .../Design/Fallback/CachingProxyTest.php | 212 +- .../testsuite/Mage/Core/Model/DirTest.php | 124 + .../Mage/Core/Model/EncryptionTest.php | 71 + .../testsuite/Mage/Core/Model/LoggerTest.php | 26 +- .../testsuite/Mage/Core/Model/ThemeTest.php | 25 +- .../Mage/Core/Model/Validator/FactoryTest.php | 3 +- .../Controller/Varien/Router/StandardTest.php | 98 +- .../Mage/DesignEditor/Model/StateTest.php | 17 +- .../Mage/Index/Model/Lock/StorageTest.php | 43 +- .../Mage/Page/Block/Html/HeaderTest.php | 19 +- .../Adminhtml/Role/Edit/Tab/ResourceTest.php | 8 +- .../Block/Adminhtml/Role/Edit/TabsTest.php | 6 +- .../Webapi/Block/Adminhtml/Role/EditTest.php | 14 +- .../Mage/Webapi/Block/Adminhtml/RoleTest.php | 12 +- .../Webapi/Block/Adminhtml/User/EditTest.php | 12 +- .../Mage/Webapi/Block/Adminhtml/UserTest.php | 12 +- .../Dispatcher/ErrorProcessorTest.php | 42 +- .../Webapi/Controller/Dispatcher/RestTest.php | 10 +- .../Dispatcher/Soap/AuthenticationTest.php | 2 +- .../Dispatcher/Soap/HandlerTest.php | 2 +- .../Webapi/Controller/Dispatcher/SoapTest.php | 2 +- .../Mage/Webapi/Controller/FrontTest.php | 20 +- .../Request/Rest/Interpreter/FactoryTest.php | 2 +- .../Request/Rest/Interpreter/JsonTest.php | 6 +- .../Request/Rest/Interpreter/XmlTest.php | 4 +- .../Webapi/Controller/Request/RestTest.php | 48 +- .../Webapi/Controller/Request/SoapTest.php | 6 +- .../Mage/Webapi/Controller/RequestTest.php | 14 +- .../Controller/Response/FactoryTest.php | 10 +- .../Response/Rest/Renderer/FactoryTest.php | 8 +- .../Response/Rest/Renderer/JsonTest.php | 8 +- .../Response/Rest/Renderer/XmlTest.php | 2 +- .../Webapi/Controller/Response/RestTest.php | 16 +- .../Mage/Webapi/Controller/ResponseTest.php | 10 +- .../Controller/Router/Route/RestTest.php | 12 +- .../{Route/ApiTypeTest.php => RouteTest.php} | 10 +- .../Webapi/Model/Acl/Role/FactoryTest.php | 4 +- .../Model/Acl/Role/InRoleUserUpdaterTest.php | 2 +- .../Mage/Webapi/Model/Acl/RoleTest.php | 6 +- .../Mage/Webapi/Model/Acl/RuleTest.php | 12 +- .../Webapi/Model/Acl/User/FactoryTest.php | 2 +- .../Mage/Webapi/Model/Acl/UserTest.php | 12 +- .../Model/Authorization/Config/ReaderTest.php | 4 +- .../Webapi/Model/Authorization/ConfigTest.php | 12 +- .../Authorization/Loader/ResourceTest.php | 8 +- .../Model/Authorization/Loader/RoleTest.php | 10 +- .../Model/Authorization/Loader/RuleTest.php | 4 +- .../Webapi/Model/Resource/Acl/RoleTest.php | 10 +- .../Webapi/Model/Resource/Acl/RuleTest.php | 18 +- .../Webapi/Model/Resource/Acl/UserTest.php | 8 +- .../Webapi/Model/Rest/Oauth/ServerTest.php | 6 +- .../Webapi/Model/Soap/AutoDiscoverTest.php | 10 +- .../Mage/Webapi/Model/Soap/FaultTest.php | 20 +- .../Model/Soap/Security/UsernameTokenTest.php | 6 +- .../Mage/Webapi/Model/Soap/ServerTest.php | 53 +- .../ComplexTypeStrategy/ConfigBasedTest.php | 6 +- .../Mage/Webapi/Model/Source/Acl/RoleTest.php | 4 +- .../unit/testsuite/Magento/ShellTest.php | 98 +- index.php | 13 +- lib/Magento/Filesystem/Adapter/Local.php | 7 +- lib/Magento/ObjectManager/Zend.php | 7 +- lib/Magento/Shell.php | 53 +- lib/Varien/Data/Form/Element/Date.php | 23 +- pub/.htaccess | 5 - pub/get.php | 32 +- pub/index.php | 5 +- pub/lib/.htaccess | 6 + pub/lib/jquery/jstree/jquery.hotkeys.js | 99 + pub/lib/mage/adminhtml/grid.js | 17 + pub/lib/mage/backend/action-link.js | 2 +- pub/lib/mage/backend/multisuggest.js | 152 + pub/lib/mage/backend/suggest.js | 298 +- pub/lib/mage/backend/tree-suggest.js | 169 + pub/lib/mage/mage.js | 78 +- pub/lib/mage/validation.js | 6 - 759 files changed, 56348 insertions(+), 8523 deletions(-) create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Buttons.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Editroles.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Grid/Role.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Role.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Role/Grid/User.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Roles.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Tab/Roleinfo.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesedit.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesusers.php rename app/code/core/Mage/{Core/Block/Template/Zend.php => Adminhtml/Block/Api/User.php} (57%) create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/User/Edit.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Form.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Roles.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tabs.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Api/User/Grid.php delete mode 100644 app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Group.php delete mode 100644 app/code/core/Mage/Adminhtml/Block/Html/Date.php delete mode 100644 app/code/core/Mage/Adminhtml/Block/Html/Select.php delete mode 100644 app/code/core/Mage/Adminhtml/Block/Messages.php delete mode 100644 app/code/core/Mage/Adminhtml/Model/Extension.php create mode 100644 app/code/core/Mage/Adminhtml/controllers/Api/RoleController.php create mode 100644 app/code/core/Mage/Adminhtml/controllers/Api/UserController.php create mode 100644 app/code/core/Mage/Adminhtml/view/adminhtml/api/role_users_grid_js.phtml create mode 100644 app/code/core/Mage/Adminhtml/view/adminhtml/api/roleinfo.phtml rename dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/theme.xml => app/code/core/Mage/Adminhtml/view/adminhtml/api/roles.phtml (61%) create mode 100644 app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesedit.phtml rename dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/Mage_Core/dummy.phtml => app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesusers.phtml (83%) create mode 100644 app/code/core/Mage/Adminhtml/view/adminhtml/api/user_roles_grid_js.phtml create mode 100644 app/code/core/Mage/Adminhtml/view/adminhtml/api/userinfo.phtml rename dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/Mage_Core/dummy.phtml => app/code/core/Mage/Adminhtml/view/adminhtml/api/usernroles.phtml (72%) delete mode 100644 app/code/core/Mage/Adminhtml/view/adminhtml/resetforgottenpassword.phtml create mode 100644 app/code/core/Mage/Api/Controller/Action.php create mode 100644 app/code/core/Mage/Api/Exception.php create mode 100644 app/code/core/Mage/Api/Helper/Data.php create mode 100644 app/code/core/Mage/Api/Model/Acl.php create mode 100644 app/code/core/Mage/Api/Model/Acl/Resource.php create mode 100644 app/code/core/Mage/Api/Model/Acl/Role.php create mode 100644 app/code/core/Mage/Api/Model/Acl/Role/Generic.php create mode 100644 app/code/core/Mage/Api/Model/Acl/Role/Group.php create mode 100644 app/code/core/Mage/Api/Model/Acl/Role/Registry.php create mode 100644 app/code/core/Mage/Api/Model/Acl/Role/User.php create mode 100644 app/code/core/Mage/Api/Model/Config.php create mode 100644 app/code/core/Mage/Api/Model/Resource/Abstract.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Acl.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Acl/Role.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Acl/Role/Collection.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Permissions/Collection.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Role.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Role/Collection.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Roles.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Roles/Collection.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Roles/User/Collection.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Rules.php create mode 100755 app/code/core/Mage/Api/Model/Resource/Rules/Collection.php create mode 100755 app/code/core/Mage/Api/Model/Resource/User.php create mode 100755 app/code/core/Mage/Api/Model/Resource/User/Collection.php create mode 100644 app/code/core/Mage/Api/Model/Role.php create mode 100644 app/code/core/Mage/Api/Model/Roles.php create mode 100644 app/code/core/Mage/Api/Model/Rules.php create mode 100644 app/code/core/Mage/Api/Model/Server.php create mode 100644 app/code/core/Mage/Api/Model/Server/Adapter/Soap.php create mode 100644 app/code/core/Mage/Api/Model/Server/Adapter/Soap/Wsi.php create mode 100644 app/code/core/Mage/Api/Model/Server/Handler/Soap.php create mode 100644 app/code/core/Mage/Api/Model/Server/Handler/Soap/Wsi.php create mode 100644 app/code/core/Mage/Api/Model/Server/HandlerAbstract.php create mode 100644 app/code/core/Mage/Api/Model/Session.php create mode 100644 app/code/core/Mage/Api/Model/User.php create mode 100644 app/code/core/Mage/Api/Model/Wsdl/Config.php create mode 100644 app/code/core/Mage/Api/Model/Wsdl/Config/Base.php create mode 100644 app/code/core/Mage/Api/Model/Wsdl/Config/Element.php create mode 100644 app/code/core/Mage/Api/controllers/Soap/WsiController.php create mode 100644 app/code/core/Mage/Api/controllers/SoapController.php create mode 100644 app/code/core/Mage/Api/etc/adminhtml.xml create mode 100644 app/code/core/Mage/Api/etc/adminhtml/menu.xml create mode 100644 app/code/core/Mage/Api/etc/adminhtml/system.xml create mode 100644 app/code/core/Mage/Api/etc/api.xml create mode 100644 app/code/core/Mage/Api/etc/config.xml create mode 100644 app/code/core/Mage/Api/etc/wsdl.xml create mode 100644 app/code/core/Mage/Api/etc/wsi.xml create mode 100644 app/code/core/Mage/Api/locale/de_DE/Mage_Api.csv create mode 100644 app/code/core/Mage/Api/locale/en_US/Mage_Api.csv create mode 100644 app/code/core/Mage/Api/locale/es_ES/Mage_Api.csv create mode 100644 app/code/core/Mage/Api/locale/fr_FR/Mage_Api.csv create mode 100644 app/code/core/Mage/Api/locale/nl_NL/Mage_Api.csv create mode 100644 app/code/core/Mage/Api/locale/pt_BR/Mage_Api.csv create mode 100644 app/code/core/Mage/Api/locale/zh_CN/Mage_Api.csv create mode 100644 app/code/core/Mage/Api/sql/api_setup/install-1.6.0.0.php create mode 100644 app/code/core/Mage/Backend/Block/Catalog/Product/Tab/Container.php create mode 100644 app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Button.php create mode 100644 app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Grip.php create mode 100644 app/code/core/Mage/Bundle/view/adminhtml/css/bundle-product.css create mode 100644 app/code/core/Mage/Bundle/view/adminhtml/js/bundle-product.js create mode 100644 app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts.php create mode 100644 app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts/Grid.php create mode 100644 app/code/core/Mage/Catalog/Model/Api/Resource.php create mode 100644 app/code/core/Mage/Catalog/Model/Category/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Category/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Category/Attribute/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Category/Attribute/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Link/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Link/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Option/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Option/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Option/Value/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Option/Value/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Type/Api.php create mode 100644 app/code/core/Mage/Catalog/Model/Product/Type/Api/V2.php create mode 100644 app/code/core/Mage/Catalog/Model/Resource/Product/Type/Grouped/AssociatedProductsCollection.php create mode 100644 app/code/core/Mage/Catalog/etc/api.xml create mode 100644 app/code/core/Mage/Catalog/etc/wsdl.xml create mode 100644 app/code/core/Mage/Catalog/etc/wsi.xml create mode 100644 app/code/core/Mage/Catalog/view/adminhtml/js/grouped-product.js rename dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/theme.xml => app/code/core/Mage/Catalog/view/adminhtml/product/grouped/container.phtml (66%) create mode 100644 app/code/core/Mage/Catalog/view/adminhtml/product/grouped/grouped.phtml create mode 100644 app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api.php create mode 100644 app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api/V2.php create mode 100644 app/code/core/Mage/CatalogInventory/etc/api.xml create mode 100644 app/code/core/Mage/CatalogInventory/etc/wsdl.xml create mode 100644 app/code/core/Mage/CatalogInventory/etc/wsi.xml create mode 100644 app/code/core/Mage/Checkout/Model/Api/Resource.php create mode 100644 app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php create mode 100644 app/code/core/Mage/Checkout/Model/Api/Resource/Product.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Api.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Api/V2.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Coupon/Api.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Coupon/Api/V2.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Customer/Api.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Customer/Api/V2.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Payment/Api.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Payment/Api/V2.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Product/Api.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Product/Api/V2.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Shipping/Api.php create mode 100644 app/code/core/Mage/Checkout/Model/Cart/Shipping/Api/V2.php create mode 100644 app/code/core/Mage/Checkout/etc/api.xml create mode 100644 app/code/core/Mage/Checkout/etc/wsdl.xml create mode 100644 app/code/core/Mage/Checkout/etc/wsi.xml delete mode 100644 app/code/core/Mage/Core/Model/App/Options.php delete mode 100644 app/code/core/Mage/Core/Model/Config/Options.php create mode 100644 app/code/core/Mage/Core/Model/Dir.php create mode 100644 app/code/core/Mage/Core/Model/Magento/Api.php rename dev/tests/integration/testsuite/Mage/Core/_files/load_configuration.php => app/code/core/Mage/Core/Model/Magento/Api/V2.php (81%) create mode 100644 app/code/core/Mage/Core/Model/Store/Api.php rename app/code/core/Mage/{Adminhtml/Block/Abstract.php => Core/Model/Store/Api/V2.php} (85%) create mode 100644 app/code/core/Mage/Core/etc/api.xml create mode 100644 app/code/core/Mage/Core/etc/wsdl.xml create mode 100644 app/code/core/Mage/Core/etc/wsi.xml create mode 100644 app/code/core/Mage/Customer/Model/Address/Api.php create mode 100644 app/code/core/Mage/Customer/Model/Address/Api/V2.php create mode 100644 app/code/core/Mage/Customer/Model/Api/Resource.php create mode 100644 app/code/core/Mage/Customer/Model/Customer/Api.php create mode 100644 app/code/core/Mage/Customer/Model/Customer/Api/V2.php create mode 100644 app/code/core/Mage/Customer/Model/Group/Api.php create mode 100644 app/code/core/Mage/Customer/Model/Group/Api/V2.php create mode 100644 app/code/core/Mage/Customer/etc/api.xml create mode 100644 app/code/core/Mage/Customer/etc/wsdl.xml create mode 100644 app/code/core/Mage/Customer/etc/wsi.xml create mode 100644 app/code/core/Mage/Directory/Model/Country/Api.php create mode 100644 app/code/core/Mage/Directory/Model/Country/Api/V2.php create mode 100644 app/code/core/Mage/Directory/Model/Region/Api.php create mode 100644 app/code/core/Mage/Directory/Model/Region/Api/V2.php create mode 100644 app/code/core/Mage/Directory/etc/api.xml create mode 100644 app/code/core/Mage/Directory/etc/wsdl.xml create mode 100644 app/code/core/Mage/Directory/etc/wsi.xml create mode 100644 app/code/core/Mage/Downloadable/Model/Link/Api.php create mode 100644 app/code/core/Mage/Downloadable/Model/Link/Api/Uploader.php create mode 100644 app/code/core/Mage/Downloadable/Model/Link/Api/V2.php create mode 100644 app/code/core/Mage/Downloadable/Model/Link/Api/Validator.php create mode 100644 app/code/core/Mage/Downloadable/etc/api.xml create mode 100644 app/code/core/Mage/Downloadable/etc/wsdl.xml create mode 100644 app/code/core/Mage/Downloadable/etc/wsi.xml create mode 100644 app/code/core/Mage/GiftMessage/Model/Api.php create mode 100644 app/code/core/Mage/GiftMessage/Model/Api/V2.php create mode 100644 app/code/core/Mage/GiftMessage/etc/api.xml create mode 100644 app/code/core/Mage/GiftMessage/etc/wsdl.xml create mode 100644 app/code/core/Mage/GiftMessage/etc/wsi.xml create mode 100644 app/code/core/Mage/Sales/Model/Api/Resource.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Api.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Api/V2.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Creditmemo/Api.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Creditmemo/Api/V2.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Invoice/Api.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Invoice/Api/V2.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Shipment/Api.php create mode 100644 app/code/core/Mage/Sales/Model/Order/Shipment/Api/V2.php create mode 100644 app/code/core/Mage/Sales/etc/api.xml create mode 100644 app/code/core/Mage/Sales/etc/wsdl.xml create mode 100644 app/code/core/Mage/Sales/etc/wsi.xml create mode 100644 app/code/core/Mage/Tag/Model/Api.php create mode 100644 app/code/core/Mage/Tag/Model/Api/V2.php create mode 100644 app/code/core/Mage/Tag/etc/api.xml create mode 100644 app/code/core/Mage/Tag/etc/wsdl.xml create mode 100644 app/code/core/Mage/Tag/etc/wsi.xml create mode 100644 app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Request.php create mode 100644 app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Response.php rename app/code/core/Mage/Webapi/Controller/Router/{RouteAbstract.php => Route.php} (93%) create mode 100644 dev/tests/integration/framework/Magento/Test/Helper/Api.php create mode 100644 dev/tests/integration/framework/Magento/Test/Helper/Eav.php create mode 100644 dev/tests/integration/framework/Magento/Test/Workaround/Cleanup/StaticProperties.php rename dev/tests/integration/framework/Magento/Test/{ClearProperties.php => Workaround/Cleanup/TestCaseProperties.php} (91%) rename dev/tests/integration/framework/{tests/unit/testsuite/Magento/Test/_files/Stub.php => Magento/Test/Workaround/Segfault.php} (81%) delete mode 100644 dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ClearPropertiesTest.php create mode 100644 dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Cleanup/TestCasePropertiesTest.php rename dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/{ => Workaround/Cleanup}/_files/DummyTestCase.php (84%) rename app/code/core/Mage/Webapi/Controller/Router/Route/Webapi.php => dev/tests/integration/testsuite/Mage/Adminhtml/Block/Notification/BaseurlTest.php (70%) create mode 100644 dev/tests/integration/testsuite/Mage/Adminhtml/Block/Page/HeadTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/LabelsTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Adminhtml/Block/Rating/Edit/Tab/FormTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Backend/Block/_files/backend_theme.php create mode 100644 dev/tests/integration/testsuite/Mage/Backend/Model/Config/Backend/BaseurlTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Api/V2Test.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Category/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Attribute/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Category/_files/category_data.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Attribute/TierPriceTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeSetCRUDTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/BackorderStatusTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ConfigurableTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/DownloadableLinkCRUDTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Configurable.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Simple.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ImageTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/SimpleTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TagCRUDTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TestCaseAbstract.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet.php rename index.php.sample => dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet_rollback.php (64%) create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductAttributeData.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductData.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/book.pdf create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/image.jpg create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.bmp.jpg create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.jpg.jpg create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.php.jpg create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.png.jpg create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/song.mp3 create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/test.txt create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/product_configurable_all_fields.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_all_fields_data.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_data.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_inventory_use_config.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_manage_stock_use_config.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_special_chars_data.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/AttributeSet.xml create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOption.xml create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionTypes.xml create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionValue.xml create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/LinkCRUD.xml create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/TagCRUD.xml create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/attribute_set_with_configurable.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Media/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2Test.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Link/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Option/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/CatalogInventory/Model/Stock/Item/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/AbstractTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Api/_files/license_agreement.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Coupon/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Customer/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Payment/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Product/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Shipping/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/_files/discount_10percent.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/_files/quote.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address_saved.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_ccsave_payment.php create mode 100644 dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment.php rename app/code/core/Mage/Core/Block/Template/Smarty.php => dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment_rollback.php (87%) create mode 100644 dev/tests/integration/testsuite/Mage/Cms/Helper/Wysiwyg/ImagesTest.php delete mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/Config/OptionsTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/Email/_files/themes.php delete mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/LayoutArgumentTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/LayoutDirectivesTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/Magento/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/Store/ApiTest.php rename dev/tests/integration/testsuite/Mage/{Install/Helper/DataTest.php => Core/Model/Store/GroupTest.php} (53%) create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/design/themes.php rename dev/tests/integration/testsuite/Mage/Core/Model/_files/fallback/pub/{js => lib}/mage/script.js (100%) rename dev/tests/integration/testsuite/Mage/Core/Model/_files/{local_config/no_local_config_no_custom_config/a.xml => layout_directives_test/action_for_anonymous_parent_block.xml} (69%) create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_complex_values.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type_updaters.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_url_type.xml rename dev/tests/integration/testsuite/Mage/Core/Model/_files/{local_config/local_config_custom_config/custom/invalid.pattern.xml => layout_directives_test/get_block.xml} (81%) create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/get_block_exception.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_alias_broken.xml rename dev/tests/integration/testsuite/Mage/Core/Model/_files/{local_config/local_config_custom_config/local.xml => layout_directives_test/move_broken.xml} (85%) create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_new_alias.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_the_same_alias.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove_broken.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/render.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_after.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_previous.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_after.xml create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_before.xml rename dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/{local_config_no_custom_config => local_config/custom}/local.xml (82%) create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/custom/prohibited.filename.xml rename dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/{local_config_custom_config/custom => local_config}/local.xml (82%) rename dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/{local_config_no_custom_config => local_config}/z.xml (82%) rename dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/{no_local_config_custom_config => no_local_config}/a.xml (82%) rename dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/{no_local_config_no_custom_config => no_local_config}/b.xml (82%) create mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/custom/local.xml delete mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_custom_config/custom/local.xml delete mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/sort_special_cases.xml delete mode 100644 dev/tests/integration/testsuite/Mage/Core/Model/_files/valid_layout_updates.xml delete mode 100644 dev/tests/integration/testsuite/Mage/Core/Utility/Theme.php rename dev/tests/integration/testsuite/Mage/Core/{Model/LayoutTestBase.php => _files/media_for_change.php} (50%) create mode 100644 dev/tests/integration/testsuite/Mage/Core/_files/media_for_change_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Customer/Model/Address/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Customer/Model/Customer/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Customer/Model/Group/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Customer/_files/two_customers.php create mode 100644 dev/tests/integration/testsuite/Mage/Directory/Model/Country/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Directory/Model/Region/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/GiftMessage/Model/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Install/IndexControllerTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Install/Model/Installer/ConfigTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Page/Block/HtmlTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Paypal/Adminhtml/Paypal/ReportsControllerTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Paypal/Model/Report/SettlementTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment_rollback.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Creditmemo/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Invoice/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/Model/Order/Shipment/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/_files/invoice.php create mode 100644 dev/tests/integration/testsuite/Mage/Sales/_files/invoice_verisign.php create mode 100644 dev/tests/integration/testsuite/Mage/Tag/Model/Api/_files/tag.php create mode 100644 dev/tests/integration/testsuite/Mage/Tag/Model/ApiTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Usa/Block/Adminhtml/Dhl/UnitofmeasureTest.php create mode 100644 dev/tests/integration/testsuite/Mage/Widget/_files/themes.php create mode 100644 dev/tests/integration/testsuite/MemoryUsageTest.php delete mode 100644 dev/tests/static/testsuite/Js/_files/blacklist/ee.txt create mode 100644 dev/tests/unit/testsuite/Mage/Core/Block/TemplateTest.php rename dev/tests/{integration => unit}/testsuite/Mage/Core/Block/_files/template_test_assign.phtml (96%) delete mode 100644 dev/tests/unit/testsuite/Mage/Core/Model/App/OptionsTest.php delete mode 100644 dev/tests/unit/testsuite/Mage/Core/Model/Config/OptionsTest.php create mode 100644 dev/tests/unit/testsuite/Mage/Core/Model/DirTest.php create mode 100644 dev/tests/unit/testsuite/Mage/Core/Model/EncryptionTest.php rename dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/{Route/ApiTypeTest.php => RouteTest.php} (78%) create mode 100644 pub/lib/.htaccess create mode 100644 pub/lib/jquery/jstree/jquery.hotkeys.js create mode 100644 pub/lib/mage/backend/multisuggest.js create mode 100644 pub/lib/mage/backend/tree-suggest.js diff --git a/.gitignore b/.gitignore index ee2ae170cef..1f08e5627de 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,3 @@ atlassian* /pub/media/customer/* /pub/media/downloadable/* /var/* - diff --git a/.htaccess b/.htaccess index e02679d64fa..0a28bdaf030 100644 --- a/.htaccess +++ b/.htaccess @@ -141,11 +141,6 @@ #RewriteCond %{HTTP_USER_AGENT} "android|blackberry|ipad|iphone|ipod|iemobile|opera mobile|palmos|webos|googlebot-mobile" [NC] #RewriteRule ^(.*)$ /mobiledirectoryhere/ [L,R=302] -############################################ -## always send 404 on missing files in these folders - - RewriteCond %{REQUEST_URI} !^/pub/(media|js)/ - ############################################ ## never rewrite for existing files, directories and links diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index c8816df7256..32e34eceb03 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,3 +1,28 @@ +2.0.0.0-dev40 +============= +* Implemented ability to customize all the main directory paths for the application, i.e. locations of `var`, `etc`, `media` and other directories +* Implemented ability to pass application configuration data from the environment +* Magento Web API changes: + * Added SOAP V2 API coverage from Magento 1.x + * Improved integration testing framework to develop Web API tests. Covered SOAP V2 API with positive integration tests. + * Changed `Mage_Webapi` module front name from `api` to `webapi` +* Improvements for product creation UI: + * Implemented AJAX suggestions popup and categories tree popup for convenient assignment of categories + * Moved selection of Bundle and Grouped sub-products to the "General" tab, implemented popup grids for them + * Made "Weight" checkbox to be selected by default for a Configurable product +* Implemented integration test to measure and control PHP memory leak on application reinitialization +* Changed format of configuration files for static tests that search for obsolete Magento 1.x code +* Bug fixes: + * Fixed Web API WSDL incompatibility with C# and Java + * Fixed issue, that Magento duplicated custom options field for a product, if creating them via a multi-call to API + * Fixed `shoppingCartPaymentList` method in Web API, which was throwing exception "Object has no 'code' property" + * Fixed invalid Wishlist link and several invalid links in Checkout on frontend store view + * Made Stock Status in 'quantity_and_stock_status' attribute editable again for a Configurable product + * Fixed issue, that it was not possible to save Customer after first save, because "Date Of Birth" format was reported by Magento to be incorrect + * Fixed fatal error in Code Sniffer exemplar test + * Fixed wrong failures of `Varien_Db_Adapter_Pdo_MysqlTest::testWaitTimeout()` integration test in developer mode + * Fixed issue, that mass-action column in backend grids moved to another position in single store mode + 2.0.0.0-dev39 ============= * Visual design editor improvements: diff --git a/app/Mage.php b/app/Mage.php index 6629187adfc..02c46493940 100644 --- a/app/Mage.php +++ b/app/Mage.php @@ -29,6 +29,26 @@ */ final class Mage { + /**#@+ + * Application initialization options to inject custom request/response objects + */ + const INIT_OPTION_REQUEST = 'request'; + const INIT_OPTION_RESPONSE = 'response'; + /**#@-*/ + + /** + * Application initialization option to specify custom product edition label + */ + const INIT_OPTION_EDITION = 'edition'; + + /** + * Product edition labels + */ + const EDITION_COMMUNITY = 'Community'; + const EDITION_ENTERPRISE = 'Enterprise'; + const EDITION_PROFESSIONAL = 'Professional'; + const EDITION_GO = 'Go'; + /** * Registry collection * @@ -113,14 +133,6 @@ final class Mage */ protected static $_design; - /** - * Magento edition constants - */ - const EDITION_COMMUNITY = 'Community'; - const EDITION_ENTERPRISE = 'Enterprise'; - const EDITION_PROFESSIONAL = 'Professional'; - const EDITION_GO = 'Go'; - /** * Current Magento edition. * @@ -163,7 +175,7 @@ final class Mage 'revision' => '0', 'patch' => '0', 'stability' => 'dev', - 'number' => '39', + 'number' => '40', ); } @@ -311,9 +323,11 @@ final class Mage * @param string $type * @return string */ - public static function getBaseDir($type = 'base') + public static function getBaseDir($type = Mage_Core_Model_Dir::ROOT) { - return self::getConfig()->getOptions()->getDir($type); + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = self::$_objectManager->get('Mage_Core_Model_Dir'); + return $dirs->getDir($type); } /** @@ -398,14 +412,23 @@ final class Mage /** * Retrieve a config instance * + * This method doesn't suit Magento 2 anymore, it is left only until refactoring, when all calls + * to Mage::getConfig() will be removed in favor of config dependency injection. + * * @return Mage_Core_Model_Config */ public static function getConfig() { - if (!self::$_config) { - self::$_config = self::getObjectManager()->get('Mage_Core_Model_Config'); + if (self::$_app) { + // Usual workflow - act as a proxy, retrieve config from the application + return self::$_app->getConfig(); + } else { + // Temp workaround for unit tests only, so there is no urgent need to check and refactor them all + if (!self::$_config) { + self::$_config = self::getObjectManager()->get('Mage_Core_Model_Config'); + } + return self::$_config; } - return self::$_config; } /** @@ -620,19 +643,17 @@ final class Mage /** * Get initialized application object. * - * @param string $code - * @param string $type - * @param string|array $options + * @param array $params * @return Mage_Core_Model_App */ - public static function app($code = '', $type = 'store', $options = array()) + public static function app(array $params = array()) { if (null === self::$_app) { self::$_app = self::getObjectManager()->get('Mage_Core_Model_App'); self::$_events = new Varien_Event_Collection(); Magento_Profiler::start('self::app::init'); - self::$_app->init($code, $type, $options); + self::$_app->init($params); Magento_Profiler::stop('self::app::init'); } return self::$_app; @@ -640,26 +661,25 @@ final class Mage /** * @static - * @param string $code - * @param string $type - * @param array $options + * @param array $params * @param string|array $modules */ - public static function init($code = '', $type = 'store', $options = array(), $modules = array()) + public static function init(array $params, $modules = array()) { try { - self::$_app = self::getObjectManager()->create('Mage_Core_Model_App'); - + /** @var $app Mage_Core_Model_App */ + $app = self::getObjectManager()->create('Mage_Core_Model_App'); + self::$_app = $app; if (!empty($modules)) { - self::$_app->initSpecified($code, $type, $options, $modules); + self::$_app->initSpecified($params, $modules); } else { - self::$_app->init($code, $type, $options); + self::$_app->init($params); } } catch (Mage_Core_Model_Session_Exception $e) { header('Location: ' . self::getBaseUrl()); die; } catch (Mage_Core_Model_Store_Exception $e) { - require_once(self::getBaseDir() . DS . 'pub' . DS . 'errors' . DS . '404.php'); + require_once(self::getBaseDir(Mage_Core_Model_Dir::PUB) . DS . 'errors' . DS . '404.php'); die; } catch (Exception $e) { self::printException($e); @@ -670,30 +690,26 @@ final class Mage /** * Front end main entry point * - * @param string $code - * @param string $type - * @param string|array $options + * @param array $params */ - public static function run($code = '', $type = 'store', $options = array()) + public static function run(array $params) { try { Magento_Profiler::start('mage'); - if (isset($options['edition'])) { - self::$_currentEdition = $options['edition']; + if (isset($params[self::INIT_OPTION_EDITION])) { + self::$_currentEdition = $params[self::INIT_OPTION_EDITION]; } - self::$_app = self::getObjectManager()->get('Mage_Core_Model_App'); - if (isset($options['request'])) { - self::$_app->setRequest($options['request']); + /** @var $app Mage_Core_Model_App */ + $app = self::getObjectManager()->create('Mage_Core_Model_App'); + self::$_app = $app; + if (isset($params[self::INIT_OPTION_REQUEST])) { + self::$_app->setRequest($params[self::INIT_OPTION_REQUEST]); } - if (isset($options['response'])) { - self::$_app->setResponse($options['response']); + if (isset($params[self::INIT_OPTION_RESPONSE])) { + self::$_app->setResponse($params[self::INIT_OPTION_RESPONSE]); } self::$_events = new Varien_Event_Collection(); - self::$_app->run(array( - 'scope_code' => $code, - 'scope_type' => $type, - 'options' => $options, - )); + self::$_app->run($params); Magento_Profiler::stop('mage'); } catch (Mage_Core_Model_Session_Exception $e) { header('Location: ' . self::getBaseUrl()); @@ -822,7 +838,7 @@ final class Mage } catch (Exception $e) { } - require_once(self::getBaseDir() . DS . 'pub' . DS . 'errors' . DS . 'report.php'); + require_once(self::getBaseDir(Mage_Core_Model_Dir::PUB) . DS . 'errors' . DS . 'report.php'); } die(); diff --git a/app/bootstrap.php b/app/bootstrap.php index 22da0bd5b7a..bac5bf5a10d 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -43,6 +43,22 @@ umask(0); require_once BP . '/app/code/core/Mage/Core/functions.php'; require_once BP . '/app/Mage.php'; +require_once __DIR__ . '/autoload.php'; +Magento_Autoload_IncludePath::addIncludePath(array( + BP . DS . 'app' . DS . 'code' . DS . 'local', + BP . DS . 'app' . DS . 'code' . DS . 'community', + BP . DS . 'app' . DS . 'code' . DS . 'core', + BP . DS . 'lib', + BP . DS . 'var' . DS . 'generation', +)); +$classMapPath = BP . DS . 'var/classmap.ser'; +if (file_exists($classMapPath)) { + require_once BP . '/lib/Magento/Autoload/ClassMap.php'; + $classMap = new Magento_Autoload_ClassMap(BP); + $classMap->addMap(unserialize(file_get_contents($classMapPath))); + spl_autoload_register(array($classMap, 'load')); +} + if (!defined('BARE_BOOTSTRAP')) { /* PHP version validation */ if (version_compare(phpversion(), '5.3.0', '<') === true) { @@ -94,22 +110,6 @@ HTML; } } -require_once __DIR__ . '/autoload.php'; -Magento_Autoload_IncludePath::addIncludePath(array( - BP . DS . 'app' . DS . 'code' . DS . 'local', - BP . DS . 'app' . DS . 'code' . DS . 'community', - BP . DS . 'app' . DS . 'code' . DS . 'core', - BP . DS . 'lib', - BP . DS . 'var' . DS . 'generation', -)); -$classMapPath = BP . DS . 'var/classmap.ser'; -if (file_exists($classMapPath)) { - require_once BP . '/lib/Magento/Autoload/ClassMap.php'; - $classMap = new Magento_Autoload_ClassMap(BP); - $classMap->addMap(unserialize(file_get_contents($classMapPath))); - spl_autoload_register(array($classMap, 'load')); -} - $definitionsFile = BP . DS . 'var/di/definitions.php'; if (file_exists($definitionsFile)) { Mage::initializeObjectManager($definitionsFile); diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Buttons.php b/app/code/core/Mage/Adminhtml/Block/Api/Buttons.php new file mode 100644 index 00000000000..1f8e478523f --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Buttons.php @@ -0,0 +1,88 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Adminhtml_Block_Api_Buttons extends Mage_Adminhtml_Block_Template +{ + + protected $_template = 'api/userinfo.phtml'; + + protected function _prepareLayout() + { + $this->addChild('backButton', 'Mage_Adminhtml_Block_Widget_Button', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Back'), + 'onclick' => 'window.location.href=\''.$this->getUrl('*/*/').'\'', + 'class' => 'back' + )); + + $this->addChild('resetButton', 'Mage_Adminhtml_Block_Widget_Button', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Reset'), + 'onclick' => 'window.location.reload()' + )); + + $this->addChild('saveButton', 'Mage_Adminhtml_Block_Widget_Button', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Save Role'), + 'class' => 'save', + 'data_attr' => array( + 'widget-button' => array('event' => 'save', 'related' => '#role-edit-form') + ) + )); + + $this->addChild('deleteButton', 'Mage_Adminhtml_Block_Widget_Button', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Delete Role'), + 'onclick' => 'deleteConfirm(\'' . Mage::helper('Mage_Adminhtml_Helper_Data')->__('Are you sure you want to do this?') . '\', \'' . $this->getUrl('*/*/delete', array('rid' => $this->getRequest()->getParam('rid'))) . '\')', + 'class' => 'delete' + )); + return parent::_prepareLayout(); + } + + public function getBackButtonHtml() + { + return $this->getChildHtml('backButton'); + } + + public function getResetButtonHtml() + { + return $this->getChildHtml('resetButton'); + } + + public function getSaveButtonHtml() + { + return $this->getChildHtml('saveButton'); + } + + public function getDeleteButtonHtml() + { + if( intval($this->getRequest()->getParam('rid')) == 0 ) { + return; + } + return $this->getChildHtml('deleteButton'); + } + + public function getUser() + { + return Mage::registry('user_data'); + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Editroles.php b/app/code/core/Mage/Adminhtml/Block/Api/Editroles.php new file mode 100644 index 00000000000..756f5d88845 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Editroles.php @@ -0,0 +1,69 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Adminhtml_Block_Api_Editroles extends Mage_Adminhtml_Block_Widget_Tabs { + protected function _construct() + { + parent::_construct(); + $this->setId('role_info_tabs'); + $this->setDestElementId('role-edit-form'); + $this->setTitle(Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Information')); + } + + protected function _beforeToHtml() + { + $roleId = $this->getRequest()->getParam('rid', false); + $role = Mage::getModel('Mage_Api_Model_Roles') + ->load($roleId); + + $this->addTab('info', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Info'), + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Info'), + 'content' => $this->getLayout()->createBlock( + 'Mage_Adminhtml_Block_Api_Tab_Roleinfo' + )->setRole($role)->toHtml(), + 'active' => true + )); + + $this->addTab('account', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Resources'), + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Resources'), + 'content' => $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_Tab_Rolesedit')->toHtml(), + )); + + if( intval($roleId) > 0 ) { + $this->addTab('roles', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Users'), + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Users'), + 'content' => $this->getLayout()->createBlock( + 'Mage_Adminhtml_Block_Api_Tab_Rolesusers', + 'role.users.grid' + )->toHtml(), + )); + } + return parent::_beforeToHtml(); + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Grid/Role.php b/app/code/core/Mage/Adminhtml/Block/Api/Grid/Role.php new file mode 100644 index 00000000000..66f3f11a7d7 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Grid/Role.php @@ -0,0 +1,81 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * roles grid + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Block_Api_Grid_Role extends Mage_Adminhtml_Block_Widget_Grid +{ + protected function _construct() + { + parent::_construct(); + $this->setId('roleGrid'); + $this->setSaveParametersInSession(true); + $this->setDefaultSort('role_id'); + $this->setDefaultDir('asc'); + $this->setUseAjax(true); + } + + protected function _prepareCollection() + { + $collection = Mage::getModel('Mage_Api_Model_Roles')->getCollection(); + $this->setCollection($collection); + + return parent::_prepareCollection(); + } + + protected function _prepareColumns() + { + + $this->addColumn('role_id', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('ID'), + 'index' =>'role_id', + 'align' => 'right', + 'width' => '50px' + )); + + $this->addColumn('role_name', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Name'), + 'index' =>'role_name' + )); + + return parent::_prepareColumns(); + } + + public function getGridUrl() + { + return $this->getUrl('*/*/roleGrid', array('_current'=>true)); + } + + public function getRowUrl($row) + { + return $this->getUrl('*/*/editrole', array('rid' => $row->getRoleId())); + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Role.php b/app/code/core/Mage/Adminhtml/Block/Api/Role.php new file mode 100644 index 00000000000..0132077acd0 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Role.php @@ -0,0 +1,37 @@ +<?php +/** + * Adminhtml permissioms role block + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Adminhtml_Block_Api_Role extends Mage_Adminhtml_Block_Widget_Grid_Container +{ + + protected function _construct() + { + $this->_controller = 'api_role'; + $this->_headerText = Mage::helper('Mage_Adminhtml_Helper_Data')->__('Roles'); + $this->_addButtonLabel = Mage::helper('Mage_Adminhtml_Helper_Data')->__('Add New Role'); + parent::_construct(); + } + +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Role/Grid/User.php b/app/code/core/Mage/Adminhtml/Block/Api/Role/Grid/User.php new file mode 100644 index 00000000000..f220af82959 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Role/Grid/User.php @@ -0,0 +1,182 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Acl role user grid + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Block_Api_Role_Grid_User extends Mage_Adminhtml_Block_Widget_Grid +{ + + protected function _construct() + { + parent::_construct(); + $this->setDefaultSort('role_user_id'); + $this->setDefaultDir('asc'); + $this->setId('roleUserGrid'); + $this->setDefaultFilter(array('in_role_users'=>1)); + $this->setUseAjax(true); + } + + protected function _addColumnFilterToCollection($column) + { + if ($column->getId() == 'in_role_users') { + $inRoleIds = $this->_getUsers(); + if (empty($inRoleIds)) { + $inRoleIds = 0; + } + if ($column->getFilter()->getValue()) { + $this->getCollection()->addFieldToFilter('user_id', array('in'=>$inRoleIds)); + } + else { + if($inRoleIds) { + $this->getCollection()->addFieldToFilter('user_id', array('nin'=>$inRoleIds)); + } + } + } + else { + parent::_addColumnFilterToCollection($column); + } + return $this; + } + + protected function _prepareCollection() + { + $roleId = $this->getRequest()->getParam('rid'); + Mage::register('RID', $roleId); + $collection = Mage::getModel('Mage_Api_Model_Roles')->getUsersCollection(); + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + protected function _prepareColumns() + { + $this->addColumn('in_role_users', array( + 'header_css_class' => 'a-center', + 'type' => 'checkbox', + 'name' => 'in_role_users', + 'values' => $this->_getUsers(), + 'align' => 'center', + 'index' => 'user_id' + )); + + $this->addColumn('role_user_id', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('User ID'), + 'width' =>5, + 'align' =>'left', + 'sortable' =>true, + 'index' =>'user_id' + )); + + $this->addColumn('role_user_username', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Name'), + 'align' =>'left', + 'index' =>'username' + )); + + $this->addColumn('role_user_firstname', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('First Name'), + 'align' =>'left', + 'index' =>'firstname' + )); + + $this->addColumn('role_user_lastname', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Last Name'), + 'align' =>'left', + 'index' =>'lastname' + )); + + $this->addColumn('role_user_email', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Email'), + 'width' =>40, + 'align' =>'left', + 'index' =>'email' + )); + + $this->addColumn('role_user_is_active', array( + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Status'), + 'index' => 'is_active', + 'align' =>'left', + 'type' => 'options', + 'options' => array('1' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Active'), '0' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Inactive')), + )); + + /* + $this->addColumn('grid_actions', + array( + 'header'=>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Actions'), + 'width'=>5, + 'sortable'=>false, + 'filter' =>false, + 'type' => 'action', + 'actions' => array( + array( + 'caption' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Remove'), + 'onClick' => 'role.deleteFromRole($role_id);' + ) + ) + ) + ); + */ + + return parent::_prepareColumns(); + } + + public function getGridUrl() + { + $roleId = $this->getRequest()->getParam('rid'); + return $this->getUrl('*/*/editrolegrid', array('rid' => $roleId)); + } + + protected function _getUsers($json=false) + { + if ( $this->getRequest()->getParam('in_role_user') != "" ) { + return $this->getRequest()->getParam('in_role_user'); + } + $roleId = ( $this->getRequest()->getParam('rid') > 0 ) ? $this->getRequest()->getParam('rid') : Mage::registry('RID'); + $users = Mage::getModel('Mage_Api_Model_Roles')->setId($roleId)->getRoleUsers(); + if (sizeof($users) > 0) { + if ( $json ) { + $jsonUsers = Array(); + foreach($users as $usrid) $jsonUsers[$usrid] = 0; + return Mage::helper('Mage_Core_Helper_Data')->jsonEncode((object)$jsonUsers); + } else { + return array_values($users); + } + } else { + if ( $json ) { + return '{}'; + } else { + return array(); + } + } + } + +} + diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Roles.php b/app/code/core/Mage/Adminhtml/Block/Api/Roles.php new file mode 100644 index 00000000000..f199067242d --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Roles.php @@ -0,0 +1,48 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * user roles block + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Block_Api_Roles extends Mage_Adminhtml_Block_Template +{ + + protected $_template = 'api/roles.phtml'; + + public function getAddNewUrl() + { + return $this->getUrl('*/*/editrole'); + } + + public function getGridHtml() + { + return $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_Grid_Role')->toHtml(); + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Tab/Roleinfo.php b/app/code/core/Mage/Adminhtml/Block/Api/Tab/Roleinfo.php new file mode 100644 index 00000000000..ed57e4098fc --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Tab/Roleinfo.php @@ -0,0 +1,69 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Adminhtml_Block_Api_Tab_Roleinfo extends Mage_Adminhtml_Block_Widget_Form +{ + public function _beforeToHtml() { + $this->_initForm(); + + return parent::_beforeToHtml(); + } + + protected function _initForm() + { + $roleId = $this->getRequest()->getParam('rid'); + + $form = new Varien_Data_Form(); + + $fieldset = $form->addFieldset('base_fieldset', array('legend'=>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Information'))); + + $fieldset->addField('role_name', 'text', + array( + 'name' => 'rolename', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Name'), + 'id' => 'role_name', + 'class' => 'required-entry', + 'required' => true, + ) + ); + + $fieldset->addField('role_id', 'hidden', + array( + 'name' => 'role_id', + 'id' => 'role_id', + ) + ); + + $fieldset->addField('in_role_user', 'hidden', + array( + 'name' => 'in_role_user', + 'id' => 'in_role_userz', + ) + ); + + $fieldset->addField('in_role_user_old', 'hidden', array('name' => 'in_role_user_old')); + + $form->setValues($this->getRole()->getData()); + $this->setForm($form); + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesedit.php b/app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesedit.php new file mode 100644 index 00000000000..2acc4d1ec69 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesedit.php @@ -0,0 +1,122 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Adminhtml_Block_Api_Tab_Rolesedit extends Mage_Adminhtml_Block_Widget_Form { + + protected $_template = 'api/rolesedit.phtml'; + + + protected function _construct() { + parent::_construct(); + + $rid = Mage::app()->getRequest()->getParam('rid', false); + + $resources = Mage::getModel('Mage_Api_Model_Roles')->getResourcesList(); + + $rules_set = Mage::getResourceModel('Mage_Api_Model_Resource_Rules_Collection')->getByRoles($rid)->load(); + + $selrids = array(); + + foreach ($rules_set->getItems() as $item) { + if (array_key_exists(strtolower($item->getResource_id()), $resources) + && $item->getApiPermission() == 'allow') + { + $resources[$item->getResource_id()]['checked'] = true; + array_push($selrids, $item->getResource_id()); + } + } + + $this->setSelectedResources($selrids); + + + //->assign('resources', $resources); + //->assign('checkedResources', join(',', $selrids)); + } + + public function getEverythingAllowed() + { + return in_array('all', $this->getSelectedResources()); + } + + public function getResTreeJson() + { + $rid = Mage::app()->getRequest()->getParam('rid', false); + $resources = Mage::getModel('Mage_Api_Model_Roles')->getResourcesTree(); + + $rootArray = $this->_getNodeJson($resources,1); + + $json = Mage::helper('Mage_Core_Helper_Data')->jsonEncode(isset($rootArray['children']) ? $rootArray['children'] : array()); + + return $json; + } + + protected function _sortTree($a, $b) + { + return $a['sort_order']<$b['sort_order'] ? -1 : ($a['sort_order']>$b['sort_order'] ? 1 : 0); + } + + + protected function _getNodeJson($node, $level=0) + { + $item = array(); + $selres = $this->getSelectedResources(); + + if ($level != 0) { + $item['text']= (string)$node->title; + $item['sort_order']= isset($node->sort_order) ? (string)$node->sort_order : 0; + $item['id'] = (string)$node->attributes()->aclpath; + + if (in_array($item['id'], $selres)) + $item['checked'] = true; + } + if (isset($node->children)) { + $children = $node->children->children(); + } else { + $children = $node->children(); + } + if (empty($children)) { + return $item; + } + + if ($children) { + $item['children'] = array(); + //$item['cls'] = 'fiche-node'; + foreach ($children as $child) { + if ($child->getName()!='title' && $child->getName()!='sort_order' && $child->attributes()->module) { + if ($level != 0) { + $item['children'][] = $this->_getNodeJson($child, $level+1); + } else { + $item = $this->_getNodeJson($child, $level+1); + } + } + } + if (!empty($item['children'])) { + usort($item['children'], array($this, '_sortTree')); + } + } + return $item; + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesusers.php b/app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesusers.php new file mode 100644 index 00000000000..bacf853a403 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/Tab/Rolesusers.php @@ -0,0 +1,54 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Adminhtml_Block_Api_Tab_Rolesusers extends Mage_Adminhtml_Block_Widget_Tabs { + + protected function _construct() + { + parent::_construct(); + + $roleId = $this->getRequest()->getParam('rid', false); + + $users = Mage::getModel('Mage_Api_Model_User')->getCollection()->load(); + $this->setTemplate('api/rolesusers.phtml') + ->assign('users', $users->getItems()) + ->assign('roleId', $roleId); + } + + protected function _prepareLayout() + { + $this->setChild( + 'userGrid', + $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_Role_Grid_User', 'roleUsersGrid') + ); + return parent::_prepareLayout(); + } + + protected function _getGridHtml() + { + return $this->getChildHtml('userGrid'); + } +} diff --git a/app/code/core/Mage/Core/Block/Template/Zend.php b/app/code/core/Mage/Adminhtml/Block/Api/User.php similarity index 57% rename from app/code/core/Mage/Core/Block/Template/Zend.php rename to app/code/core/Mage/Adminhtml/Block/Api/User.php index 0c005e426c6..54f560c56e1 100644 --- a/app/code/core/Mage/Core/Block/Template/Zend.php +++ b/app/code/core/Mage/Adminhtml/Block/Api/User.php @@ -19,56 +19,37 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category Mage - * @package Mage_Core + * @package Mage_Adminhtml * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - /** - * Zend html block + * Adminhtml permissions user block * * @category Mage - * @package Mage_Core + * @package Mage_Adminhtml * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Core_Block_Template_Zend extends Mage_Core_Block_Template +class Mage_Adminhtml_Block_Api_User extends Mage_Adminhtml_Block_Widget_Grid_Container { - protected $_view = null; - - /** - * Class constructor. Base html block - * - * @param none - * @return void - */ - function _construct() + protected function _construct() { + $this->_controller = 'api_user'; + $this->_headerText = Mage::helper('Mage_Adminhtml_Helper_Data')->__('Users'); + $this->_addButtonLabel = Mage::helper('Mage_Adminhtml_Helper_Data')->__('Add New User'); parent::_construct(); - $this->_view = new Zend_View(); - } - - public function assign($key, $value=null) - { - if (is_array($key) && is_null($value)) { - foreach ($key as $k=>$v) { - $this->assign($k, $v); - } - } elseif (!is_null($value)) { - $this->_view->assign($key, $value); - } - return $this; } - public function setScriptPath($dir) - { - $this->_view->setScriptPath($dir.DS); - } - - public function fetchView($fileName) + /** + * Prepare output HTML + * + * @return string + */ + protected function _toHtml() { - return $this->_view->render($fileName); + Mage::dispatchEvent('api_user_html_before', array('block' => $this)); + return parent::_toHtml(); } - } diff --git a/app/code/core/Mage/Adminhtml/Block/Api/User/Edit.php b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit.php new file mode 100644 index 00000000000..104e6a116b8 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit.php @@ -0,0 +1,58 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Adminhtml permissions user edit page + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Block_Api_User_Edit extends Mage_Adminhtml_Block_Widget_Form_Container +{ + + protected function _construct() + { + $this->_objectId = 'user_id'; + $this->_controller = 'api_user'; + + parent::_construct(); + + $this->_updateButton('save', 'label', Mage::helper('Mage_Adminhtml_Helper_Data')->__('Save User')); + $this->_updateButton('delete', 'label', Mage::helper('Mage_Adminhtml_Helper_Data')->__('Delete User')); + } + + public function getHeaderText() + { + if (Mage::registry('api_user')->getId()) { + return Mage::helper('Mage_Adminhtml_Helper_Data')->__("Edit User '%s'", $this->escapeHtml(Mage::registry('api_user')->getUsername())); + } + else { + return Mage::helper('Mage_Adminhtml_Helper_Data')->__('New User'); + } + } + +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Form.php b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Form.php new file mode 100644 index 00000000000..ce33093e613 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Form.php @@ -0,0 +1,45 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Adminhtml permissions user edit form + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Block_Api_User_Edit_Form extends Mage_Adminhtml_Block_Widget_Form +{ + + protected function _prepareForm() + { + $form = new Varien_Data_Form(array('id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post')); + $form->setUseContainer(true); + $this->setForm($form); + return parent::_prepareForm(); + } + +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php new file mode 100644 index 00000000000..4ef7f8cf40c --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Main.php @@ -0,0 +1,153 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Cms page edit form main tab + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Adminhtml_Block_Api_User_Edit_Tab_Main extends Mage_Adminhtml_Block_Widget_Form +{ + + protected function _prepareForm() + { + $model = Mage::registry('api_user'); + + $form = new Varien_Data_Form(); + + $form->setHtmlIdPrefix('user_'); + + $fieldset = $form->addFieldset('base_fieldset', array('legend'=>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Account Information'))); + + if ($model->getUserId()) { + $fieldset->addField('user_id', 'hidden', array( + 'name' => 'user_id', + )); + } else { + if (! $model->hasData('is_active')) { + $model->setIsActive(1); + } + } + + $fieldset->addField('username', 'text', array( + 'name' => 'username', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Name'), + 'id' => 'username', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Name'), + 'required' => true, + )); + + $fieldset->addField('firstname', 'text', array( + 'name' => 'firstname', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('First Name'), + 'id' => 'firstname', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('First Name'), + 'required' => true, + )); + + $fieldset->addField('lastname', 'text', array( + 'name' => 'lastname', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Last Name'), + 'id' => 'lastname', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Last Name'), + 'required' => true, + )); + + $fieldset->addField('email', 'text', array( + 'name' => 'email', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Email'), + 'id' => 'customer_email', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Email'), + 'class' => 'required-entry validate-email', + 'required' => true, + )); + + if ($model->getUserId()) { + $fieldset->addField('password', 'password', array( + 'name' => 'new_api_key', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('New API Key'), + 'id' => 'new_pass', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('New API Key'), + 'class' => 'input-text validate-password', + )); + + $fieldset->addField('confirmation', 'password', array( + 'name' => 'api_key_confirmation', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('API Key Confirmation'), + 'id' => 'confirmation', + 'class' => 'input-text validate-cpassword', + )); + } + else { + $fieldset->addField('password', 'password', array( + 'name' => 'api_key', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('API Key'), + 'id' => 'customer_pass', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('API Key'), + 'class' => 'input-text required-entry validate-password', + 'required' => true, + )); + $fieldset->addField('confirmation', 'password', array( + 'name' => 'api_key_confirmation', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('API Key Confirmation'), + 'id' => 'confirmation', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('API Key Confirmation'), + 'class' => 'input-text required-entry validate-cpassword', + 'required' => true, + )); + } + + if (Mage::getSingleton('Mage_Backend_Model_Auth_Session')->getUser()->getId() != $model->getUserId()) { + $fieldset->addField('is_active', 'select', array( + 'name' => 'is_active', + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('This account is'), + 'id' => 'is_active', + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Account status'), + 'class' => 'input-select', + 'style' => 'width: 80px', + 'options' => array('1' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Active'), '0' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Inactive')), + )); + } + + $fieldset->addField('user_roles', 'hidden', array( + 'name' => 'user_roles', + 'id' => '_user_roles', + )); + + $data = $model->getData(); + + unset($data['password']); + + $form->setValues($data); + + $this->setForm($form); + + return parent::_prepareForm(); + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Roles.php b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Roles.php new file mode 100644 index 00000000000..3dddfc46177 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tab/Roles.php @@ -0,0 +1,119 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Adminhtml_Block_Api_User_Edit_Tab_Roles extends Mage_Adminhtml_Block_Widget_Grid +{ + + protected function _construct() + { + parent::_construct(); + $this->setId('permissionsUserRolesGrid'); + $this->setDefaultSort('sort_order'); + $this->setDefaultDir('asc'); + //$this->setDefaultFilter(array('assigned_user_role'=>1)); + $this->setTitle(Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Roles Information')); + $this->setUseAjax(true); + } + + protected function _addColumnFilterToCollection($column) + { + if ($column->getId() == 'assigned_user_role') { + $userRoles = $this->_getSelectedRoles(); + if (empty($userRoles)) { + $userRoles = 0; + } + if ($column->getFilter()->getValue()) { + $this->getCollection()->addFieldToFilter('role_id', array('in'=>$userRoles)); + } + else { + if($userRoles) { + $this->getCollection()->addFieldToFilter('role_id', array('nin'=>$userRoles)); + } + } + } + else { + parent::_addColumnFilterToCollection($column); + } + return $this; + } + + protected function _prepareCollection() + { + $collection = Mage::getResourceModel('Mage_Api_Model_Resource_Role_Collection'); + $collection->setRolesFilter(); + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + protected function _prepareColumns() + { + + $this->addColumn('assigned_user_role', array( + 'header_css_class' => 'a-center', + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Assigned'), + 'type' => 'radio', + 'html_name' => 'roles[]', + 'values' => $this->_getSelectedRoles(), + 'align' => 'center', + 'index' => 'role_id' + )); + + /*$this->addColumn('role_id', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role ID'), + 'index' =>'role_id', + 'align' => 'right', + 'width' => '50px' + ));*/ + + $this->addColumn('role_name', array( + 'header' =>Mage::helper('Mage_Adminhtml_Helper_Data')->__('Role Name'), + 'index' =>'role_name' + )); + + return parent::_prepareColumns(); + } + + public function getGridUrl() + { + return $this->getUrl('*/*/rolesGrid', array('user_id' => Mage::registry('api_user')->getUserId())); + } + + protected function _getSelectedRoles($json=false) + { + if ( $this->getRequest()->getParam('user_roles') != "" ) { + return $this->getRequest()->getParam('user_roles'); + } + $uRoles = Mage::registry('api_user')->getRoles(); + if ($json) { + $jsonRoles = Array(); + foreach($uRoles as $urid) $jsonRoles[$urid] = 0; + return Mage::helper('Mage_Core_Helper_Data')->jsonEncode((object)$jsonRoles); + } else { + return $uRoles; + } + } + +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tabs.php b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tabs.php new file mode 100644 index 00000000000..14851aa8436 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/User/Edit/Tabs.php @@ -0,0 +1,65 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Admin page left menu + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Block_Api_User_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs +{ + + protected function _construct() + { + parent::_construct(); + $this->setId('page_tabs'); + $this->setDestElementId('edit_form'); + $this->setTitle(Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Information')); + } + + protected function _beforeToHtml() + { + $this->addTab('main_section', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Info'), + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Info'), + 'content' => $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_User_Edit_Tab_Main')->toHtml(), + 'active' => true + )); + + $this->addTab('roles_section', array( + 'label' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Role'), + 'title' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Role'), + 'content' => $this->getLayout()->createBlock( + 'Mage_Adminhtml_Block_Api_User_Edit_Tab_Roles', + 'user.roles.grid' + )->toHtml(), + )); + return parent::_beforeToHtml(); + } + +} diff --git a/app/code/core/Mage/Adminhtml/Block/Api/User/Grid.php b/app/code/core/Mage/Adminhtml/Block/Api/User/Grid.php new file mode 100644 index 00000000000..0e635df6722 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Api/User/Grid.php @@ -0,0 +1,106 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Adminhtml permissions user grid + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Block_Api_User_Grid extends Mage_Adminhtml_Block_Widget_Grid +{ + + protected function _construct() + { + parent::_construct(); + $this->setId('permissionsUserGrid'); + $this->setDefaultSort('username'); + $this->setDefaultDir('asc'); + $this->setUseAjax(true); + } + + protected function _prepareCollection() + { + $collection = Mage::getResourceModel('Mage_Api_Model_Resource_User_Collection'); + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + protected function _prepareColumns() + { + $this->addColumn('user_id', array( + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('ID'), + 'width' => 5, + 'align' => 'right', + 'sortable' => true, + 'index' => 'user_id' + )); + + $this->addColumn('username', array( + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('User Name'), + 'index' => 'username' + )); + + $this->addColumn('firstname', array( + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('First Name'), + 'index' => 'firstname' + )); + + $this->addColumn('lastname', array( + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Last Name'), + 'index' => 'lastname' + )); + + $this->addColumn('email', array( + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Email'), + 'width' => 40, + 'align' => 'left', + 'index' => 'email' + )); + + $this->addColumn('is_active', array( + 'header' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Status'), + 'index' => 'is_active', + 'type' => 'options', + 'options' => array('1' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Active'), '0' => Mage::helper('Mage_Adminhtml_Helper_Data')->__('Inactive')), + )); + + return parent::_prepareColumns(); + } + + public function getRowUrl($row) + { + return $this->getUrl('*/*/edit', array('user_id' => $row->getId())); + } + + public function getGridUrl() + { + //$uid = $this->getRequest()->getParam('user_id'); + return $this->getUrl('*/*/roleGrid', array()); + } + +} diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tree.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tree.php index 78ad8b75d2d..00cb782c93b 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tree.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tree.php @@ -149,7 +149,7 @@ class Mage_Adminhtml_Block_Catalog_Category_Tree extends Mage_Adminhtml_Block_Ca } } $categoryById[$category->getId()]['is_active'] = $category->getIsActive(); - $categoryById[$category->getId()]['name'] = $category->getName(); + $categoryById[$category->getId()]['label'] = $category->getName(); $categoryById[$category->getParentId()]['children'][] = &$categoryById[$category->getId()]; } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php index 586e53d870c..fae5ad7042f 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Option.php @@ -154,7 +154,7 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Options_Option extends Mage_ public function getTypeSelectHtml() { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setData(array( 'id' => $this->getFieldId().'_{{id}}_type', 'class' => 'select select-product-option-type required-option-select' @@ -167,7 +167,7 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Options_Option extends Mage_ public function getRequireSelectHtml() { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setData(array( 'id' => $this->getFieldId().'_{{id}}_is_require', 'class' => 'select' diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Type/Abstract.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Type/Abstract.php index f23fc2bc472..7724605a743 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Type/Abstract.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Options/Type/Abstract.php @@ -39,7 +39,7 @@ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Options_Type_Abstract extend protected function _prepareLayout() { $this->setChild('option_price_type', - $this->getLayout()->addBlock('Mage_Adminhtml_Block_Html_Select', '', $this->getNameInLayout()) + $this->getLayout()->addBlock('Mage_Core_Block_Html_Select', '', $this->getNameInLayout()) ->setData(array( 'id' => 'product_option_{{option_id}}_price_type', 'class' => 'select product-option-price-type' diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Group.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Group.php deleted file mode 100644 index bf7f14eafc8..00000000000 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Group.php +++ /dev/null @@ -1,236 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Mage - * @package Mage_Adminhtml - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -/** - * Product in category grid - * - * @category Mage - * @package Mage_Adminhtml - * @author Magento Core Team <core@magentocommerce.com> - */ -class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Group extends Mage_Adminhtml_Block_Widget_Grid - implements Mage_Adminhtml_Block_Widget_Tab_Interface -{ - protected function _construct() - { - parent::_construct(); - $this->setId('super_product_grid'); - $this->setDefaultSort('entity_id'); - $this->setSkipGenerateContent(true); - $this->setUseAjax(true); - if ($this->_getProduct() && $this->_getProduct()->getId()) { - $this->setDefaultFilter(array('in_products'=>1)); - } - } - - public function getTabUrl() - { - return $this->getUrl('*/*/superGroup', array('_current'=>true)); - } - - public function getTabClass() - { - return 'ajax'; - } - - /** - * Retrieve currently edited product model - * - * @return Mage_Catalog_Model_Product - */ - protected function _getProduct() - { - return Mage::registry('current_product'); - } - - protected function _addColumnFilterToCollection($column) - { - // Set custom filter for in product flag - if ($column->getId() == 'in_products') { - $productIds = $this->_getSelectedProducts(); - if (empty($productIds)) { - $productIds = 0; - } - if ($column->getFilter()->getValue()) { - $this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds)); - } - else { - $this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$productIds)); - } - } - else { - parent::_addColumnFilterToCollection($column); - } - - return $this; - } - - /** - * Prepare collection - * - * @return Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Group - */ - protected function _prepareCollection() - { - $allowProductTypes = array(); - $allowProductTypeNodes = Mage::getConfig() - ->getNode('global/catalog/product/type/grouped/allow_product_types')->children(); - foreach ($allowProductTypeNodes as $type) { - $allowProductTypes[] = $type->getName(); - } - - $collection = Mage::getModel('Mage_Catalog_Model_Product_Link')->useGroupedLinks() - ->getProductCollection() - ->setProduct($this->_getProduct()) - ->addAttributeToSelect('*') - ->addFilterByRequiredOptions() - ->addAttributeToFilter('type_id', $allowProductTypes); - - if ($this->getIsReadonly() === true) { - $collection->addFieldToFilter('entity_id', array('in' => $this->_getSelectedProducts())); - } - $this->setCollection($collection); - return parent::_prepareCollection(); - } - - protected function _prepareColumns() - { - $this->addColumn('in_products', array( - 'header_css_class' => 'a-center', - 'type' => 'checkbox', - 'name' => 'in_products', - 'values' => $this->_getSelectedProducts(), - 'align' => 'center', - 'index' => 'entity_id' - )); - - $this->addColumn('entity_id', array( - 'header' => Mage::helper('Mage_Catalog_Helper_Data')->__('ID'), - 'sortable' => true, - 'width' => '60px', - 'index' => 'entity_id' - )); - $this->addColumn('name', array( - 'header' => Mage::helper('Mage_Catalog_Helper_Data')->__('Name'), - 'index' => 'name' - )); - $this->addColumn('sku', array( - 'header' => Mage::helper('Mage_Catalog_Helper_Data')->__('SKU'), - 'width' => '80px', - 'index' => 'sku' - )); - $this->addColumn('price', array( - 'header' => Mage::helper('Mage_Catalog_Helper_Data')->__('Price'), - 'type' => 'currency', - 'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE), - 'index' => 'price' - )); - - $this->addColumn('qty', array( - 'header' => Mage::helper('Mage_Catalog_Helper_Data')->__('Default Qty'), - 'name' => 'qty', - 'type' => 'number', - 'validate_class' => 'validate-number', - 'index' => 'qty', - 'width' => '1', - 'editable' => true - )); - - $this->addColumn('position', array( - 'header' => Mage::helper('Mage_Catalog_Helper_Data')->__('Position'), - 'name' => 'position', - 'type' => 'number', - 'validate_class' => 'validate-number', - 'index' => 'position', - 'width' => '1', - 'editable' => true, - 'edit_only' => !$this->_getProduct()->getId() - )); - - return parent::_prepareColumns(); - } - - /** - * Get Grid Url - * - * @return string - */ - public function getGridUrl() - { - return $this->_getData('grid_url') - ? $this->_getData('grid_url') : $this->getUrl('*/*/superGroupGridOnly', array('_current'=>true)); - } - - /** - * Retrieve selected grouped products - * - * @return array - */ - protected function _getSelectedProducts() - { - $products = $this->getProductsGrouped(); - if (!is_array($products)) { - $products = array_keys($this->getSelectedGroupedProducts()); - } - return $products; - } - - /** - * Retrieve grouped products - * - * @return array - */ - public function getSelectedGroupedProducts() - { - $associatedProducts = Mage::registry('current_product')->getTypeInstance() - ->getAssociatedProducts(Mage::registry('current_product')); - $products = array(); - foreach ($associatedProducts as $product) { - $products[$product->getId()] = array( - 'qty' => $product->getQty(), - 'position' => $product->getPosition() - ); - } - return $products; - } - - public function getTabLabel() - { - return Mage::helper('Mage_Catalog_Helper_Data')->__('Associated Products'); - } - public function getTabTitle() - { - return Mage::helper('Mage_Catalog_Helper_Data')->__('Associated Products'); - } - public function canShowTab() - { - return true; - } - public function isHidden() - { - return false; - } -} diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Frontend/Product/Watermark.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Frontend/Product/Watermark.php index 223400b1163..b94eff85227 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Frontend/Product/Watermark.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Frontend/Product/Watermark.php @@ -31,7 +31,9 @@ * @package Mage_Adminhtml * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Adminhtml_Block_Catalog_Product_Frontend_Product_Watermark extends Mage_Adminhtml_Block_Abstract implements Varien_Data_Form_Element_Renderer_Interface +class Mage_Adminhtml_Block_Catalog_Product_Frontend_Product_Watermark + extends Mage_Core_Block_Template + implements Varien_Data_Form_Element_Renderer_Interface { const XML_PATH_IMAGE_TYPES = 'global/catalog/product/media/image_types'; diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Category.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Category.php index 9cdbb7bb09e..3bee6f60ffb 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Category.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Category.php @@ -76,11 +76,46 @@ class Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Category extends Varien_D { /** @var $coreHelper Mage_Core_Helper_Data */ $coreHelper = Mage::helper('Mage_Core_Helper_Data'); + $treeOptions = $coreHelper->escapeHtml($coreHelper->jsonEncode(array( + 'jstree' => array( + 'plugins' => array('themes', 'html_data', 'ui', 'hotkeys'), + 'themes' => array( + 'theme' => 'default', + 'dots' => false, + 'icons' => false, + ), + ) + ))); + return parent::getElementHtml() . "\n" + . '<input id="' . $this->getHtmlId() . '-suggest" />' . "\n" + . '<script id="' . $this->getHtmlId() . '-template" type="text/x-jquery-tmpl">' + . '{{if $data.allShown()}}' + . '{{if typeof nested === "undefined"}}' + . '<div style="display:none;" data-mage-init="' . $treeOptions . '">{{/if}}' + . '<ul>{{each items}}' + . '<li><a href="#" {{html optionData($value)}}>${$value.label}</a>' + . '{{if $value.children && $value.children.length}}' + . '{{html renderTreeLevel($value.children)}}' + . '{{/if}}' + . '</li>{{/each}}</ul>' + . '{{if typeof nested === "undefined"}}</div>{{/if}}' + . '{{else}}' + . '<ul data-mage-init="{"menu":[]}">' + . '{{each items}}' + . '<li {{html optionData($value)}}><a href="#"><span class="category-label">${$value.label}<span>' + . '<span class="category-path">${$value.path}<span></a></li>' + . '{{/each}}</ul>' + . '{{/if}}' + . '</script>' . "\n" . '<script>//<![CDATA[' . "\n" - . 'jQuery(' . $coreHelper->jsonEncode('#' . $this->getHtmlId()) . ').categorySelector(' - . $coreHelper->jsonEncode($this->_getSelectorOptions()) . ')' . "\n" - . '//]]></script>'; + . 'jQuery(' . $coreHelper->jsonEncode('#' . $this->getHtmlId() . '-suggest') . ').treeSuggest(' + . $coreHelper->jsonEncode($this->_getSelectorOptions()) . ');' . "\n" + . '//]]></script>' + . '<button title="' . $coreHelper->__('New Category') . '" type="button"' + . ' onclick="jQuery(\'#new-category\').dialog(\'open\')">' + . '<span><span><span>' . $coreHelper->__('New Category') . '</span></span></span>' + . '</button>'; } /** @@ -91,7 +126,12 @@ class Mage_Adminhtml_Block_Catalog_Product_Helper_Form_Category extends Varien_D protected function _getSelectorOptions() { return array( - 'url' => Mage::helper('Mage_Backend_Helper_Data')->getUrl('adminhtml/catalog_category/suggestCategories'), + 'source' => Mage::helper('Mage_Backend_Helper_Data') + ->getUrl('adminhtml/catalog_category/suggestCategories'), + 'valueField' => '#' . $this->getHtmlId(), + 'template' => '#' . $this->getHtmlId() . '-template', + 'control' => 'jstree', + 'className' => 'category-select' ); } } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Options/Ajax.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Options/Ajax.php index c7d8b7fbc85..171985da8a1 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Options/Ajax.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Options/Ajax.php @@ -31,7 +31,7 @@ * @package Mage_Adminhtml * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Adminhtml_Block_Catalog_Product_Options_Ajax extends Mage_Backend_Block_Abstract +class Mage_Adminhtml_Block_Catalog_Product_Options_Ajax extends Mage_Core_Block_Template { /** * Return product custom options in JSON format diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php index b9b92e25849..bb570115e48 100644 --- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php +++ b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Newpass.php @@ -31,7 +31,9 @@ * @package Mage_Adminhtml * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Adminhtml_Block_Customer_Edit_Renderer_Newpass extends Mage_Adminhtml_Block_Abstract implements Varien_Data_Form_Element_Renderer_Interface +class Mage_Adminhtml_Block_Customer_Edit_Renderer_Newpass + extends Mage_Core_Block_Template + implements Varien_Data_Form_Element_Renderer_Interface { public function render(Varien_Data_Form_Element_Abstract $element) diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Region.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Region.php index b8b99879cf5..7a011f5e6ff 100644 --- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Region.php +++ b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Renderer/Region.php @@ -30,7 +30,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Adminhtml_Block_Customer_Edit_Renderer_Region - extends Mage_Adminhtml_Block_Abstract + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { /** diff --git a/app/code/core/Mage/Adminhtml/Block/Html/Date.php b/app/code/core/Mage/Adminhtml/Block/Html/Date.php deleted file mode 100644 index 63927e368da..00000000000 --- a/app/code/core/Mage/Adminhtml/Block/Html/Date.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Mage - * @package Mage_Adminhtml - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - - -/** - * Adminhtml HTML select element block - * - * @category Mage - * @package Mage_Core - * @author Magento Core Team <core@magentocommerce.com> - */ -class Mage_Adminhtml_Block_Html_Date extends Mage_Core_Block_Html_Date -{ - - /** - * @param Mage_Core_Controller_Request_Http $request - * @param Mage_Core_Model_Layout $layout - * @param Mage_Core_Model_Event_Manager $eventManager - * @param Mage_Backend_Model_Url $urlBuilder - * @param Mage_Core_Model_Translate $translator - * @param Mage_Core_Model_Cache $cache - * @param Mage_Core_Model_Design_Package $designPackage - * @param Mage_Core_Model_Session $session - * @param Mage_Core_Model_Store_Config $storeConfig - * @param Mage_Core_Controller_Varien_Front $frontController - * @param Mage_Core_Model_Factory_Helper $helperFactory - * @param Magento_Filesystem $filesystem - * @param array $data - * - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - */ - public function __construct( - Mage_Core_Controller_Request_Http $request, - Mage_Core_Model_Layout $layout, - Mage_Core_Model_Event_Manager $eventManager, - Mage_Backend_Model_Url $urlBuilder, - Mage_Core_Model_Translate $translator, - Mage_Core_Model_Cache $cache, - Mage_Core_Model_Design_Package $designPackage, - Mage_Core_Model_Session $session, - Mage_Core_Model_Store_Config $storeConfig, - Mage_Core_Controller_Varien_Front $frontController, - Mage_Core_Model_Factory_Helper $helperFactory, - Magento_Filesystem $filesystem, - array $data = array() - ) { - parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data - ); - } -} diff --git a/app/code/core/Mage/Adminhtml/Block/Html/Select.php b/app/code/core/Mage/Adminhtml/Block/Html/Select.php deleted file mode 100644 index 7f41c1c581d..00000000000 --- a/app/code/core/Mage/Adminhtml/Block/Html/Select.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Mage - * @package Mage_Adminhtml - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -/** - * Adminhtml HTML select element block - * - * @category Mage - * @package Mage_Core - * @author Magento Core Team <core@magentocommerce.com> - */ -class Mage_Adminhtml_Block_Html_Select extends Mage_Core_Block_Html_Select -{ - /** - * @param Mage_Core_Controller_Request_Http $request - * @param Mage_Core_Model_Layout $layout - * @param Mage_Core_Model_Event_Manager $eventManager - * @param Mage_Backend_Model_Url $urlBuilder - * @param Mage_Core_Model_Translate $translator - * @param Mage_Core_Model_Cache $cache - * @param Mage_Core_Model_Design_Package $designPackage - * @param Mage_Core_Model_Session $session - * @param Mage_Core_Model_Store_Config $storeConfig - * @param Mage_Core_Controller_Varien_Front $frontController - * @param Mage_Core_Model_Factory_Helper $helperFactory - * @param array $data - * - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - */ - public function __construct( - Mage_Core_Controller_Request_Http $request, - Mage_Core_Model_Layout $layout, - Mage_Core_Model_Event_Manager $eventManager, - Mage_Backend_Model_Url $urlBuilder, - Mage_Core_Model_Translate $translator, - Mage_Core_Model_Cache $cache, - Mage_Core_Model_Design_Package $designPackage, - Mage_Core_Model_Session $session, - Mage_Core_Model_Store_Config $storeConfig, - Mage_Core_Controller_Varien_Front $frontController, - Mage_Core_Model_Factory_Helper $helperFactory, - array $data = array() - ) { - parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $data - ); - } -} diff --git a/app/code/core/Mage/Adminhtml/Block/Messages.php b/app/code/core/Mage/Adminhtml/Block/Messages.php deleted file mode 100644 index 84d07a3a1da..00000000000 --- a/app/code/core/Mage/Adminhtml/Block/Messages.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Mage - * @package Mage_Adminhtml - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - - -/** - * Adminhtml messages block - * - * @category Mage - * @package Mage_Adminhtml - * @author Magento Core Team <core@magentocommerce.com> - */ -class Mage_Adminhtml_Block_Messages extends Mage_Core_Block_Messages -{ - /** - * @param Mage_Core_Controller_Request_Http $request - * @param Mage_Core_Model_Layout $layout - * @param Mage_Core_Model_Event_Manager $eventManager - * @param Mage_Backend_Model_Url $urlBuilder - * @param Mage_Core_Model_Translate $translator - * @param Mage_Core_Model_Cache $cache - * @param Mage_Core_Model_Design_Package $designPackage - * @param Mage_Core_Model_Session $session - * @param Mage_Core_Model_Store_Config $storeConfig - * @param Mage_Core_Controller_Varien_Front $frontController - * @param Mage_Core_Model_Factory_Helper $helperFactory - * @param Magento_Filesystem $filesystem - * @param array $data - * - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - */ - public function __construct( - Mage_Core_Controller_Request_Http $request, - Mage_Core_Model_Layout $layout, - Mage_Core_Model_Event_Manager $eventManager, - Mage_Backend_Model_Url $urlBuilder, - Mage_Core_Model_Translate $translator, - Mage_Core_Model_Cache $cache, - Mage_Core_Model_Design_Package $designPackage, - Mage_Core_Model_Session $session, - Mage_Core_Model_Store_Config $storeConfig, - Mage_Core_Controller_Varien_Front $frontController, - Mage_Core_Model_Factory_Helper $helperFactory, - Magento_Filesystem $filesystem, - array $data = array() - ) { - parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); - } -} diff --git a/app/code/core/Mage/Adminhtml/Block/Notification/Baseurl.php b/app/code/core/Mage/Adminhtml/Block/Notification/Baseurl.php index db427839100..c220ca7c681 100644 --- a/app/code/core/Mage/Adminhtml/Block/Notification/Baseurl.php +++ b/app/code/core/Mage/Adminhtml/Block/Notification/Baseurl.php @@ -36,13 +36,15 @@ class Mage_Adminhtml_Block_Notification_Baseurl extends Mage_Adminhtml_Block_Tem $defaultUnsecure= (string) Mage::getConfig()->getNode('default/'.Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL); $defaultSecure = (string) Mage::getConfig()->getNode('default/'.Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL); - if ($defaultSecure == '{{base_url}}' || $defaultUnsecure == '{{base_url}}') { + if ($defaultSecure == Mage_Core_Model_Store::BASE_URL_PLACEHOLDER + || $defaultUnsecure == Mage_Core_Model_Store::BASE_URL_PLACEHOLDER + ) { return $this->getUrl('adminhtml/system_config/edit', array('section'=>'web')); } $configData = Mage::getModel('Mage_Core_Model_Config_Data'); $dataCollection = $configData->getCollection() - ->addValueFilter('{{base_url}}'); + ->addValueFilter(Mage_Core_Model_Store::BASE_URL_PLACEHOLDER); $url = false; foreach ($dataCollection as $data) { diff --git a/app/code/core/Mage/Adminhtml/Block/Page/Footer.php b/app/code/core/Mage/Adminhtml/Block/Page/Footer.php index e478fdffe24..7005c3ddbbc 100644 --- a/app/code/core/Mage/Adminhtml/Block/Page/Footer.php +++ b/app/code/core/Mage/Adminhtml/Block/Page/Footer.php @@ -67,7 +67,7 @@ class Mage_Adminhtml_Block_Page_Footer extends Mage_Adminhtml_Block_Template $html = Mage::app()->loadCache($cacheId); if (!$html) { - $html = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $html = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setName('locale') ->setId('interface_locale') ->setTitle(Mage::helper('Mage_Page_Helper_Data')->__('Interface Language')) diff --git a/app/code/core/Mage/Adminhtml/Block/Page/Head.php b/app/code/core/Mage/Adminhtml/Block/Page/Head.php index 2ea53cbc569..547514f11c1 100644 --- a/app/code/core/Mage/Adminhtml/Block/Page/Head.php +++ b/app/code/core/Mage/Adminhtml/Block/Page/Head.php @@ -47,6 +47,8 @@ class Mage_Adminhtml_Block_Page_Head extends Mage_Page_Block_Html_Head * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param array $data * @@ -64,11 +66,13 @@ class Mage_Adminhtml_Block_Page_Head extends Mage_Page_Block_Html_Head Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); } diff --git a/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Labels.php b/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Labels.php index 06288f4a741..2b3c08e6335 100644 --- a/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Labels.php +++ b/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Labels.php @@ -36,6 +36,8 @@ class Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Labels protected $_app; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -47,6 +49,8 @@ class Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Labels * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $app * @param array $data @@ -65,13 +69,15 @@ class Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Labels Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_App $app, array $data = array() ) { $this->_app = $app; parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); } diff --git a/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Main/Renderer/Checkbox.php b/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Main/Renderer/Checkbox.php index 9066114ea7e..8e103aeca0c 100644 --- a/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Main/Renderer/Checkbox.php +++ b/app/code/core/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/Main/Renderer/Checkbox.php @@ -32,7 +32,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Main_Renderer_Checkbox - extends Mage_Adminhtml_Block_Abstract + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { /** diff --git a/app/code/core/Mage/Adminhtml/Block/Promo/Widget/Chooser/Daterange.php b/app/code/core/Mage/Adminhtml/Block/Promo/Widget/Chooser/Daterange.php index 3573522dc49..0030bce0a18 100644 --- a/app/code/core/Mage/Adminhtml/Block/Promo/Widget/Chooser/Daterange.php +++ b/app/code/core/Mage/Adminhtml/Block/Promo/Widget/Chooser/Daterange.php @@ -28,7 +28,7 @@ * Date range promo widget chooser * Currently works without localized format */ -class Mage_Adminhtml_Block_Promo_Widget_Chooser_Daterange extends Mage_Adminhtml_Block_Abstract +class Mage_Adminhtml_Block_Promo_Widget_Chooser_Daterange extends Mage_Core_Block_Template { /** * HTML ID of the element that will obtain the joined chosen values diff --git a/app/code/core/Mage/Adminhtml/Block/Rating/Edit/Tab/Form.php b/app/code/core/Mage/Adminhtml/Block/Rating/Edit/Tab/Form.php index b1305f78967..fc4d93df92d 100644 --- a/app/code/core/Mage/Adminhtml/Block/Rating/Edit/Tab/Form.php +++ b/app/code/core/Mage/Adminhtml/Block/Rating/Edit/Tab/Form.php @@ -42,6 +42,8 @@ class Mage_Adminhtml_Block_Rating_Edit_Tab_Form extends Mage_Backend_Block_Widge protected $_app; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -53,6 +55,8 @@ class Mage_Adminhtml_Block_Rating_Edit_Tab_Form extends Mage_Backend_Block_Widge * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $app * @param array $data @@ -71,13 +75,15 @@ class Mage_Adminhtml_Block_Rating_Edit_Tab_Form extends Mage_Backend_Block_Widge Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_App $app, array $data = array() ) { $this->_app = $app; parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); } diff --git a/app/code/core/Mage/Adminhtml/Block/Sales/Order/Create/Messages.php b/app/code/core/Mage/Adminhtml/Block/Sales/Order/Create/Messages.php index d650589a44f..034f003835a 100644 --- a/app/code/core/Mage/Adminhtml/Block/Sales/Order/Create/Messages.php +++ b/app/code/core/Mage/Adminhtml/Block/Sales/Order/Create/Messages.php @@ -31,7 +31,7 @@ * @package Mage_Adminhtml * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Adminhtml_Block_Sales_Order_Create_Messages extends Mage_Adminhtml_Block_Messages +class Mage_Adminhtml_Block_Sales_Order_Create_Messages extends Mage_Core_Block_Messages { public function _prepareLayout() diff --git a/app/code/core/Mage/Adminhtml/Block/Sales/Order/View/Messages.php b/app/code/core/Mage/Adminhtml/Block/Sales/Order/View/Messages.php index 649fbf39db9..4fad233aa85 100644 --- a/app/code/core/Mage/Adminhtml/Block/Sales/Order/View/Messages.php +++ b/app/code/core/Mage/Adminhtml/Block/Sales/Order/View/Messages.php @@ -31,7 +31,7 @@ * @package Mage_Adminhtml * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Adminhtml_Block_Sales_Order_View_Messages extends Mage_Adminhtml_Block_Messages +class Mage_Adminhtml_Block_Sales_Order_View_Messages extends Mage_Core_Block_Messages { protected function _getOrder() diff --git a/app/code/core/Mage/Adminhtml/Block/System/Currency/Rate/Services.php b/app/code/core/Mage/Adminhtml/Block/System/Currency/Rate/Services.php index d29e500b04c..f1e276eafe4 100644 --- a/app/code/core/Mage/Adminhtml/Block/System/Currency/Rate/Services.php +++ b/app/code/core/Mage/Adminhtml/Block/System/Currency/Rate/Services.php @@ -44,7 +44,7 @@ class Mage_Adminhtml_Block_System_Currency_Rate_Services extends Mage_Adminhtml_ protected function _prepareLayout() { $this->setChild('import_services', - $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setOptions(Mage::getModel('Mage_Backend_Model_Config_Source_Currency_Service')->toOptionArray(0)) ->setId('rate_services') ->setName('rate_services') diff --git a/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php b/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php index 1f6840ff299..2ada9fa34bf 100644 --- a/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php +++ b/app/code/core/Mage/Adminhtml/Block/System/Email/Template/Edit.php @@ -61,6 +61,8 @@ class Mage_Adminhtml_Block_System_Email_Template_Edit extends Mage_Adminhtml_Blo * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_Registry $registry * @param Mage_Backend_Model_Menu_Config $menuConfig @@ -81,6 +83,8 @@ class Mage_Adminhtml_Block_System_Email_Template_Edit extends Mage_Adminhtml_Blo Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_Registry $registry, Mage_Backend_Model_Menu_Config $menuConfig, @@ -89,7 +93,8 @@ class Mage_Adminhtml_Block_System_Email_Template_Edit extends Mage_Adminhtml_Blo ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, - $designPackage, $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $designPackage, $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); $this->_registryManager = $registry; $this->_menuConfig = $menuConfig; $this->_configStructure = $configStructure; diff --git a/app/code/core/Mage/Adminhtml/Model/Extension.php b/app/code/core/Mage/Adminhtml/Model/Extension.php deleted file mode 100644 index f28c0b5c32a..00000000000 --- a/app/code/core/Mage/Adminhtml/Model/Extension.php +++ /dev/null @@ -1,402 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Mage - * @package Mage_Adminhtml - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -class Mage_Adminhtml_Model_Extension extends Varien_Object -{ - protected $_roles; - - /** - * @var Magento_Filesystem - */ - protected $_filesystem; - - /** - * Constructor - * - * @param Magento_Filesystem $filesystem - * @param array $data - */ - public function __construct(Magento_Filesystem $filesystem, array $data = array()) - { - $this->_filesystem = $filesystem; - $this->_filesystem->setIsAllowCreateDirectories(true); - $this->_filesystem->setWorkingDirectory($this->getRoleDir('mage')); - parent::__construct($data); - } - - public function getPear() - { - return Varien_Pear::getInstance(); - } - - public function generatePackageXml() - { - Mage::getSingleton('Mage_Adminhtml_Model_Session') - ->setLocalExtensionPackageFormData($this->getData()); - - Varien_Pear::$reloadOnRegistryUpdate = false; - $pkg = new Varien_Pear_Package; - #$pkg->getPear()->runHtmlConsole(array('command'=>'list-channels')); - $pfm = $pkg->getPfm(); - $pfm->setOptions(array( - 'packagedirectory'=>'.', - 'baseinstalldir'=>'.', - 'simpleoutput'=>true, - )); - - $this->_setPackage($pfm); - $this->_setRelease($pfm); - $this->_setMaintainers($pfm); - $this->_setDependencies($pfm); - $this->_setContents($pfm); -#echo "<pre>".print_r($pfm,1)."</pre>"; - if (!$pfm->validate(PEAR_VALIDATE_NORMAL)) { - //echo "<pre>".print_r($this->getData(),1)."</pre>"; - //echo "TEST:"; - //echo "<pre>".print_r($pfm->getValidationWarnings(), 1)."</pre>"; - $message = $pfm->getValidationWarnings(); - //$message = $message[0]['message']; - throw Mage::exception('Mage_Adminhtml', Mage::helper('Mage_Adminhtml_Helper_Data')->__($message[0]['message'])); - - return $this; - } - - $this->setPackageXml($pfm->getDefaultGenerator()->toXml(PEAR_VALIDATE_NORMAL)); - return $this; - } - - protected function _setPackage($pfm) - { - $pfm->setPackageType('php'); - $pfm->setChannel($this->getData('channel')); - - $pfm->setLicense($this->getData('license'), $this->getData('license_uri')); - - $pfm->setPackage($this->getData('name')); - $pfm->setSummary($this->getData('summary')); - $pfm->setDescription($this->getData('description')); - } - - protected function _setRelease($pfm) - { - $pfm->addRelease(); - $pfm->setDate(date('Y-m-d')); - - $pfm->setAPIVersion($this->getData('api_version')); - $pfm->setReleaseVersion($this->getData('release_version')); - $pfm->setAPIStability($this->getData('api_stability')); - $pfm->setReleaseStability($this->getData('release_stability')); - $pfm->setNotes($this->getData('notes')); - } - - protected function _setMaintainers($pfm) - { - $maintainers = $this->getData('maintainers'); - foreach ($maintainers['role'] as $i=>$role) { - if (0===$i) { - continue; - } - $handle = $maintainers['handle'][$i]; - $name = $maintainers['name'][$i]; - $email = $maintainers['email'][$i]; - $active = !empty($maintainers['active'][$i]) ? 'yes' : 'no'; - $pfm->addMaintainer($role, $handle, $name, $email, $active); - } - } - - protected function _setDependencies($pfm) - { - $pfm->clearDeps(); - $exclude = $this->getData('depends_php_exclude')!=='' ? explode(',', $this->getData('depends_php_exclude')) : false; - $pfm->setPhpDep($this->getData('depends_php_min'), $this->getData('depends_php_max'), $exclude); - $pfm->setPearinstallerDep('1.6.2'); - - foreach ($this->getData('depends') as $deptype=>$deps) { - foreach ($deps['type'] as $i=>$type) { - if (0===$i) { - continue; - } - $name = $deps['name'][$i]; - $min = !empty($deps['min'][$i]) ? $deps['min'][$i] : false; - $max = !empty($deps['max'][$i]) ? $deps['max'][$i] : false; - $recommended = !empty($deps['recommended'][$i]) ? $deps['recommended'][$i] : false; - $exclude = !empty($deps['exclude'][$i]) ? explode(',', $deps['exclude'][$i]) : false; - if ($deptype!=='extension') { - $channel = !empty($deps['channel'][$i]) ? $deps['channel'][$i] : 'connect.magentocommerce.com/core'; - } - switch ($deptype) { - case 'package': - if ($type==='conflicts') { - $pfm->addConflictingPackageDepWithChannel( - $name, $channel, false, $min, $max, $recommended, $exclude); - } else { - $pfm->addPackageDepWithChannel( - $type, $name, $channel, $min, $max, $recommended, $exclude); - } - break; - - case 'subpackage': - if ($type==='conflicts') { - Mage::throwException(Mage::helper('Mage_Adminhtml_Helper_Data')->__("Subpackage cannot be conflicting.")); - } - $pfm->addSubpackageDepWithChannel( - $type, $name, $channel, $min, $max, $recommended, $exclude); - break; - - case 'extension': - $pfm->addExtensionDep( - $type, $name, $min, $max, $recommended, $exclude); - break; - } - } - } - } - - protected function _setContents($pfm) - { - $pfm->clearContents(); - $contents = $this->getData('contents'); - $usesRoles = array(); - foreach ($contents['role'] as $i=>$role) { - if (0===$i) { - continue; - } - - $usesRoles[$role] = 1; - - $roleDir = $this->getRoleDir($role).DS; - $fullPath = $roleDir.$contents['path'][$i]; - - switch ($contents['type'][$i]) { - case 'file': - if (!$this->_filesystem->isFile($fullPath)) { - Mage::throwException(Mage::helper('Mage_Adminhtml_Helper_Data')->__("Invalid file: %s", $fullPath)); - } - $pfm->addFile('/', $contents['path'][$i], - array('role' => $role, 'md5sum' => $this->_filesystem->getFileMd5($fullPath))); - break; - - case 'dir': - if (!$this->_filesystem->isDirectory($fullPath)) { - Mage::throwException(Mage::helper('Mage_Adminhtml_Helper_Data')->__("Invalid directory: %s", $fullPath)); - } - $path = $contents['path'][$i]; - $include = $contents['include'][$i]; - $ignore = $contents['ignore'][$i]; - $this->_addDir($pfm, $role, $roleDir, $path, $include, $ignore); - break; - } - } - - $pearRoles = $this->getRoles(); -#echo "<pre>".print_r($usesRoles,1)."</pre>"; - foreach ($usesRoles as $role=>$dummy) { - if (empty($pearRoles[$role]['package'])) { - continue; - } - $pfm->addUsesrole($role, $pearRoles[$role]['package']); - } - } - - protected function _addDir($pfm, $role, $roleDir, $path, $include, $ignore) - { - $roleDirLen = strlen($roleDir); - $entries = $this->_filesystem->getNestedKeys($roleDir . $path . DS); - if (!empty($entries)) { - foreach ($entries as $entry) { - $filePath = substr($entry, $roleDirLen); - if (!empty($include) && !preg_match($include, $filePath)) { - continue; - } - if (!empty($ignore) && preg_match($ignore, $filePath)) { - continue; - } - if ($this->_filesystem->isFile($entry)) { - $pfm->addFile('/', $filePath, - array('role' => $role, 'md5sum' => $this->_filesystem->getFileMd5($entry))); - } - } - } - } - - public function getRoles() - { - if (!$this->_roles) { - $frontend = $this->getPear()->getFrontend(); - $config = $this->getPear()->getConfig(); - $pearMage = new PEAR_Command_Mage($frontend, $config); - $this->_roles = $pearMage->getRoles(); - } - return $this->_roles; - } - - public function getRoleDir($role) - { - $roles = $this->getRoles(); - return Varien_Pear::getInstance()->getConfig()->get($roles[$role]['dir_config']); - } - - public function getMaintainerRoles() - { - return array( - 'lead'=>'Lead', - 'developer'=>'Developer', - 'contributor'=>'Contributor', - 'helper'=>'Helper' - ); - } - - public function savePackage() - { - if ($this->getData('file_name') != '') { - $fileName = $this->getData('file_name'); - $this->unsetData('file_name'); - } else { - $fileName = $this->getName(); - } - - if (!preg_match('/^[a-z0-9]+[a-z0-9\-\_\.]*([\/\\\\]{1}[a-z0-9]+[a-z0-9\-\_\.]*)*$/i', $fileName)) { - return false; - } - - if (!$this->getPackageXml()) { - $this->generatePackageXml(); - } - if (!$this->getPackageXml()) { - return false; - } - - $pear = Varien_Pear::getInstance(); - $dir = Mage::getBaseDir('var').DS.'pear'; - try { - $this->_filesystem->write($dir.DS.'package.xml', $this->getPackageXml()); - } catch (Magento_Filesystem_Exception $e) { - return false; - } - - $pkgver = $this->getName().'-'.$this->getReleaseVersion(); - $this->unsPackageXml(); - $this->unsRoles(); - $xml = Mage::helper('Mage_Core_Helper_Data')->assocToXml($this->getData()); - $xml = new Varien_Simplexml_Element($xml->asXML()); - - try { - $this->_filesystem->write($dir . DS . $fileName . '.xml', $xml->asNiceXml()); - } catch (Magento_Filesystem_Exception $e) { - return false; - } - - return true; - } - - public function createPackage() - { - $pear = Varien_Pear::getInstance(); - $dir = Mage::getBaseDir('var').DS.'pear'; - if (!Mage::getConfig()->createDirIfNotExists($dir)) { - return false; - } - $curDir = getcwd(); - chdir($dir); - $result = $pear->run('mage-package', array(), array('package.xml')); - chdir($curDir); - if ($result instanceof PEAR_Error) { - return $result; - } - return true; - } - - - public function getStabilityOptions() - { - return array( - 'devel'=>'Development', - 'alpha'=>'Alpha', - 'beta'=>'Beta', - 'stable'=>'Stable', - ); - } - - public function getKnownChannels() - { - /* - $pear = Varien_Pear::getInstance(); - $pear->run('list-channels'); - $output = $pear->getOutput(); - $pear->getFrontend()->clear(); - - $data = $output[0]['output']['data']; - $arr = array(); - foreach ($data as $channel) { - $arr[$channel[0]] = $channel[1].' ('.$channel[0].')'; - } - */ - $arr = array( - 'connect.magentocommerce.com/core' => 'Magento Core Team', - 'connect.magentocommerce.com/community' => 'Magento Community', - #'pear.php.net' => 'PEAR', - #'pear.phpunit.de' => 'PHPUnit', - ); - return $arr; - } - - public function loadLocal($package, $options=array()) - { - $pear = $this->getPear(); - - $pear->getFrontend()->clear(); - - $result = $pear->run('info', $options, array($package)); - if ($result instanceof PEAR_Error) { - Mage::throwException($result->message); - break; - } - - $output = $pear->getOutput(); - $pkg = new PEAR_PackageFile_v2; - $pkg->fromArray($output[0]['output']['raw']); - - return $pkg; - } - - public function loadRemote($package, $options=array()) - { - $pear = $this->getPear(); - - $pear->getFrontend()->clear(); - - $result = $pear->run('remote-info', $options, array($package)); - if ($result instanceof PEAR_Error) { - Mage::throwException($result->message); - break; - } - - $output = $pear->getOutput(); - $this->setData($output[0]['output']); - - return $this; - } -} diff --git a/app/code/core/Mage/Adminhtml/controllers/Api/RoleController.php b/app/code/core/Mage/Adminhtml/controllers/Api/RoleController.php new file mode 100644 index 00000000000..8b5823da1a9 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/controllers/Api/RoleController.php @@ -0,0 +1,217 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Adminhtml roles controller + * + * @category Mage + * @package Mage_Adminhtml + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Adminhtml_Api_RoleController extends Mage_Adminhtml_Controller_Action +{ + + protected function _initAction() + { + $this->loadLayout(); + $this->_setActiveMenu('Mage_Api::system_legacy_api_roles'); + $this->_addBreadcrumb($this->__('Web services'), $this->__('Web services')); + $this->_addBreadcrumb($this->__('Permissions'), $this->__('Permissions')); + $this->_addBreadcrumb($this->__('Roles'), $this->__('Roles')); + return $this; + } + + public function indexAction() + { + $this->_title($this->__('System')) + ->_title($this->__('Web Services')) + ->_title($this->__('Roles')); + + $this->_initAction(); + + $this->_addContent($this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_Roles')); + + $this->renderLayout(); + } + + public function roleGridAction() + { + $this->getResponse() + ->setBody($this->getLayout() + ->createBlock('Mage_Adminhtml_Block_Api_Grid_Role') + ->toHtml() + ); + } + + public function editRoleAction() + { + $this->_title($this->__('System')) + ->_title($this->__('Web Services')) + ->_title($this->__('Roles')); + + $this->_initAction(); + + $roleId = $this->getRequest()->getParam('rid'); + if( intval($roleId) > 0 ) { + $breadCrumb = $this->__('Edit Role'); + $breadCrumbTitle = $this->__('Edit Role'); + $this->_title($this->__('Edit Role')); + } else { + $breadCrumb = $this->__('Add New Role'); + $breadCrumbTitle = $this->__('Add New Role'); + $this->_title($this->__('New Role')); + } + $this->_addBreadcrumb($breadCrumb, $breadCrumbTitle); + + $this->getLayout()->getBlock('head')->setCanLoadExtJs(true); + + $this->_addLeft( + $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_Editroles') + ); + $resources = Mage::getModel('Mage_Api_Model_Roles')->getResourcesList(); + $this->_addContent( + $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_Buttons') + ->setRoleId($roleId) + ->setRoleInfo(Mage::getModel('Mage_Api_Model_Roles')->load($roleId)) + ->setTemplate('api/roleinfo.phtml') + ); + $this->_addJs( + $this->getLayout() + ->createBlock('Mage_Adminhtml_Block_Template') + ->setTemplate('api/role_users_grid_js.phtml') + ); + $this->renderLayout(); + } + + public function deleteAction() + { + $rid = $this->getRequest()->getParam('rid', false); + + try { + Mage::getModel('Mage_Api_Model_Roles')->load($rid)->delete(); + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess($this->__('The role has been deleted.')); + } catch (Exception $e) { + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('An error occurred while deleting this role.')); + } + + $this->_redirect("*/*/"); + } + + public function saveRoleAction() + { + + $rid = $this->getRequest()->getParam('role_id', false); + $role = Mage::getModel('Mage_Api_Model_Roles')->load($rid); + if (!$role->getId() && $rid) { + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('This Role no longer exists')); + $this->_redirect('*/*/'); + return; + } + + $resource = explode(',', $this->getRequest()->getParam('resource', false)); + $roleUsers = $this->getRequest()->getParam('in_role_user', null); + parse_str($roleUsers, $roleUsers); + $roleUsers = array_keys($roleUsers); + + $oldRoleUsers = $this->getRequest()->getParam('in_role_user_old'); + parse_str($oldRoleUsers, $oldRoleUsers); + $oldRoleUsers = array_keys($oldRoleUsers); + + $isAll = $this->getRequest()->getParam('all'); + if ($isAll) { + $resource = array("all"); + } + + try { + $role = $role + ->setName($this->getRequest()->getParam('rolename', false)) + ->setPid($this->getRequest()->getParam('parent_id', false)) + ->setRoleType('G') + ->save(); + + Mage::getModel('Mage_Api_Model_Rules') + ->setRoleId($role->getId()) + ->setResources($resource) + ->saveRel(); + + foreach($oldRoleUsers as $oUid) { + $this->_deleteUserFromRole($oUid, $role->getId()); + } + + foreach ($roleUsers as $nRuid) { + $this->_addUserToRole($nRuid, $role->getId()); + } + + $rid = $role->getId(); + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess($this->__('The role has been saved.')); + } catch (Exception $e) { + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('An error occurred while saving this role.')); + } + + //$this->getResponse()->setRedirect($this->getUrl("*/*/editrole/rid/$rid")); + $this->_redirect('*/*/editrole', array('rid' => $rid)); + return; + } + + public function editrolegridAction() + { + $this->getResponse()->setBody( + $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_Role_Grid_User')->toHtml() + ); + } + + protected function _deleteUserFromRole($userId, $roleId) + { + try { + Mage::getModel('Mage_Api_Model_User') + ->setRoleId($roleId) + ->setUserId($userId) + ->deleteFromRole(); + } catch (Exception $e) { + throw $e; + return false; + } + return true; + } + + protected function _addUserToRole($userId, $roleId) + { + $user = Mage::getModel('Mage_Api_Model_User')->load($userId); + $user->setRoleId($roleId)->setUserId($userId); + + if( $user->roleUserExists() === true ) { + return false; + } else { + $user->add(); + return true; + } + } + + protected function _isAllowed() + { + return Mage::getSingleton('Mage_Core_Model_Authorization')->isAllowed('Mage_Api::roles'); + } +} diff --git a/app/code/core/Mage/Adminhtml/controllers/Api/UserController.php b/app/code/core/Mage/Adminhtml/controllers/Api/UserController.php new file mode 100644 index 00000000000..8c06e6269a9 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/controllers/Api/UserController.php @@ -0,0 +1,190 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Adminhtml + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Adminhtml_Api_UserController extends Mage_Adminhtml_Controller_Action +{ + + protected function _initAction() + { + $this->loadLayout() + ->_setActiveMenu('Mage_Api::system_legacy_api_users') + ->_addBreadcrumb($this->__('Web Services'), $this->__('Web Services')) + ->_addBreadcrumb($this->__('Permissions'), $this->__('Permissions')) + ->_addBreadcrumb($this->__('Users'), $this->__('Users')) + ; + return $this; + } + + public function indexAction() + { + $this->_title($this->__('System')) + ->_title($this->__('Web Services')) + ->_title($this->__('Users')); + + $this->_initAction() + ->_addContent($this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_User')) + ->renderLayout(); + } + + public function newAction() + { + $this->_forward('edit'); + } + + public function editAction() + { + $this->_title($this->__('System')) + ->_title($this->__('Web Services')) + ->_title($this->__('Users')); + + $id = $this->getRequest()->getParam('user_id'); + $model = Mage::getModel('Mage_Api_Model_User'); + + if ($id) { + $model->load($id); + if (! $model->getId()) { + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('This user no longer exists.')); + $this->_redirect('*/*/'); + return; + } + } + + $this->_title($model->getId() ? $model->getName() : $this->__('New User')); + + // Restore previously entered form data from session + $data = Mage::getSingleton('Mage_Adminhtml_Model_Session')->getUserData(true); + if (!empty($data)) { + $model->setData($data); + } + + Mage::register('api_user', $model); + + $this->_initAction() + ->_addBreadcrumb($id ? $this->__('Edit User') : $this->__('New User'), $id ? $this->__('Edit User') : $this->__('New User')) + ->_addContent($this->getLayout() + ->createBlock('Mage_Adminhtml_Block_Api_User_Edit') + ->setData('action', $this->getUrl('*/api_user/save'))) + ->_addLeft($this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_User_Edit_Tabs')); + + $this->_addJs($this->getLayout() + ->createBlock('Mage_Adminhtml_Block_Template') + ->setTemplate('api/user_roles_grid_js.phtml') + ); + $this->renderLayout(); + } + + public function saveAction() + { + if ($data = $this->getRequest()->getPost()) { + $id = $this->getRequest()->getPost('user_id', false); + $model = Mage::getModel('Mage_Api_Model_User')->load($id); + if (!$model->getId() && $id) { + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('This user no longer exists.')); + $this->_redirect('*/*/'); + return; + } + $model->setData($data); + try { + $model->save(); + if ( $uRoles = $this->getRequest()->getParam('roles', false) ) { + /*parse_str($uRoles, $uRoles); + $uRoles = array_keys($uRoles);*/ + if ( 1 == sizeof($uRoles) ) { + $model->setRoleIds($uRoles) + ->setRoleUserId($model->getUserId()) + ->saveRelations(); + } else if ( sizeof($uRoles) > 1 ) { + //@FIXME: stupid fix of previous multi-roles logic. + //@TODO: make proper DB upgrade in the future revisions. + $rs = array(); + $rs[0] = $uRoles[0]; + $model->setRoleIds( $rs )->setRoleUserId( $model->getUserId() )->saveRelations(); + } + } + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess($this->__('The user has been saved.')); + Mage::getSingleton('Mage_Adminhtml_Model_Session')->setUserData(false); + $this->_redirect('*/*/edit', array('user_id' => $model->getUserId())); + return; + } catch (Exception $e) { + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage()); + Mage::getSingleton('Mage_Adminhtml_Model_Session')->setUserData($data); + $this->_redirect('*/*/edit', array('user_id' => $model->getUserId())); + return; + } + } + $this->_redirect('*/*/'); + } + + public function deleteAction() + { + if ($id = $this->getRequest()->getParam('user_id')) { + + try { + $model = Mage::getModel('Mage_Api_Model_User')->load($id); + $model->delete(); + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addSuccess($this->__('The user has been deleted.')); + $this->_redirect('*/*/'); + return; + } + catch (Exception $e) { + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($e->getMessage()); + $this->_redirect('*/*/edit', array('user_id' => $this->getRequest()->getParam('user_id'))); + return; + } + } + Mage::getSingleton('Mage_Adminhtml_Model_Session')->addError($this->__('Unable to find a user to delete.')); + $this->_redirect('*/*/'); + } + + public function rolesGridAction() + { + $id = $this->getRequest()->getParam('user_id'); + $model = Mage::getModel('Mage_Api_Model_User'); + + if ($id) { + $model->load($id); + } + + Mage::register('api_user', $model); + $this->getResponse()->setBody( + $this->getLayout()->createBlock('Mage_Adminhtml_Block_Api_User_Edit_Tab_Roles')->toHtml() + ); + } + + public function roleGridAction() + { + $this->getResponse() + ->setBody($this->getLayout() + ->createBlock('Mage_Adminhtml_Block_Api_User_Grid') + ->toHtml() + ); + } + + protected function _isAllowed() + { + return Mage::getSingleton('Mage_Core_Model_Authorization')->isAllowed('Mage_Api::users'); + } + +} diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php index 52548bc6ee6..fa08d7763b7 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php @@ -444,27 +444,21 @@ class Mage_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Controller } /** - * Get associated grouped products grid and serializer block + * Get associated grouped products grid */ public function superGroupAction() { - $this->_initProduct(); - $this->loadLayout(); - $this->getLayout()->getBlock('catalog.product.edit.tab.super.group') - ->setProductsGrouped($this->getRequest()->getPost('products_grouped', null)); + $this->loadLayout(false); $this->renderLayout(); } /** - * Get associated grouped products grid only - * + * Get associated grouped products grid popup */ - public function superGroupGridOnlyAction() + public function superGroupPopupAction() { $this->_initProduct(); - $this->loadLayout(); - $this->getLayout()->getBlock('catalog.product.edit.tab.super.group') - ->setProductsGrouped($this->getRequest()->getPost('products_grouped', null)); + $this->loadLayout(false); $this->renderLayout(); } @@ -693,7 +687,7 @@ class Mage_Adminhtml_Catalog_ProductController extends Mage_Adminhtml_Controller } if (isset($links['grouped']) && !$product->getGroupedReadonly()) { $product->setGroupedLinkData( - Mage::helper('Mage_Adminhtml_Helper_Js')->decodeGridSerializedInput($links['grouped']) + Mage::helper('Mage_Core_Helper_Data')->jsonDecode($links['grouped']) ); } diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/api/role_users_grid_js.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/role_users_grid_js.phtml new file mode 100644 index 00000000000..11fb8f6d2b0 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/role_users_grid_js.phtml @@ -0,0 +1,105 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category design + * @package default_default + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +?> +<script type="text/javascript"> +<!-- +<?php $myBlock = $this->getLayout()->getBlock('roleUsersGrid'); ?> +<?php if( is_object($myBlock) && $myBlock->getJsObjectName() ): ?> + var checkBoxes = $H({}); + var warning = false; + var inRoleUsers = $H(<?php echo $myBlock->_getUsers(true) ?>); + if (inRoleUsers.size() > 0) warning = true; + $('in_role_user').value = inRoleUsers.toQueryString(); + + function registerUserRole(grid, element, checked){ + if(checked){ + inRoleUsers.set(element.value, 0); + } else { + inRoleUsers.unset(element.value); + } + $('in_role_user').value = inRoleUsers.toQueryString(); + grid.reloadParams = {'in_role_user[]':inRoleUsers.keys()}; + } + + function roleUsersRowClick(grid, event){ + var trElement = Event.findElement(event, 'tr'); + var isInput = Event.element(event).tagName == 'INPUT'; + if(trElement){ + var checkbox = Element.getElementsBySelector(trElement, 'input'); + if(checkbox[0]){ + var checked = isInput ? checkbox[0].checked : !checkbox[0].checked; + if (warning && checkBoxes.size() > 0) { + if ( !confirm("<?php echo $this->__('Warning!\r\nThis action will remove this user from already assigned role\r\nAre you sure?') ?>") ) { + checkbox[0].checked = false; + checkBoxes.each(function(elem) { + if (elem.value.status == 1) { + elem.value.object.checked = true; + } + }); + return false; + } + warning = false; + } + <?php echo $myBlock->getJsObjectName() ?>.setCheckboxChecked(checkbox[0], checked); + } + } + } + + function roleUsersRowInit(grid, row){ + var checkbox = $(row).getElementsByClassName('checkbox')[0]; + if (checkbox) { + checkBoxes.set(checkbox.value, {'status' : ((checkbox.checked) ? 1 : 0), 'object' : checkbox}); + } + } + + function myhandler(obj) + { + if (checkBoxes.size() > 0) { + if ( !confirm("<?php echo $this->__('Warning!\r\nThis action will remove those users from already assigned roles\r\nAre you sure?') ?>") ) { + obj.checked = false; + checkBoxes.each(function(elem) { + if (elem.value.status == 1) { + elem.value.object.checked = true; + } + }); + return false; + } + warning = false; + } + checkBoxes.each(function(elem) { + <?php echo $myBlock->getJsObjectName() ?>.setCheckboxChecked(elem.value.object, obj.checked); + }); + } + +<?php echo $myBlock->getJsObjectName() ?>.rowClickCallback = roleUsersRowClick; +<?php echo $myBlock->getJsObjectName() ?>.initRowCallback = roleUsersRowInit; +<?php echo $myBlock->getJsObjectName() ?>.checkboxCheckCallback = registerUserRole; +<?php echo $myBlock->getJsObjectName() ?>.checkCheckboxes = myhandler; +<?php echo $myBlock->getJsObjectName() ?>.rows.each(function(row){roleUsersRowInit(<?php echo $myBlock->getJsObjectName() ?>, row)}); + $('in_role_user_old').value = $('in_role_user').value; +<?php endif; ?> +//--> +</script> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/api/roleinfo.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/roleinfo.phtml new file mode 100644 index 00000000000..1d64e04c554 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/roleinfo.phtml @@ -0,0 +1,47 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category design + * @package default_default + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +/** @var $this Mage_Adminhtml_Block_Api_Tab_Roleinfo */ + +?> +<div class="content-header"> + <table cellspacing="0"> + <tr> + <td style="width:50%;"><h3 class="icon-head head-permissions-role"><?php echo ($this->getRoleId() > 0 ) ? ($this->__('Edit Role') . " '{$this->escapeHtml($this->getRoleInfo()->getRoleName())}'") : $this->__('Add New Role') ?></h3></td> + <td class="form-buttons"> + <?php echo $this->getBackButtonHtml() ?> + <?php echo $this->getResetButtonHtml() ?> + <?php echo $this->getDeleteButtonHtml() ?> + <?php echo $this->getSaveButtonHtml() ?> + </td> + </tr> + </table> +</div> +<form action="<?php echo $this->getUrl('*/*/saverole') ?>" method="post" id="role-edit-form"> + <?php echo $this->getBlockHtml('formkey')?> +</form> +<script type="text/javascript"> + jQuery('#role-edit-form').form().validation(); +</script> diff --git a/dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/theme.xml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/roles.phtml similarity index 61% rename from dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/theme.xml rename to app/code/core/Mage/Adminhtml/view/adminhtml/api/roles.phtml index 454f1534ae8..422ad419ad8 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/theme.xml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/roles.phtml @@ -1,4 +1,4 @@ -<!-- +<?php /** * Magento * @@ -18,21 +18,20 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Magento - * @package Design - * @subpackage integration_tests + * @category design + * @package default_default * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ---> -<design> - <package code="default"> - <title>Default</title> - <theme version="2.0.0.0" code="demo"> - <title>Default</title> - <requirements> - <magento_version from="2.0.0.0-dev1" to="*"/> - </requirements> - </theme> - </package> -</design> +?> +<div class="content-header"> + <table cellspacing="0"> + <tr> + <td style="width:50%;"><h3 class="icon-head head-permissions-role"><?php echo $this->__('Roles') ?></h3></td> + <td class="form-buttons"> + <button class="scalable add" onclick="window.location='<?php echo $this->getAddNewUrl() ?>'"><span><span><span><?php echo $this->__('Add New Role') ?></span></span></span></button> + </td> + </tr> + </table> +</div> +<?php echo $this->getGridHtml() ?> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesedit.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesedit.phtml new file mode 100644 index 00000000000..03cc092e539 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesedit.phtml @@ -0,0 +1,143 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category design + * @package default_default + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +?> +<div class="entry-edit"> + <div class="entry-edit-head"> + <h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('Roles Resources') ?></h4> + </div> + <input type="hidden" name="resource" id="role_resources" value=""> + <fieldset id="role_resources"> + + <span class="field-row"> + <label for="all"><?php echo $this->__('Resource Access') ?></label> + <select id="all" name="all" onchange="$('resources_container').toggle()" class="select"> + <option value="0" <?php echo ($this->getEverythingAllowed()?'':'selected="selected"'); ?>><?php echo $this->__('Custom') ?></option> + <option value="1" <?php echo ($this->getEverythingAllowed()?'selected="selected"':''); ?>><?php echo $this->__('All') ?></option> + </select> + </span> + + <span class="field-row" id="resources_container"> + <label><?php echo $this->__('Resources') ?></label> + <div class="f-left"> + <div class="tree x-tree" id="resource-tree"></div> + </div> + </span> + + </fieldset> +</div> +<!-- Draw Resources Tree --> +<script type="text/javascript"> +<?php if($this->getEverythingAllowed()): ?> + $('resources_container').hide(); +<?php endif; ?> +Ext.EventManager.onDocumentReady(function() { + var tree = new Ext.tree.TreePanel('resource-tree', { + animate:false, + loader: false, + enableDD:false, + containerScroll: true, + rootUIProvider: Ext.tree.CheckboxNodeUI, + selModel: new Ext.tree.CheckNodeMultiSelectionModel(), + rootVisible: false + }); + + tree.on('check', checkHandler, tree); + + // set the root node + var root = new Ext.tree.TreeNode({ + text: 'root', + draggable:false, + checked:'false', + id:'__root__', + uiProvider: Ext.tree.CheckboxNodeUI + }); + + tree.setRootNode(root); + bildResourcesTree(root, <?php echo $this->getResTreeJson() ?>); + tree.addListener('click', resourceClick.createDelegate(this)); + + // render the tree + tree.render(); + // root.expand(); + tree.expandAll(); + + $('role_resources').value = tree.getChecked().join(','); +}); + +function resourceClick(node, e){ + node.getUI().check(!node.getUI().checked()); + varienElementMethods.setHasChanges(Event.element(e), e); +}; + +function bildResourcesTree(parent, config){ + if (!config) return null; + + if (parent && config && config.length){ + for (var i = 0; i < config.length; i++){ + config[i].uiProvider = Ext.tree.CheckboxNodeUI; + var node = new Ext.tree.TreeNode(config[i]); + parent.appendChild(node); + if(config[i].children){ + bildResourcesTree(node, config[i].children); + } + } + } +} + +function checkHandler(node) +{ + if ( node.attributes.checked && node.parentNode ) { + var n = node.parentNode; + this.removeListener('check', checkHandler); + do { + if (!n || n.attributes.id == 'admin' || n.attributes.id == '__root__') { + break; + } else { + n.ui.check(true); + } + } while (n = n.parentNode ); + this.on('check', checkHandler); + } + if ( !node.isLeaf() && node.hasChildNodes() ) { + this.removeListener('check', checkHandler); + processChildren(node, node.attributes.checked); + this.on('check', checkHandler); + } + $('role_resources').value = this.getChecked().join(','); +} + +function processChildren(node, state) +{ + if ( !node.hasChildNodes() ) return false; + for(var i = 0; i < node.childNodes.length; i++ ) { + node.childNodes[i].ui.check(state); + if ( node.childNodes[i].hasChildNodes() ) { + processChildren(node.childNodes[i], state); + } + } + return true; +} +</script> diff --git a/dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/Mage_Core/dummy.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesusers.phtml similarity index 83% rename from dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/Mage_Core/dummy.phtml rename to app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesusers.phtml index d66d2b3fc0e..38fd74195f7 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Block/_files/frontend/default/demo/Mage_Core/dummy.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/rolesusers.phtml @@ -18,11 +18,11 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Magento - * @package Mage_Core - * @subpackage integration_tests + * @category design + * @package default_default * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -<?php echo '1234567890' ?> +<h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('Role Users') ?></h4> +<?php echo $this->_getGridHtml() ?> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/api/user_roles_grid_js.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/user_roles_grid_js.phtml new file mode 100644 index 00000000000..a632e48c7bf --- /dev/null +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/user_roles_grid_js.phtml @@ -0,0 +1,85 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category design + * @package default_default + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +?> +<script type="text/javascript"> +<!-- +<?php $myBlock = $this->getLayout()->getBlock('user.roles.grid'); ?> +<?php if( is_object($myBlock) && $myBlock->getJsObjectName()): ?> + var radioBoxes = $H({}); + var warning = false; + var userRoles = $H(<?php echo $myBlock->_getSelectedRoles(true) ?>); + if (userRoles.size() > 0) warning = true; + $('user_user_roles').value = userRoles.toQueryString(); + + function registerUserRole(grid, element, checked){ + if(checked){ + userRoles.each(function(o){userRoles.remove(o[0]);}); + userRoles[element.value] = 0; + } else { + userRoles.remove(element.value); + } + $('user_user_roles').value = userRoles.toQueryString(); + grid.reloadParams = {'user_roles[]':userRoles.keys()}; + } + + function roleRowClick(grid, event){ + var trElement = Event.findElement(event, 'tr'); + var isInput = Event.element(event).tagName == 'INPUT'; + if(trElement){ + var checkbox = Element.getElementsBySelector(trElement, 'input'); + if(checkbox[0] && !checkbox[0].checked){ + var checked = isInput ? checkbox[0].checked : !checkbox[0].checked; + if (checked && warning && radioBoxes.size() > 0) { + if ( !confirm("<?php echo $this->__('Warning!\r\nThis action will remove this user from already assigned role\r\nAre you sure?') ?>") ) { + checkbox[0].checked = false; + for(i in radioBoxes) { + if( radioBoxes[i].status == 1) { + radioBoxes[i].object.checked = true; + } + } + return false; + } + warning = false; + } + <?php echo $myBlock->getJsObjectName() ?>.setCheckboxChecked(checkbox[0], checked); + } + } + } + + function rolesRowInit(grid, row){ + var checkbox = $(row).getElementsByClassName('radio')[0]; + if (checkbox) { + radioBoxes[checkbox.value] = {'status' : ((checkbox.checked) ? 1 : 0), 'object' : checkbox}; + } + } + +<?php echo $myBlock->getJsObjectName() ?>.rowClickCallback = roleRowClick; +<?php echo $myBlock->getJsObjectName() ?>.initRowCallback = rolesRowInit; +<?php echo $myBlock->getJsObjectName() ?>.checkboxCheckCallback = registerUserRole; +<?php echo $myBlock->getJsObjectName() ?>.rows.each(function(row){rolesRowInit(<?php echo $myBlock->getJsObjectName() ?>, row)}); +<?php endif; ?> +//--> +</script> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/api/userinfo.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/userinfo.phtml new file mode 100644 index 00000000000..d1cafe10be5 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/userinfo.phtml @@ -0,0 +1,52 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category design + * @package default_default + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +?> +<div class="content-header"> + <table cellspacing="0"> + <tr> + <td style="width:50%;"> + <h3> + <?php if($this->getUser()->getUserId()): ?> + <?php $_userName = $this->getUser()->getFirstname() . ' ' . $this->getUser()->getLastname() ?> + <?php echo $this->__("Edit User '%s'", $_userName) ?> + <?php else: ?> + <?php echo $this->__('Add New User') ?> + <?php endif; ?> + </h3> + </td> + <td class="form-buttons"> + <?php echo $this->getBackButtonHtml() ?> + <?php echo $this->getResetButtonHtml() ?> + <?php echo $this->getDeleteButtonHtml() ?> + <?php echo $this->getSaveButtonHtml() ?> + </table> +</div> +<form action="<?php echo $this->getUrl('*/*/saveuser') ?>" method="post" id="user-edit-form"> + <?php echo $this->getBlockHtml('formkey')?> +</form> +<script type="text/javascript"> + jQuery('#user-edit-form').form().validation(); +</script> diff --git a/dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/Mage_Core/dummy.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/api/usernroles.phtml similarity index 72% rename from dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/Mage_Core/dummy.phtml rename to app/code/core/Mage/Adminhtml/view/adminhtml/api/usernroles.phtml index d66d2b3fc0e..ede0536cc52 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/Mage_Core/dummy.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/api/usernroles.phtml @@ -18,11 +18,14 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Magento - * @package Mage_Core - * @subpackage integration_tests + * @category design + * @package default_default * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -<?php echo '1234567890' ?> +<div id="roles"> + <li class="add"><a href="<?php echo $this->getUrl('*/*/edituser') ?>"><?php echo $this->__('Add New User') ?></a></li> + <li class="add"><a href="<?php echo $this->getUrl('*/*/editroles') ?>"><?php echo $this->__('Add New Role') ?></a></li> +</div> +<div class="clear"></div> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml index ea6d1a69908..341c97801ef 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog.xml @@ -52,6 +52,12 @@ <action method="addJs"><file>Mage_Adminhtml::jquery/fileUploader/jquery.fileupload-fp.js</file></action> <action method="addCss"><file>Mage_Adminhtml::catalog/category-selector.css</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/category-selector.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::json2.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::mage/backend/suggest.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::mage/backend/multisuggest.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::jquery/jstree/jquery.hotkeys.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::jquery/jstree/jquery.jstree.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::mage/backend/tree-suggest.js</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/type-switcher.js</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/product-variation.js</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/base-image-uploader.js</file></action> @@ -100,6 +106,12 @@ <action method="addJs"><file>Mage_Adminhtml::jquery/fileUploader/jquery.fileupload-fp.js</file></action> <action method="addCss"><file>Mage_Adminhtml::catalog/category-selector.css</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/category-selector.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::json2.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::mage/backend/suggest.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::mage/backend/multisuggest.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::jquery/jstree/jquery.hotkeys.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::jquery/jstree/jquery.jstree.js</file></action> + <action method="addJs"><file>Mage_Adminhtml::mage/backend/tree-suggest.js</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/type-switcher.js</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/product-variation.js</file></action> <action method="addJs"><file>Mage_Adminhtml::catalog/base-image-uploader.js</file></action> @@ -377,36 +389,186 @@ Layout handle for virtual products Layout handle for grouped products --> <adminhtml_catalog_product_grouped> - <reference name="product_tabs"> - <action method="addTab"><name>super</name><block>Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Group</block></action> + <update handle="adminhtml_catalog_product_grouped_grid"/> + <update handle="adminhtml_catalog_product_grouped_grid_popup"/> + <reference name="product-type-tabs"> + <block type="Mage_Catalog_Block_Product_Grouped_AssociatedProducts" name="catalog.product.edit.grouped.container" template="Mage_Catalog::product/grouped/container.phtml"> + <block type="Mage_Core_Block_Template" name="catalog.product.edit.tab.super.container" template="Mage_Catalog::product/grouped/grouped.phtml"> + <block type="Mage_Core_Block_Template" name="catalog.product.edit.tab.super.grid.container" as="catalog.product.group.grid.container"/> + <block type="Mage_Core_Block_Template" name="catalog.product.edit.tab.super.grid.popup.container" as="catalog.product.group.grid.popup.container"/> + </block> + </block> </reference> </adminhtml_catalog_product_grouped> - <adminhtml_catalog_product_supergroup> - <container name="root" label="Root" output="1"> - <block type="Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Group" name="catalog.product.edit.tab.super.group" /> - <block type="Mage_Adminhtml_Block_Widget_Grid_Serializer" name="grouped_grid_serializer"> - <reference name="grouped_grid_serializer"> - <action method="initSerializerBlock"> - <grid_block_name>catalog.product.edit.tab.super.group</grid_block_name> - <data_callback>getSelectedGroupedProducts</data_callback> - <hidden_input_name>links[grouped]</hidden_input_name> - <reload_param_name>products_grouped</reload_param_name> - </action> - <action method="addColumnInputName"> + <adminhtml_catalog_product_grouped_grid> + <reference name="catalog.product.edit.tab.super.grid.container"> + <block type="Mage_Catalog_Block_Product_Grouped_AssociatedProducts_Grid" name="catalog.product.edit.tab.super.group" as="catalog.product.group.grid"> + <arguments> + <id>grouped_grid</id> + <dataSource type="object">Mage_Catalog_Model_Resource_Product_Type_Grouped_AssociatedProductsCollection</dataSource> + <use_ajax>1</use_ajax> + <default_sort>id</default_sort> + <default_dir>DESC</default_dir> + <save_parameters_in_session>0</save_parameters_in_session> + <pager_visibility>0</pager_visibility> + <grid_url type="url"> + <path>*/*/superGroup</path> + <params> + <_current>1</_current> + </params> + </grid_url> + </arguments> + <block type="Mage_Backend_Block_Widget_Grid_ColumnSet" name="catalog.product.edit.tab.super.group.columnSet" as="grid.columnSet"> + <arguments> + <id>grouped_grid</id> + <filter_visibility>0</filter_visibility> + </arguments> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="info"> + <arguments> + <type>grip</type> + <index>entity_id</index> + <width>5px</width> + <sortable>0</sortable> + <inline_css>ui-icon ui-icon-grip-dotted-vertical</inline_css> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="name"> + <arguments> + <header translate="true" module="Mage_Sales">Name</header> + <type>text</type> + <index>name</index> + <editable>1</editable> + <sortable>0</sortable> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="sku"> + <arguments> + <header translate="true" module="Mage_Sales">SKU</header> + <type>text</type> + <index>sku</index> + <width>80px</width> + <sortable>0</sortable> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="price"> + <arguments> + <header translate="true" module="Mage_Sales">Price</header> + <type>currency</type> + <index>price</index> + <width>110px</width> + <align>right</align> + <sortable>0</sortable> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="qty"> + <arguments> + <header translate="true" module="Mage_Sales">Default Qty</header> + <type>number</type> + <index>qty</index> + <width>110px</width> + <align>right</align> + <editable>1</editable> + <sortable>0</sortable> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="delete"> + <arguments> + <header translate="true" module="Mage_Sales">Delete</header> + <type>button</type> + <button_type>button</button_type> + <column_css_class>product-delete</column_css_class> + <width>60px</width> + <renderer>Mage_Backend_Block_Widget_Grid_Column_Renderer_Button</renderer> + <align>right</align> + <sortable>0</sortable> + </arguments> + </block> + </block> + <action method="setGridData"> + <hidden_input_name>links[grouped]</hidden_input_name> + <fields_to_save> <input_name>qty</input_name> - <input_name>position</input_name> - </action> - </reference> + <input_name2>position</input_name2> + </fields_to_save> + </action> </block> - </container> + </reference> + </adminhtml_catalog_product_grouped_grid> + + <adminhtml_catalog_product_grouped_grid_popup> + <reference name="catalog.product.edit.tab.super.grid.popup.container"> + <block type="Mage_Backend_Block_Widget_Grid" name="catalog.product.edit.tab.super.group.popup" as="catalog.product.group.grid.popup"> + <arguments> + <id>grouped_grid_popup</id> + <dataSource type="object">Mage_Catalog_Model_Resource_Product_Type_Grouped_AssociatedProductsCollection</dataSource> + <use_ajax>1</use_ajax> + <default_sort>id</default_sort> + <default_dir>ASC</default_dir> + <save_parameters_in_session>1</save_parameters_in_session> + <grid_url type="url"> + <path>*/*/superGroupPopup</path> + <params> + <_current>1</_current> + </params> + </grid_url> + </arguments> + <block type="Mage_Backend_Block_Widget_Grid_ColumnSet" name="catalog.product.edit.tab.super.group.popup.columnSet" as="grid.columnSet"> + <arguments> + <id>grouped_grid_popup</id> + </arguments> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="in_products"> + <arguments> + <type>checkbox</type> + <header_css_class>a-center</header_css_class> + <column_css_class>selected-products</column_css_class> + <width>60px</width> + <align>center</align> + <index>entity_id</index> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="name"> + <arguments> + <header translate="true" module="Mage_Sales">Name</header> + <column_css_class>associated-product-name</column_css_class> + <type>text</type> + <index>name</index> + <editable>1</editable> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="sku"> + <arguments> + <header translate="true" module="Mage_Sales">SKU</header> + <column_css_class>associated-product-sku</column_css_class> + <type>text</type> + <index>sku</index> + <width>80px</width> + </arguments> + </block> + <block type="Mage_Backend_Block_Widget_Grid_Column" as="price"> + <arguments> + <header translate="true" module="Mage_Sales">Price</header> + <column_css_class>associated-product-price</column_css_class> + <type>currency</type> + <index>price</index> + <width>110px</width> + <align>right</align> + </arguments> + </block> + </block> + </block> + </reference> + </adminhtml_catalog_product_grouped_grid_popup> + + <adminhtml_catalog_product_supergroup> + <update handle="adminhtml_catalog_product_grouped"/> + <container output="1" name="catalog.product.edit.tab.super.grid.container" label="grid"></container> </adminhtml_catalog_product_supergroup> - <adminhtml_catalog_product_supergroupgridonly> - <container name="root" label="Root" output="1"> - <block type="Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Group" name="catalog.product.edit.tab.super.group" /> - </container> - </adminhtml_catalog_product_supergroupgridonly> + <adminhtml_catalog_product_supergrouppopup> + <update handle="adminhtml_catalog_product_grouped"/> + <container output="1" name="catalog.product.edit.tab.super.grid.popup.container" label="grid"></container> + </adminhtml_catalog_product_supergrouppopup> <adminhtml_catalog_product_variationsmatrix> <container name="root" label="Root" output="1"> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product-variation.js b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product-variation.js index 1b8f4f993b9..7a7050a6097 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product-variation.js +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product-variation.js @@ -27,7 +27,7 @@ _create: function () { this.element.sortable({ axis: 'y', - handle: '.entry-edit-head', + handle: '.ui-icon-grip-dotted-vertical', update: function () { $(this).find('[name$="[position]"]').each(function (index) { $(this).val(index); diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product.js b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product.js index e5df89f39bd..ee4e2f5743a 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product.js +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product.js @@ -315,579 +315,6 @@ Product.Attributes.prototype = { } }; -Product.Configurable = Class.create(); -Product.Configurable.prototype = { - initialize : function(attributes, links, idPrefix, grid, readonly) { - this.templatesSyntax = new RegExp( - '(^|.|\\r|\\n)(\'{{\\s*(\\w+)\\s*}}\')', ""); - this.attributes = attributes; // Attributes - this.idPrefix = idPrefix; // Container id prefix - this.links = $H(links); // Associated products - this.newProducts = []; // For product that's created through Create - // Empty and Copy from Configurable - this.readonly = readonly; - - /* Generation templates */ - this.addAttributeTemplate = new Template( - $(idPrefix + 'attribute_template').innerHTML.replace(/__id__/g, - "'{{html_id}}'").replace(/ template no-display/g, ''), - this.templatesSyntax); - this.addValueTemplate = new Template( - $(idPrefix + 'value_template').innerHTML.replace(/__id__/g, - "'{{html_id}}'").replace(/ template no-display/g, ''), - this.templatesSyntax); - this.pricingValueTemplate = new Template( - $(idPrefix + 'simple_pricing').innerHTML, this.templatesSyntax); - this.pricingValueViewTemplate = new Template( - $(idPrefix + 'simple_pricing_view').innerHTML, - this.templatesSyntax); - - this.container = $(idPrefix + 'attributes'); - - /* Listeners */ - this.onLabelUpdate = this.updateLabel.bindAsEventListener(this); // Update - // attribute - // label - this.onValuePriceUpdate = this.updateValuePrice - .bindAsEventListener(this); // Update pricing value - this.onValueTypeUpdate = this.updateValueType.bindAsEventListener(this); // Update - // pricing - // type - this.onValueDefaultUpdate = this.updateValueUseDefault - .bindAsEventListener(this); - - /* Grid initialization and attributes initialization */ - this.createAttributes(); // Creation of default attributes - - this.grid = grid; - this.grid.rowClickCallback = this.rowClick.bind(this); - this.grid.initRowCallback = this.rowInit.bind(this); - this.grid.checkboxCheckCallback = this.registerProduct.bind(this); // Associate/Unassociate - // simple - // product - - this.grid.rows.each( function(row) { - this.rowInit(this.grid, row); - }.bind(this)); - this.updateGrid(); - }, - createAttributes : function() { - this.attributes.each( function(attribute, index) { - // var li = Builder.node('li', {className:'attribute'}); - var li = $(document.createElement('LI')); - li.className = 'attribute'; - - li.id = this.idPrefix + '_attribute_' + index; - attribute.html_id = li.id; - if (attribute && attribute.label && attribute.label.blank()) { - attribute.label = ' ' - } - var label_readonly = ''; - var use_default_checked = ''; - if (attribute.use_default == '1') { - use_default_checked = ' checked="checked"'; - label_readonly = ' readonly="readonly"'; - } - - var template = this.addAttributeTemplate.evaluate(attribute); - template = template.replace( - new RegExp(' readonly="label"', 'ig'), label_readonly); - template = template.replace(new RegExp( - ' checked="use_default"', 'ig'), use_default_checked); - li.update(template); - li.attributeObject = attribute; - - this.container.appendChild(li); - li.attributeValues = li.down('.attribute-values'); - - if (attribute.values) { - attribute.values.each( function(value) { - this.createValueRow(li, value); // Add pricing values - }.bind(this)); - } - - /* Observe label change */ - Event.observe(li.down('.attribute-label'), 'change', - this.onLabelUpdate); - Event.observe(li.down('.attribute-label'), 'keyup', - this.onLabelUpdate); - Event.observe(li.down('.attribute-use-default-label'), - 'change', this.onLabelUpdate); - }.bind(this)); - if (!this.readonly) { - // Creation of sortable for attributes sorting - Sortable.create(this.container, { - handle :'attribute-name-container', - onUpdate :this.updatePositions.bind(this) - }); - } - this.updateSaveInput(); - }, - - updateLabel : function(event) { - var li = Event.findElement(event, 'LI'); - var labelEl = li.down('.attribute-label'); - var defEl = li.down('.attribute-use-default-label'); - - li.attributeObject.label = labelEl.value; - if (defEl.checked) { - labelEl.readOnly = true; - li.attributeObject.use_default = 1; - } else { - labelEl.readOnly = false; - li.attributeObject.use_default = 0; - } - - this.updateSaveInput(); - }, - updatePositions : function(param) { - this.container.childElements().each( function(row, index) { - row.attributeObject.position = index; - }); - this.updateSaveInput(); - }, - addNewProduct : function(productId, attributes) { - if (this.checkAttributes(attributes)) { - this.links.set(productId, this.cloneAttributes(attributes)); - } else { - this.newProducts.push(productId); - } - - this.updateGrid(); - this.updateValues(); - this.grid.reload(null); - }, - createEmptyProduct : function() { - this.createPopup(this.createEmptyUrl) - }, - createNewProduct : function() { - this.createPopup(this.createNormalUrl); - }, - createPopup : function(url) { - if (this.win && !this.win.closed) { - this.win.close(); - } - - this.win = window.open(url, '', - 'width=1000,height=700,resizable=1,scrollbars=1'); - this.win.focus(); - }, - registerProduct : function(grid, element, checked) { - if (checked) { - if (element.linkAttributes) { - this.links.set(element.value, element.linkAttributes); - } - } else { - this.links.unset(element.value); - } - this.updateGrid(); - this.grid.rows.each( function(row) { - this.revalidateRow(this.grid, row); - }.bind(this)); - this.updateValues(); - }, - updateProduct : function(productId, attributes) { - var isAssociated = false; - - if (typeof this.links.get(productId) != 'undefined') { - isAssociated = true; - this.links.unset(productId); - } - - if (isAssociated && this.checkAttributes(attributes)) { - this.links.set(productId, this.cloneAttributes(attributes)); - } else if (isAssociated) { - this.newProducts.push(productId); - } - - this.updateGrid(); - this.updateValues(); - this.grid.reload(null); - }, - cloneAttributes : function(attributes) { - var newObj = []; - for ( var i = 0, length = attributes.length; i < length; i++) { - newObj[i] = Object.clone(attributes[i]); - } - return newObj; - }, - rowClick : function(grid, event) { - var trElement = Event.findElement(event, 'tr'); - var isInput = Event.element(event).tagName.toUpperCase() == 'INPUT'; - - if ($(Event.findElement(event, 'td')).down('a')) { - return; - } - - if (trElement) { - var checkbox = $(trElement).down('input'); - if (checkbox && !checkbox.disabled) { - var checked = isInput ? checkbox.checked : !checkbox.checked; - grid.setCheckboxChecked(checkbox, checked); - } - } - }, - rowInit : function(grid, row) { - var checkbox = $(row).down('.checkbox'); - var input = $(row).down('.value-json'); - if (checkbox && input) { - checkbox.linkAttributes = input.value.evalJSON(); - if (!checkbox.checked) { - if (!this.checkAttributes(checkbox.linkAttributes)) { - $(row).addClassName('invalid'); - checkbox.disable(); - } else { - $(row).removeClassName('invalid'); - checkbox.enable(); - } - } - } - }, - revalidateRow : function(grid, row) { - var checkbox = $(row).down('.checkbox'); - if (checkbox) { - if (!checkbox.checked) { - if (!this.checkAttributes(checkbox.linkAttributes)) { - $(row).addClassName('invalid'); - checkbox.disable(); - } else { - $(row).removeClassName('invalid'); - checkbox.enable(); - } - } - } - }, - checkAttributes : function(attributes) { - var result = true; - this.links - .each( function(pair) { - var fail = false; - for ( var i = 0; i < pair.value.length && !fail; i++) { - for ( var j = 0; j < attributes.length && !fail; j++) { - if (pair.value[i].attribute_id == attributes[j].attribute_id - && pair.value[i].value_index != attributes[j].value_index) { - fail = true; - } - } - } - if (!fail) { - result = false; - } - }); - return result; - }, - updateGrid : function() { - this.grid.reloadParams = { - 'attributes[]': this.attributes.map(function(el) { return el.attribute_id; }), - 'products[]' :this.links.keys().size() ? this.links.keys() : [ 0 ], - 'new_products[]' :this.newProducts - }; - }, - updateValues : function() { - var uniqueAttributeValues = $H( {}); - /* Collect unique attributes */ - this.links.each( function(pair) { - for ( var i = 0, length = pair.value.length; i < length; i++) { - var attribute = pair.value[i]; - if (uniqueAttributeValues.keys() - .indexOf(attribute.attribute_id) == -1) { - uniqueAttributeValues.set(attribute.attribute_id, $H( {})); - } - uniqueAttributeValues.get(attribute.attribute_id).set( - attribute.value_index, attribute); - } - }); - /* Updating attributes value container */ - this.container - .childElements() - .each( - function(row) { - var attribute = row.attributeObject; - for ( var i = 0, length = attribute.values.length; i < length; i++) { - if (uniqueAttributeValues.keys().indexOf( - attribute.attribute_id) == -1 - || uniqueAttributeValues - .get(attribute.attribute_id) - .keys() - .indexOf( - attribute.values[i].value_index) == -1) { - row.attributeValues - .childElements() - .each( - function(elem) { - if (elem.valueObject.value_index == attribute.values[i].value_index) { - elem.remove(); - } - }); - attribute.values[i] = undefined; - - } else { - uniqueAttributeValues.get( - attribute.attribute_id).unset( - attribute.values[i].value_index); - } - } - attribute.values = attribute.values.compact(); - if (uniqueAttributeValues - .get(attribute.attribute_id)) { - uniqueAttributeValues.get( - attribute.attribute_id).each( - function(pair) { - attribute.values.push(pair.value); - this - .createValueRow(row, - pair.value); - }.bind(this)); - } - }.bind(this)); - this.updateSaveInput(); - this.updateSimpleForm(); - }, - createValueRow : function(container, value) { - var templateVariables = $H( {}); - if (!this.valueAutoIndex) { - this.valueAutoIndex = 1; - } - templateVariables.set('html_id', container.id + '_' - + this.valueAutoIndex); - templateVariables.update(value); - var pricingValue = parseFloat(templateVariables.get('pricing_value')); - if (!isNaN(pricingValue)) { - templateVariables.set('pricing_value', pricingValue); - } else { - templateVariables.unset('pricing_value'); - } - this.valueAutoIndex++; - - // var li = $(Builder.node('li', {className:'attribute-value'})); - var li = $(document.createElement('LI')); - li.className = 'attribute-value'; - li.id = templateVariables.get('html_id'); - li.update(this.addValueTemplate.evaluate(templateVariables)); - li.valueObject = value; - if (typeof li.valueObject.is_percent == 'undefined') { - li.valueObject.is_percent = 0; - } - - if (typeof li.valueObject.pricing_value == 'undefined') { - li.valueObject.pricing_value = ''; - } - - container.attributeValues.appendChild(li); - - var priceField = li.down('.attribute-price'); - var priceTypeField = li.down('.attribute-price-type'); - - if (priceTypeField != undefined && priceTypeField.options != undefined) { - if (parseInt(value.is_percent)) { - priceTypeField.options[1].selected = !(priceTypeField.options[0].selected = false); - } else { - priceTypeField.options[1].selected = !(priceTypeField.options[0].selected = true); - } - } - - Event.observe(priceField, 'keyup', this.onValuePriceUpdate); - Event.observe(priceField, 'change', this.onValuePriceUpdate); - Event.observe(priceTypeField, 'change', this.onValueTypeUpdate); - var useDefaultEl = li.down('.attribute-use-default-value'); - if (useDefaultEl) { - if (li.valueObject.use_default_value) { - useDefaultEl.checked = true; - this.updateUseDefaultRow(useDefaultEl, li); - } - Event.observe(useDefaultEl, 'change', this.onValueDefaultUpdate); - } - }, - updateValuePrice : function(event) { - var li = Event.findElement(event, 'LI'); - li.valueObject.pricing_value = (Event.element(event).value.blank() ? null - : Event.element(event).value); - this.updateSimpleForm(); - this.updateSaveInput(); - }, - updateValueType : function(event) { - var li = Event.findElement(event, 'LI'); - li.valueObject.is_percent = (Event.element(event).value.blank() ? null - : Event.element(event).value); - this.updateSimpleForm(); - this.updateSaveInput(); - }, - updateValueUseDefault : function(event) { - var li = Event.findElement(event, 'LI'); - var useDefaultEl = Event.element(event); - li.valueObject.use_default_value = useDefaultEl.checked; - this.updateUseDefaultRow(useDefaultEl, li); - }, - updateUseDefaultRow : function(useDefaultEl, li) { - var priceField = li.down('.attribute-price'); - var priceTypeField = li.down('.attribute-price-type'); - if (useDefaultEl.checked) { - priceField.disabled = true; - priceTypeField.disabled = true; - } else { - priceField.disabled = false; - priceTypeField.disabled = false; - } - this.updateSimpleForm(); - this.updateSaveInput(); - }, - updateSaveInput : function() { - $(this.idPrefix + 'save_attributes').value = Object.toJSON(this.attributes); - }, - initializeAdvicesForSimpleForm : function() { - if ($(this.idPrefix + 'simple_form').advicesInited) { - return; - } - - $(this.idPrefix + 'simple_form').select('td.value').each( function(td) { - var adviceContainer = $(Builder.node('div')); - td.appendChild(adviceContainer); - td.select('input', 'select').each( function(element) { - element.advaiceContainer = adviceContainer; - }); - }); - $(this.idPrefix + 'simple_form').advicesInited = true; - }, - checkCreationUniqueAttributes : function() { - var attributes = []; - this.attributes - .each( function(attribute) { - attributes - .push( { - attribute_id :attribute.attribute_id, - value_index :$('simple_product_' + attribute.attribute_code).value - }); - }.bind(this)); - - return this.checkAttributes(attributes); - }, - getAttributeByCode : function(attributeCode) { - var attribute = null; - this.attributes.each( function(item) { - if (item.attribute_code == attributeCode) { - attribute = item; - throw $break; - } - }); - return attribute; - }, - getAttributeById : function(attributeId) { - var attribute = null; - this.attributes.each( function(item) { - if (item.attribute_id == attributeId) { - attribute = item; - throw $break; - } - }); - return attribute; - }, - getValueByIndex : function(attribute, valueIndex) { - var result = null; - attribute.values.each( function(value) { - if (value.value_index == valueIndex) { - result = value; - throw $break; - } - }); - return result; - }, - showPricing : function(select, attributeCode) { - var attribute = this.getAttributeByCode(attributeCode); - if (!attribute) { - return; - } - - select = $(select); - if (select.value - && !$('simple_product_' + attributeCode + '_pricing_container')) { - Element - .insert( - select, - { - after :'<div class="left"></div> <div id="simple_product_' + attributeCode + '_pricing_container" class="left"></div>' - }); - var newContainer = select.next('div'); - select.parentNode.removeChild(select); - newContainer.appendChild(select); - // Fix visualization bug - $(this.idPrefix + 'simple_form').down('.form-list').style.width = '100%'; - } - - var container = $('simple_product_' + attributeCode + '_pricing_container'); - - if (select.value) { - var value = this.getValueByIndex(attribute, select.value); - if (!value) { - if (!container.down('.attribute-price')) { - if (value == null) { - value = {}; - } - container.update(this.pricingValueTemplate.evaluate(value)); - var priceValueField = container.down('.attribute-price'); - var priceTypeField = container - .down('.attribute-price-type'); - - priceValueField.attributeCode = attributeCode; - priceValueField.priceField = priceValueField; - priceValueField.typeField = priceTypeField; - - priceTypeField.attributeCode = attributeCode; - priceTypeField.priceField = priceValueField; - priceTypeField.typeField = priceTypeField; - - Event.observe(priceValueField, 'change', - this.updateSimplePricing.bindAsEventListener(this)); - Event.observe(priceValueField, 'keyup', - this.updateSimplePricing.bindAsEventListener(this)); - Event.observe(priceTypeField, 'change', - this.updateSimplePricing.bindAsEventListener(this)); - - $('simple_product_' + attributeCode + '_pricing_value').value = null; - $('simple_product_' + attributeCode + '_pricing_type').value = null; - } - } else if (!isNaN(parseFloat(value.pricing_value))) { - container.update(this.pricingValueViewTemplate.evaluate( { - 'value' :(parseFloat(value.pricing_value) > 0 ? '+' : '') - + parseFloat(value.pricing_value) - + (parseInt(value.is_percent) > 0 ? '%' : '') - })); - $('simple_product_' + attributeCode + '_pricing_value').value = value.pricing_value; - $('simple_product_' + attributeCode + '_pricing_type').value = value.is_percent; - } else { - container.update(''); - $('simple_product_' + attributeCode + '_pricing_value').value = null; - $('simple_product_' + attributeCode + '_pricing_type').value = null; - } - } else if (container) { - container.update(''); - $('simple_product_' + attributeCode + '_pricing_value').value = null; - $('simple_product_' + attributeCode + '_pricing_type').value = null; - } - }, - updateSimplePricing : function(evt) { - var element = Event.element(evt); - if (!element.priceField.value.blank()) { - $('simple_product_' + element.attributeCode + '_pricing_value').value = element.priceField.value; - $('simple_product_' + element.attributeCode + '_pricing_type').value = element.typeField.value; - } else { - $('simple_product_' + element.attributeCode + '_pricing_value').value = null; - $('simple_product_' + element.attributeCode + '_pricing_type').value = null; - } - }, - updateSimpleForm : function() { - this.attributes.each( function(attribute) { - if ($('simple_product_' + attribute.attribute_code)) { - this.showPricing( - $('simple_product_' + attribute.attribute_code), - attribute.attribute_code); - } - }.bind(this)); - }, - showNoticeMessage : function() { - $('assign_product_warrning').show(); - } -} - var onInitDisableFieldsList = []; function toogleFieldEditMode(toogleIdentifier, fieldContainer) { diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/composite/fieldset/grouped.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/composite/fieldset/grouped.phtml index a48249c31dd..a9760647a36 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/composite/fieldset/grouped.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/composite/fieldset/grouped.phtml @@ -44,7 +44,7 @@ <col /> <col width="1" /> <thead> - <tr "class="headings"> + <tr class="headings"> <th><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('ID') ?></th> <th><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('SKU') ?></th> <th><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Product Name') ?></th> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit.phtml index 0f9f54be33f..d12e65c8294 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit.phtml @@ -52,34 +52,6 @@ <?php echo $this->getChildHtml('product-type-tabs') ?> </form> <script type="text/javascript"> - var productTemplateSyntax = /(^|.|\r|\n)({{(\w+)}})/; - jQuery('#product-edit-form').mage('form') - .mage('validation', {validationUrl: '<?php echo $this->getValidationUrl() ?>'}); - function setSettings(urlTemplate, setElement, typeElement) { - var template = new Template(urlTemplate, productTemplateSyntax); - setLocation(template.evaluate({attribute_set:$F(setElement),type:$F(typeElement)})); - } - - function setSuperSettings(urlTemplate, attributesClass, validateField) { - var attributesFields = $$('.' + attributesClass); - var attributes = Form.serializeElements(attributesFields, true).attribute; - if (typeof attributes == 'string') { - attributes = [attributes]; - } - - if (!attributes) { - $(validateField).value = 'no-attributes'; - } else { - $(validateField).value = 'has-attributes'; - } - - var template = new Template(urlTemplate, productTemplateSyntax); - var url = template.evaluate({ - attributes: encode_base64(attributes.join(',')).replace(new RegExp('/', 'g'), '%2F').replace(new RegExp('=', 'g'), '%3D') - }); - jQuery('#product-edit-form').attr('action', url + '&active_tab=configurable').submit(); - } - function checkMaxLength(Object, MaxLen) { if (Object.value.length > MaxLen-1) { @@ -89,6 +61,10 @@ } jQuery(function($) { + $('#product-edit-form') + .mage('form') + .mage('validation', {validationUrl: '<?php echo $this->getValidationUrl() ?>'}); + <?php if ($this->getSelectedTabId()): ?> if($('#<?php echo $this->getSelectedTabId() ?>').length) { $('#<?php echo $this->getSelectedTabId() ?>').trigger('click'); @@ -96,7 +72,8 @@ jQuery(function($) { <?php endif; ?> $('#product_info_tabs').on('tabsbeforeactivate', function (event, ui) { - $('#config_super_product')[$(ui.newPanel).find('#attribute-name-container').length ? 'show' : 'hide'](); + var action = $(ui.newPanel).find('#attribute-name-container').length ? 'show' : 'hide'; + $('#config_super_product, #grouped_product_container')[action](); }); var masks = <?php echo $this->helper('Mage_Core_Helper_Data')->jsonEncode($this->getFieldsAutogenerationMasks())?>; @@ -172,27 +149,30 @@ jQuery(function($) { new Autogenerator(masks).bindAll(); - var data = <?php echo $this->getTypeSwitcherData();?>; - new TypeSwitcher(data).bindAll(); + new TypeSwitcher(<?php echo $this->getTypeSwitcherData();?>).bindAll(); $('.widget-button-save .item-default, #save-split-button-duplicate-button[onclick=""]').parent().hide(); var $form = $('#product-edit-form'), - fieldSelector = '.required-entry, .required-option-select'; - $form.on('focus change keyup click', fieldSelector + ',:checkbox,button', function () { - var disabled = false; - $.each($form.find(fieldSelector), function () { - if (!$.trim($(this).val()) && !$(this).closest('.ignore-validate').length - && $(this).is('input, select, textarea') && !$(this).prop('disabled') - ) { - disabled = true; - return false; - } - }); - $('.widget-button-save, .widget-button-save > *').toggleClass('disabled', disabled).prop('disabled', disabled); - }); - + fieldSelector = '.required-entry, .required-option-select', + updateSaveSplitButtonAvailability = function () { + var disabled = false; + $.each($form.find(fieldSelector), function () { + if (!$.trim($(this).val()) && !$(this).closest('.ignore-validate').length + && $(this).is('input, select, textarea') && !$(this).prop('disabled') + ) { + disabled = true; + return false; + } + }); + $('.widget-button-save, .widget-button-save > *').toggleClass('disabled', disabled).prop('disabled', disabled); + }; + $form.on('focus change keyup click', fieldSelector + ',:checkbox,button', updateSaveSplitButtonAvailability); $(window).load(function() { - $('#name').focus().val($('#name').val()); + if ($.trim($('#name').val()) == '') { + $('#name').focus(); + } else { + updateSaveSplitButtonAvailability(); + } }); }); </script> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/options.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/options.phtml index 7b77b65c6a4..e1bf3bf7e7b 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/options.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/options.phtml @@ -25,7 +25,7 @@ */ ?> <div class="entry-edit custom-options product-custom-options"> - <div id="dynamic-price-warrning" style="display:none"> + <div id="dynamic-price-warning" style="display:none"> <ul class="messages"> <li class="error-msg"> <ul> @@ -53,8 +53,8 @@ varienWindowOnload(true); //show error message if ($('price_type')) { - if ($('price_type').value == '0' && $('dynamic-price-warrning')) { - $('dynamic-price-warrning').show(); + if ($('price_type').value == '0' && $('dynamic-price-warning')) { + $('dynamic-price-warning').show(); } } </script> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-js-template.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-js-template.phtml index 5b8eb223ed8..3cd2bbdaa9e 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-js-template.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-js-template.phtml @@ -38,8 +38,8 @@ <input value="${attribute.code}" type="hidden" name="product[configurable_attributes_data][${attribute.id}][code]"/> - <div class="entry-edit-head" style="cursor: move;"> - <span class="ui-icon ui-icon-arrowthick-2-n-s" style="float:left"></span> + <div class="entry-edit-head"> + <span class="ui-icon ui-icon-grip-dotted-vertical" style="float:left"></span> <h4 class="icon-head head-edit-form fieldset-legend"> <input value="${attribute.label}" name="product[configurable_attributes_data][${attribute.id}][label]" diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-template.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-template.phtml index e3a9e1837d7..c8ce5544266 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-template.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/attribute-template.phtml @@ -48,8 +48,8 @@ $id = $this->escapeHtml($attribute['attribute_id']); <input value="<?php echo $this->escapeHtml($attribute['position']); ?>" type="hidden" name="product[configurable_attributes_data][<?php echo $id ?>][position]"/> - <div class="entry-edit-head" style="cursor: move;"> - <span class="ui-icon ui-icon-arrowthick-2-n-s" style="float:left;"></span> + <div class="entry-edit-head"> + <span class="ui-icon ui-icon-grip-dotted-vertical" style="float:left"></span> <h4 class="icon-head head-edit-form fieldset-legend"> <input value="<?php echo $this->escapeHtml($attribute['label']); ?>" name="product[configurable_attributes_data][<?php echo $id ?>][label]" @@ -62,7 +62,7 @@ $id = $this->escapeHtml($attribute['attribute_id']); name="product[configurable_attributes_data][<?php echo $id ?>][use_default]" id="attribute-<?php echo $id ?>"/> <?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Use default')?> - </label> + </label> </h4> <span class="ui-icon ui-icon-circle-close remove"></span> <span class="ui-icon ui-icon-circle-triangle-s toggle"></span> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/config.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/config.phtml index d01eefba207..1f69e3ab83d 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/config.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/edit/super/config.phtml @@ -73,18 +73,25 @@ jQuery(function($) { $('#attributes-container').variationsAttributes(); $("#<?php echo $this->getId()?>-checkbox").on('click change', function() { - var $fieldset = $("#<?php echo $this->getId()?> > fieldset"); + var $fieldset = $("#<?php echo $this->getId()?> > fieldset"), + stockAvailabilityField = $('#quantity_and_stock_status'), + qtyField = $('#qty'); if ($(this).is(':checked')) { $fieldset.show(); $('#change-attribute-set-button').attr('disabled', true).addClass('disabled'); $variationsContainer.find("input[name='attributes[]']").removeAttr('disabled'); - $('#qty').attr('disabled', true); + qtyField.prop('disabled', true).trigger('change'); + stockAvailabilityField.prop('disabled', false); $.each($('#attributes-container').variationsAttributes('getAttributes'), function() { $('#attribute-' + this.code + '-container select').attr('disabled', true); }) } else { $('#change-attribute-set-button').removeAttr('disabled').removeClass('disabled'); - $('#qty').removeAttr('disabled'); + qtyField.prop('disabled', false).trigger('change'); + if (qtyField.val() == '') { + stockAvailabilityField.val(0).trigger('change'); + stockAvailabilityField.prop('disabled', true); + } $variationsContainer.find('.entry-edit').remove(); $.each($('#attributes-container').variationsAttributes('getAttributes'), function() { $('#attribute-' + this.code + '-container select').removeAttr('disabled'); diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/tab/inventory.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/tab/inventory.phtml index 21fbab07086..b1ff06f43a5 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/tab/inventory.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/product/tab/inventory.phtml @@ -55,7 +55,7 @@ <?php endif; ?> </tr> -<?php if (!$this->getProduct()->isComposite() || $this->getProduct()->isConfigurable()): ?> +<?php if (!$this->getProduct()->isComposite()): ?> <tr> <td class="label"><label for="inventory_qty"><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Qty') ?></label></td> <td class="value"> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/type-switcher.js b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/type-switcher.js index 24ead0511be..3fb0020093c 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/type-switcher.js +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/catalog/type-switcher.js @@ -65,11 +65,15 @@ this.$is_virtual.on('change click', function() { if ($(this).is(':checked')) { $type.val(self.baseType.virtual).trigger('change'); - self.$weight.addClass('ignore-validate').attr('disabled', 'disabled'); + if ($type.val() != 'bundle') { // @TODO move this check to Mage_Bundle after refactoring as widget + self.$weight.addClass('ignore-validate').prop('disabled', true); + } self.$tab.show(); } else { $type.val(self.baseType.real).trigger('change'); - self.$weight.removeClass('ignore-validate').removeAttr('disabled', 'disabled'); + if ($type.val() != 'bundle') { // @TODO move this check to Mage_Bundle after refactoring as widget + self.$weight.removeClass('ignore-validate').prop('disabled', false); + } self.$tab.hide(); } }).trigger('change'); diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/main.xml b/app/code/core/Mage/Adminhtml/view/adminhtml/main.xml index 313d4fe971f..ff9a18fb391 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/main.xml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/main.xml @@ -60,7 +60,6 @@ Supported layout update handles (special): <action method="addJs"><file>jquery/jquery-ui.custom.min.js</file></action> <action method="addJs"><file>head.load.min.js</file></action> <action method="addJs"><file>mage/mage.js</file></action> - <action method="addJs"><file>mage/backend/button.js</file></action> <action method="addJs"><file>jquery/jquery.tmpl.min.js</file></action> <action method="addJs"><file>mage/translate.js</file></action> <action method="addJs"><file>mage/backend/bootstrap.js</file></action> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/page/js/components.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/page/js/components.phtml index d846a9742ed..c52ecf8b104 100644 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/page/js/components.phtml +++ b/app/code/core/Mage/Adminhtml/view/adminhtml/page/js/components.phtml @@ -34,6 +34,8 @@ <script type="text/javascript"> (function($) { "use strict"; + $.mage.isDevMode(<?php echo Mage::getIsDeveloperMode() ?>); + /** * Declaration of resources needed for defined components */ @@ -45,6 +47,9 @@ button: [ '<?php echo $this->getViewFileUrl('mage/backend/button.js') ?>' ], + actionLink: [ + '<?php echo $this->getViewFileUrl('mage/backend/action-link.js') ?>' + ], validation: [ '<?php echo $this->getViewFileUrl('jquery/jquery.validate.js') ?>', '<?php echo $this->getViewFileUrl('mage/translate.js') ?>', @@ -62,8 +67,28 @@ ], floatingHeader: [ '<?php echo $this->getViewFileUrl('mage/backend/floating-header.js') ?>', + ], + suggest: [ + '<?php echo $this->getViewFileUrl('jquery/jquery.tmpl.min.js') ?>', + '<?php echo $this->getViewFileUrl('json2.js') ?>', + '<?php echo $this->getViewFileUrl('mage/backend/suggest.js') ?>' ] - }).load('loader'); + }) + /** + * Declaration of resources for components (based on previously defined components) + */ + .extend('multisuggest', 'suggest', + '<?php echo $this->getViewFileUrl('mage/backend/multisuggest.js') ?>' + ) + .extend('treeSuggest', 'multisuggest', [ + '<?php echo $this->getViewFileUrl('jquery/jstree/jquery.hotkeys.js') ?>', + '<?php echo $this->getViewFileUrl('jquery/jstree/jquery.jstree.js') ?>', + '<?php echo $this->getViewFileUrl('mage/backend/tree-suggest.js') ?>' + ]) + /** + * Load resources in advance for components which needed to be instantiated without delay. + */ + .load('loader'); })(jQuery); </script> <?php echo $this->getChildHtml() ?> diff --git a/app/code/core/Mage/Adminhtml/view/adminhtml/resetforgottenpassword.phtml b/app/code/core/Mage/Adminhtml/view/adminhtml/resetforgottenpassword.phtml deleted file mode 100644 index dbfd8971a10..00000000000 --- a/app/code/core/Mage/Adminhtml/view/adminhtml/resetforgottenpassword.phtml +++ /dev/null @@ -1,89 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Academic Free License (AFL 3.0) - * that is bundled with this package in the file LICENSE_AFL.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/afl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category design - * @package default_default - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) - */ -?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html lang="en"> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <title><?php echo Mage::helper('Mage_Adminhtml_Helper_Data')->__('Reset a Password'); ?></title> - <link type="text/css" rel="stylesheet" href="<?php echo $this->getViewFileUrl('reset.css'); ?>" media="all" /> - <link type="text/css" rel="stylesheet" href="<?php echo $this->getViewFileUrl('boxes.css'); ?>" media="all" /> - <link rel="icon" href="<?php echo $this->getViewFileUrl('Mage_Page::favicon.ico'); ?>" type="image/x-icon" /> - <link rel="shortcut icon" href="<?php echo $this->getViewFileUrl('Mage_Page::favicon.ico'); ?>" type="image/x-icon" /> - - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('jquery/jquery.min.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('mage/jquery-no-conflict.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('jquery/jquery-ui.custom.min.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('jquery/jquery.tmpl.min.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('jquery/jquery.validate.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('mage/validation.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('mage/backend/validation.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('mage/backend/form.js') ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('mage/translate.js') ?>"></script> - - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('prototype/prototype.js'); ?>"></script> - <script type="text/javascript" src="<?php echo $this->getViewFileUrl('scriptaculous/effects.js'); ?>"></script> - - <!--[if IE]> <link rel="stylesheet" href="<?php echo $this->getViewFileUrl('iestyles.css'); ?>" type="text/css" media="all" /> <![endif]--> - <!--[if lt IE 7]> <link rel="stylesheet" href="<?php echo $this->getViewFileUrl('below_ie7.css'); ?>" type="text/css" media="all" /> <![endif]--> - <!--[if IE 7]> <link rel="stylesheet" href="<?php echo $this->getViewFileUrl('ie7.css'); ?>" type="text/css" media="all" /> <![endif]--> - </head> - <body id="page-login"> - <div class="login-container"> - <div class="login-box"> - <form method="post" action="<?php echo $this->getUrl('*/*/resetpasswordpost', array('_query' => array('id' => $userId, 'token' => $resetPasswordLinkToken))); ?>" id="reset-password-form"> - <fieldset class="login-form"> - <input name="form_key" type="hidden" value="<?php echo $this->getFormKey(); ?>" /> - <h2><?php echo Mage::helper('Mage_Adminhtml_Helper_Data')->__('Reset a Password'); ?></h2> - <div id="messages"> - <?php echo $this->getMessagesBlock()->getGroupedHtml(); ?> - </div> - <div class="input-box f-left"> - <label for="password"><em class="required">*</em> <?php echo $this->__('New Password'); ?></label> - <br /> - <input type="password" class="input-text required-entry validate-admin-password" name="password" id="password" /> - </div> - <div class="input-box f-right"> - <label for="confirmation"><em class="required">*</em> <?php echo $this->__('Confirm New Password'); ?></label> - <br /> - <input type="password" class="input-text required-entry validate-cpassword" name="confirmation" id="confirmation" /> - </div> - <div class="clear"></div> - <div class="form-buttons"> - <a class="left" href="<?php echo $this->getUrl('adminhtml', array('_nosecret' => true)) ?>">« <?php echo Mage::helper('Mage_Adminhtml_Helper_Data')->__('Back to Login'); ?></a> - <button type="submit" title="<?php echo Mage::helper('Mage_Adminhtml_Helper_Data')->__('Reset Password'); ?>" class="forgot-password"><span><span><span><?php echo Mage::helper('Mage_Adminhtml_Helper_Data')->__('Reset Password'); ?></span></span></span></button> - </div> - </fieldset> - <p class="legal"><?php echo Mage::helper('Mage_Adminhtml_Helper_Data')->__('Magento® is a trademark of X.commerce, Inc. Copyright © %s X.commerce, Inc.', date('Y')); ?></p> - </form> - <div class="bottom"></div> - <script type="text/javascript"> - jQuery('#reset-password-form').form().validation(); - </script> - </div> - </div> - </body> -</html> diff --git a/app/code/core/Mage/Api/Controller/Action.php b/app/code/core/Mage/Api/Controller/Action.php new file mode 100644 index 00000000000..e378d3e5a73 --- /dev/null +++ b/app/code/core/Mage/Api/Controller/Action.php @@ -0,0 +1,61 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Generic API controller + */ +class Mage_Api_Controller_Action extends Mage_Core_Controller_Front_Action +{ + /** + * Currently used area + * + * @var string + */ + protected $_currentArea = 'frontend'; + + /** + * Use 'admin' store and prevent the session from starting + * + * @return Mage_Api_Controller_Action + */ + public function preDispatch() + { + Mage::app()->setCurrentStore('admin'); + $this->setFlag('', self::FLAG_NO_START_SESSION, 1); + parent::preDispatch(); + return $this; + } + + /** + * Retrieve webservice server + * + * @return Mage_Api_Model_Server + */ + protected function _getServer() + { + return Mage::getSingleton('Mage_Api_Model_Server'); + } +} diff --git a/app/code/core/Mage/Api/Exception.php b/app/code/core/Mage/Api/Exception.php new file mode 100644 index 00000000000..e290bd268f8 --- /dev/null +++ b/app/code/core/Mage/Api/Exception.php @@ -0,0 +1,53 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Api exception + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Exception extends Mage_Core_Exception +{ + protected $_customMessage = null; + + public function __construct($faultCode, $customMessage=null) + { + parent::__construct($faultCode); + $this->_customMessage = $customMessage; + } + + /** + * Custom error message, if error is not in api. + * + * @return unknown + */ + public function getCustomMessage() + { + return $this->_customMessage; + } +} // Class Mage_Api_Model_Resource_Exception End diff --git a/app/code/core/Mage/Api/Helper/Data.php b/app/code/core/Mage/Api/Helper/Data.php new file mode 100644 index 00000000000..a7bd732c3de --- /dev/null +++ b/app/code/core/Mage/Api/Helper/Data.php @@ -0,0 +1,359 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Web service api main helper + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Helper_Data extends Mage_Core_Helper_Abstract +{ + /** + * Go thru a WSI args array and turns it to correct state. + * + * @param Object $obj - Link to Object + * @return Object + */ + public function wsiArrayUnpacker(&$obj) + { + if (is_object($obj)) { + + $modifiedKeys = $this->clearWsiFootprints($obj); + + foreach ($obj as $key => $value) { + if (is_object($value)) { + $this->wsiArrayUnpacker($value); + } + if (is_array($value)) { + foreach ($value as &$val) { + if (is_object($val)) { + $this->wsiArrayUnpacker($val); + } + } + } + } + + foreach ($modifiedKeys as $arrKey) { + $this->associativeArrayUnpack($obj->$arrKey); + } + } + } + + /** + * Go thru an object parameters and unpak associative object to array. + * + * @param Object $obj - Link to Object + * @return Object + */ + public function v2AssociativeArrayUnpacker(&$obj) + { + if (is_object($obj) + && property_exists($obj, 'key') + && property_exists($obj, 'value') + ) { + if (count(array_keys(get_object_vars($obj))) == 2) { + $obj = array($obj->key => $obj->value); + return true; + } + } elseif (is_array($obj)) { + $arr = array(); + $needReplacement = true; + foreach ($obj as $key => &$value) { + $isAssoc = $this->v2AssociativeArrayUnpacker($value); + if ($isAssoc) { + foreach ($value as $aKey => $aVal) { + $arr[$aKey] = $aVal; + } + } else { + $needReplacement = false; + } + } + if ($needReplacement) { + $obj = $arr; + } + } elseif (is_object($obj)) { + $objectKeys = array_keys(get_object_vars($obj)); + + foreach ($objectKeys as $key) { + $this->v2AssociativeArrayUnpacker($obj->$key); + } + } + return false; + } + + /** + * Go thru mixed and turns it to a correct look. + * + * @param Mixed $mixed A link to variable that may contain associative array. + */ + public function associativeArrayUnpack(&$mixed) + { + if (is_array($mixed)) { + $tmpArr = array(); + foreach ($mixed as $key => $value) { + if (is_object($value)) { + $value = get_object_vars($value); + if (count($value) == 2 && isset($value['key']) && isset($value['value'])) { + $tmpArr[$value['key']] = $value['value']; + } + } + } + if (count($tmpArr)) { + $mixed = $tmpArr; + } + } + + if (is_object($mixed)) { + $numOfVals = count(get_object_vars($mixed)); + if ($numOfVals == 2 && isset($mixed->key) && isset($mixed->value)) { + $mixed = get_object_vars($mixed); + /* + * Processing an associative arrays. + * $mixed->key = '2'; $mixed->value = '3'; turns to array(2 => '3'); + */ + $mixed = array($mixed['key'] => $mixed['value']); + } + } + } + + /** + * Corrects data representation. + * + * @param Object $obj - Link to Object + * @return Object + */ + public function clearWsiFootprints(&$obj) + { + $modifiedKeys = array(); + + $objectKeys = array_keys(get_object_vars($obj)); + + foreach ($objectKeys as $key) { + if (is_object($obj->$key) && isset($obj->$key->complexObjectArray)) { + if (is_array($obj->$key->complexObjectArray)) { + $obj->$key = $obj->$key->complexObjectArray; + } else { // for one element array + $obj->$key = array($obj->$key->complexObjectArray); + } + $modifiedKeys[] = $key; + } + } + return $modifiedKeys; + } + + /** + * For the WSI, generates an response object. + * + * @param mixed $mixed - Link to Object + * @return mixed + */ + public function wsiArrayPacker($mixed) + { + if (is_array($mixed)) { + $arrKeys = array_keys($mixed); + $isDigit = false; + $isString = false; + foreach ($arrKeys as $key) { + if (is_int($key)) { + $isDigit = true; + break; + } + } + if ($isDigit) { + $mixed = $this->packArrayToObjec($mixed); + } else { + $mixed = (object)$mixed; + } + } + if (is_object($mixed) && isset($mixed->complexObjectArray)) { + foreach ($mixed->complexObjectArray as $k => $v) { + $mixed->complexObjectArray[$k] = $this->wsiArrayPacker($v); + } + } + return $mixed; + } + + /** + * For response to the WSI, generates an object from array. + * + * @param Array $arr - Link to Object + * @return Object + */ + public function packArrayToObjec(Array $arr) + { + $obj = new stdClass(); + $obj->complexObjectArray = $arr; + return $obj; + } + + /** + * Convert objects and arrays to array recursively + * + * @param array|object $data + * @return void + */ + public function toArray(&$data) + { + if (is_object($data)) { + $data = get_object_vars($data); + } + if (is_array($data)) { + foreach ($data as &$value) { + if (is_array($value) or is_object($value)) { + $this->toArray($value); + } + } + } + } + + /** + * Parse filters and format them to be applicable for collection filtration + * + * @param null|object|array $filters + * @param array $fieldsMap Map of field names in format: array('field_name_in_filter' => 'field_name_in_db') + * @return array + */ + public function parseFilters($filters, $fieldsMap = null) + { + // if filters are used in SOAP they must be represented in array format to be used for collection filtration + if (is_object($filters)) { + $parsedFilters = array(); + // parse simple filter + if (isset($filters->filter) && is_array($filters->filter)) { + foreach ($filters->filter as $field => $value) { + if (is_object($value) && isset($value->key) && isset($value->value)) { + $parsedFilters[$value->key] = $value->value; + } else { + $parsedFilters[$field] = $value; + } + } + } + // parse complex filter + if (isset($filters->complex_filter) && is_array($filters->complex_filter)) { + if ($this->isWsiCompliant()) { + // WS-I compliance mode + foreach ($filters->complex_filter as $fieldName => $condition) { + if (is_object($condition) && isset($condition->key) && isset($condition->value)) { + $conditionName = $condition->key; + $conditionValue = $condition->value; + $this->formatFilterConditionValue($conditionName, $conditionValue); + $parsedFilters[$fieldName] = array($conditionName => $conditionValue); + } + } + } else { + // non WS-I compliance mode + foreach ($filters->complex_filter as $value) { + if (is_object($value) && isset($value->key) && isset($value->value)) { + $fieldName = $value->key; + $condition = $value->value; + if (is_object($condition) && isset($condition->key) && isset($condition->value)) { + $this->formatFilterConditionValue($condition->key, $condition->value); + $parsedFilters[$fieldName] = array($condition->key => $condition->value); + } + } + } + } + } + $filters = $parsedFilters; + } + // make sure that method result is always array + if (!is_array($filters)) { + $filters = array(); + } + // apply fields mapping + if (isset($fieldsMap) && is_array($fieldsMap)) { + foreach ($filters as $field => $value) { + if (isset($fieldsMap[$field])) { + unset($filters[$field]); + $field = $fieldsMap[$field]; + $filters[$field] = $value; + } + } + } + return $filters; + } + + /** + * Check if API is working in SOAP WS-I compliant mode. + * + * @return bool + */ + public function isWsiCompliant() + { + $pathInfo = Mage::app()->getRequest()->getPathInfo(); + $pathParts = explode('/', trim($pathInfo, '/')); + $controllerPosition = 1; + if (isset($pathParts[$controllerPosition]) && $pathParts[$controllerPosition] == 'soap_wsi') { + $isWsiCompliant = true; + } else { + $isWsiCompliant = false; + } + return $isWsiCompliant; + } + + /** + * Convert condition value from the string into the array + * for the condition operators that require value to be an array. + * Condition value is changed by reference + * + * @param string $conditionOperator + * @param string $conditionValue + */ + public function formatFilterConditionValue($conditionOperator, &$conditionValue) + { + if (is_string($conditionOperator) && in_array($conditionOperator, array('in', 'nin', 'finset')) + && is_string($conditionValue) + ) { + $delimiter = ','; + $conditionValue = explode($delimiter, $conditionValue); + } + } + + /** + * Check if attribute is allowed to be used. + * + * @param string $attributeCode + * @param string $type + * @param array $ignoredAttributes + * @param array $attributes + * @return bool + */ + public function isAttributeAllowed($attributeCode, $type, $ignoredAttributes, array $attributes = null) + { + if (!empty($attributes) && !(in_array($attributeCode, $attributes))) { + return false; + } + if (isset($ignoredAttributes['global']) && in_array($attributeCode, $ignoredAttributes['global'])) { + return false; + } + if (isset($ignoredAttributes[$type]) && in_array($attributeCode, $ignoredAttributes[$type])) { + return false; + } + return true; + } +} diff --git a/app/code/core/Mage/Api/Model/Acl.php b/app/code/core/Mage/Api/Model/Acl.php new file mode 100644 index 00000000000..3fb69610582 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Acl.php @@ -0,0 +1,103 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Acl model + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Acl extends Zend_Acl +{ + /** + * All the group roles are prepended by G + * + */ + const ROLE_TYPE_GROUP = 'G'; + + /** + * All the user roles are prepended by U + * + */ + const ROLE_TYPE_USER = 'U'; + + /** + * User types for store access + * G - Guest customer (anonymous) + * C - Authenticated customer + * A - Authenticated admin user + * + */ + const USER_TYPE_GUEST = 'G'; + const USER_TYPE_CUSTOMER = 'C'; + const USER_TYPE_ADMIN = 'A'; + + /** + * Permission level to deny access + * + */ + const RULE_PERM_DENY = 0; + + /** + * Permission level to inheric access from parent role + * + */ + const RULE_PERM_INHERIT = 1; + + /** + * Permission level to allow access + * + */ + const RULE_PERM_ALLOW = 2; + + /** + * Get role registry object or create one + * + * @return Mage_Api_Model_Acl_Role_Registry + */ + protected function _getRoleRegistry() + { + if (null === $this->_roleRegistry) { + $this->_roleRegistry = Mage::getModel('Mage_Api_Model_Acl_Role_Registry'); + } + return $this->_roleRegistry; + } + + /** + * Add parent to role object + * + * @param Zend_Acl_Role $role + * @param Zend_Acl_Role $parent + * @return Mage_Api_Model_Acl + */ + public function addRoleParent($role, $parent) + { + $this->_getRoleRegistry()->addParent($role, $parent); + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Acl/Resource.php b/app/code/core/Mage/Api/Model/Acl/Resource.php new file mode 100644 index 00000000000..e771e5e9874 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Acl/Resource.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Acl resource + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Acl_Resource extends Zend_Acl_Resource +{ + +} diff --git a/app/code/core/Mage/Api/Model/Acl/Role.php b/app/code/core/Mage/Api/Model/Acl/Role.php new file mode 100644 index 00000000000..1a4bd2ff482 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Acl/Role.php @@ -0,0 +1,37 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * User acl role + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Acl_Role extends Mage_Api_Model_Role +{ +} diff --git a/app/code/core/Mage/Api/Model/Acl/Role/Generic.php b/app/code/core/Mage/Api/Model/Acl/Role/Generic.php new file mode 100644 index 00000000000..10d240d0f42 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Acl/Role/Generic.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * User acl role + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Acl_Role_Generic extends Zend_Acl_Role +{ + +} diff --git a/app/code/core/Mage/Api/Model/Acl/Role/Group.php b/app/code/core/Mage/Api/Model/Acl/Role/Group.php new file mode 100644 index 00000000000..c30cae453e2 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Acl/Role/Group.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Acl Group model + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Acl_Role_Group extends Mage_Api_Model_Acl_Role_Generic +{ + +} diff --git a/app/code/core/Mage/Api/Model/Acl/Role/Registry.php b/app/code/core/Mage/Api/Model/Acl/Role/Registry.php new file mode 100644 index 00000000000..2da227383f1 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Acl/Role/Registry.php @@ -0,0 +1,76 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Acl role registry + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Acl_Role_Registry extends Zend_Acl_Role_Registry +{ + /** + * Add parent to the $role node + * + * @param Zend_Acl_Role_Interface|string $role + * @param array|Zend_Acl_Role_Interface|string $parents + * @return Mage_Auth_Model_Acl_Role_Registry + */ + function addParent($role, $parents) + { + try { + if ($role instanceof Zend_Acl_Role_Interface) { + $roleId = $role->getRoleId(); + } else { + $roleId = $role; + $role = $this->get($role); + } + } catch (Zend_Acl_Role_Registry_Exception $e) { + throw new Zend_Acl_Role_Registry_Exception("Child Role id '$roleId' does not exist"); + } + + if (!is_array($parents)) { + $parents = array($parents); + } + foreach ($parents as $parent) { + try { + if ($parent instanceof Zend_Acl_Role_Interface) { + $roleParentId = $parent->getRoleId(); + } else { + $roleParentId = $parent; + } + $roleParent = $this->get($roleParentId); + } catch (Zend_Acl_Role_Registry_Exception $e) { + throw new Zend_Acl_Role_Registry_Exception("Parent Role id '$roleParentId' does not exist"); + } + $this->_roles[$roleId]['parents'][$roleParentId] = $roleParent; + $this->_roles[$roleParentId]['children'][$roleId] = $role; + } + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Acl/Role/User.php b/app/code/core/Mage/Api/Model/Acl/Role/User.php new file mode 100644 index 00000000000..3833e18fd04 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Acl/Role/User.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * User acl role + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Acl_Role_User extends Mage_Api_Model_Acl_Role_Generic +{ + +} diff --git a/app/code/core/Mage/Api/Model/Config.php b/app/code/core/Mage/Api/Model/Config.php new file mode 100644 index 00000000000..2abff6da50e --- /dev/null +++ b/app/code/core/Mage/Api/Model/Config.php @@ -0,0 +1,294 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Webservice api config model + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Config extends Varien_Simplexml_Config +{ + const CACHE_TAG = 'config_api'; + + /** + * Constructor + * + * @see Varien_Simplexml_Config + */ + public function __construct($sourceData=null) + { + $this->setCacheId('config_api'); + $this->setCacheTags(array(self::CACHE_TAG)); + + parent::__construct($sourceData); + $this->_construct(); + } + + /** + * Init configuration for webservices api + * + * @return Mage_Api_Model_Config + */ + protected function _construct() + { + if (Mage::app()->useCache('config_api')) { + if ($this->loadCache()) { + return $this; + } + } + + $config = Mage::getConfig()->loadModulesConfiguration('api.xml'); + $this->setXml($config->getNode('api')); + + if (Mage::app()->useCache('config_api')) { + $this->saveCache(); + } + return $this; + } + + /** + * Retrieve adapter aliases from config. + * + * @return array + */ + public function getAdapterAliases() + { + $aliases = array(); + + foreach ($this->getNode('adapter_aliases')->children() as $alias => $adapter) { + $aliases[$alias] = array( + (string) $adapter->suggest_class, // model class name + (string) $adapter->suggest_method // model method name + ); + } + return $aliases; + } + + /** + * Retrieve all adapters + * + * @return array + */ + public function getAdapters() + { + $adapters = array(); + foreach ($this->getNode('adapters')->children() as $adapterName => $adapter) { + /* @var $adapter Varien_SimpleXml_Element */ + if (isset($adapter->use)) { + $adapter = $this->getNode('adapters/' . (string) $adapter->use); + } + $adapters[$adapterName] = $adapter; + } + return $adapters; + } + + /** + * Retrieve active adapters + * + * @return array + */ + public function getActiveAdapters() + { + $adapters = array(); + foreach ($this->getAdapters() as $adapterName => $adapter) { + if (!isset($adapter->active) || $adapter->active == '0') { + continue; + } + + if (isset($adapter->required) && isset($adapter->required->extensions)) { + foreach ($adapter->required->extensions->children() as $extension=>$data) { + if (!extension_loaded($extension)) { + continue; + } + } + } + + $adapters[$adapterName] = $adapter; + } + + return $adapters; + } + + /** + * Retrieve handlers + * + * @return Varien_Simplexml_Element + */ + public function getHandlers() + { + return $this->getNode('handlers')->children(); + } + + /** + * Retrieve resources + * + * @return Varien_Simplexml_Element + */ + public function getResources() + { + return $this->getNode('resources')->children(); + } + + /** + * Retrieve resources alias + * + * @return Varien_Simplexml_Element + */ + public function getResourcesAlias() + { + return $this->getNode('resources_alias')->children(); + } + + + /** + * Load Acl resources from config + * + * @param Mage_Api_Model_Acl $acl + * @param Mage_Core_Model_Config_Element $resource + * @param string $parentName + * @return Mage_Api_Model_Config + */ + public function loadAclResources(Mage_Api_Model_Acl $acl, $resource=null, $parentName=null) + { + $resourceName = null; + if (is_null($resource)) { + $resource = $this->getNode('acl/resources'); + } else { + $resourceName = (is_null($parentName) ? '' : $parentName.'/').$resource->getName(); + $acl->addResource( + Mage::getModel('Mage_Api_Model_Acl_Resource', array('resourceId' => $resourceName)), + $parentName + ); + } + + $children = $resource->children(); + + if (empty($children)) { + return $this; + } + + foreach ($children as $res) { + if ($res->getName() != 'title' && $res->getName() != 'sort_order') { + $this->loadAclResources($acl, $res, $resourceName); + } + } + return $this; + } + + /** + * Get acl assert config + * + * @param string $name + * @return Mage_Core_Model_Config_Element|boolean + */ + public function getAclAssert($name='') + { + $asserts = $this->getNode('acl/asserts'); + if (''===$name) { + return $asserts; + } + + if (isset($asserts->$name)) { + return $asserts->$name; + } + + return false; + } + + /** + * Retrieve privilege set by name + * + * @param string $name + * @return Mage_Core_Model_Config_Element|boolean + */ + public function getAclPrivilegeSet($name='') + { + $sets = $this->getNode('acl/privilegeSets'); + if (''===$name) { + return $sets; + } + + if (isset($sets->$name)) { + return $sets->$name; + } + + return false; + } + + public function getFaults($resourceName=null) + { + if (is_null($resourceName) + || !isset($this->getResources()->$resourceName) + || !isset($this->getResources()->$resourceName->faults)) { + $faultsNode = $this->getNode('faults'); + } else { + $faultsNode = $this->getResources()->$resourceName->faults; + } + /* @var $faultsNode Varien_Simplexml_Element */ + + $translateModule = 'Mage_Api'; + if (isset($faultsNode['module'])) { + $translateModule = (string) $faultsNode['module']; + } + + $faults = array(); + foreach ($faultsNode->children() as $faultName => $fault) { + $faults[$faultName] = array( + 'code' => (string) $fault->code, + 'message' => Mage::helper($translateModule)->__((string)$fault->message) + ); + } + + return $faults; + } + + /** + * Retrieve cache object + * + * @return Zend_Cache_Frontend_File + */ + public function getCache() + { + return Mage::app()->getCache(); + } + + protected function _loadCache($id) + { + return Mage::app()->loadCache($id); + } + + protected function _saveCache($data, $id, $tags=array(), $lifetime=false) + { + return Mage::app()->saveCache($data, $id, $tags, $lifetime); + } + + protected function _removeCache($id) + { + return Mage::app()->removeCache($id); + } +} // Class Mage_Api_Model_Config End diff --git a/app/code/core/Mage/Api/Model/Resource/Abstract.php b/app/code/core/Mage/Api/Model/Resource/Abstract.php new file mode 100644 index 00000000000..30573f5d844 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Abstract.php @@ -0,0 +1,105 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Api resource abstract + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Abstract +{ + + /** + * Resource configuration + * + * @var Varien_Simplexml_Element + */ + protected $_resourceConfig = null; + + /** + * Retrieve webservice session + * + * @return Mage_Api_Model_Session + */ + protected function _getSession() + { + return Mage::getSingleton('Mage_Api_Model_Session'); + } + + /** + * Retrieve webservice configuration + * + * @return Mage_Api_Model_Config + */ + protected function _getConfig() + { + return Mage::getSingleton('Mage_Api_Model_Config'); + } + + /** + * Set configuration for api resource + * + * @param Varien_Simplexml_Element $xml + * @return Mage_Api_Model_Resource_Abstract + */ + public function setResourceConfig(Varien_Simplexml_Element $xml) + { + $this->_resourceConfig = $xml; + return $this; + } + + /** + * Retrieve configuration for api resource + * + * @return Varien_Simplexml_Element + */ + public function getResourceConfig() + { + return $this->_resourceConfig; + } + + /** + * Retrieve webservice server + * + * @return Mage_Api_Model_Server + */ + protected function _getServer() + { + return Mage::getSingleton('Mage_Api_Model_Server'); + } + + /** + * Dispatches fault + * + * @param string $code + */ + protected function _fault($code, $customMessage=null) + { + throw new Mage_Api_Exception($code, $customMessage); + } +} // Class Mage_Api_Model_Resource_Abstract End diff --git a/app/code/core/Mage/Api/Model/Resource/Acl.php b/app/code/core/Mage/Api/Model/Resource/Acl.php new file mode 100755 index 00000000000..afffbc50fd4 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Acl.php @@ -0,0 +1,145 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Resource model for admin ACL + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Acl extends Mage_Core_Model_Resource_Db_Abstract +{ + /** + * Initialize resource connections + * + */ + protected function _construct() + { + $this->_init('api_role', 'role_id'); + } + + /** + * Load ACL for the user + * + * @return Mage_Api_Model_Acl + */ + public function loadAcl() + { + $acl = Mage::getModel('Mage_Api_Model_Acl'); + $adapter = $this->_getReadAdapter(); + + Mage::getSingleton('Mage_Api_Model_Config')->loadAclResources($acl); + + $rolesArr = $adapter->fetchAll( + $adapter->select() + ->from($this->getTable('api_role')) + ->order(array('tree_level', 'role_type')) + ); + $this->loadRoles($acl, $rolesArr); + + $rulesArr = $adapter->fetchAll( + $adapter->select() + ->from(array('r'=>$this->getTable('api_rule'))) + ->joinLeft( + array('a'=>$this->getTable('api_assert')), + 'a.assert_id=r.assert_id', + array('assert_type', 'assert_data') + )); + $this->loadRules($acl, $rulesArr); + return $acl; + } + + /** + * Load roles + * + * @param Mage_Api_Model_Acl $acl + * @param array $rolesArr + * @return Mage_Api_Model_Resource_Acl + */ + public function loadRoles(Mage_Api_Model_Acl $acl, array $rolesArr) + { + foreach ($rolesArr as $role) { + $parent = $role['parent_id']>0 ? Mage_Api_Model_Acl::ROLE_TYPE_GROUP.$role['parent_id'] : null; + switch ($role['role_type']) { + case Mage_Api_Model_Acl::ROLE_TYPE_GROUP: + $roleId = $role['role_type'].$role['role_id']; + $acl->addRole( + Mage::getModel('Mage_Api_Model_Acl_Role_Group', array('roleId' => $roleId)), + $parent + ); + break; + + case Mage_Api_Model_Acl::ROLE_TYPE_USER: + $roleId = $role['role_type'].$role['user_id']; + if (!$acl->hasRole($roleId)) { + $acl->addRole( + Mage::getModel('Mage_Api_Model_Acl_Role_User', array('roleId' => $roleId)), + $parent + ); + } else { + $acl->addRoleParent($roleId, $parent); + } + break; + } + } + + return $this; + } + + /** + * Load rules + * + * @param Mage_Api_Model_Acl $acl + * @param array $rulesArr + * @return Mage_Api_Model_Resource_Acl + */ + public function loadRules(Mage_Api_Model_Acl $acl, array $rulesArr) + { + foreach ($rulesArr as $rule) { + $role = $rule['role_type'].$rule['role_id']; + $resource = $rule['resource_id']; + $privileges = !empty($rule['api_privileges']) ? explode(',', $rule['api_privileges']) : null; + + $assert = null; + if (0!=$rule['assert_id']) { + $assertClass = Mage::getSingleton('Mage_Api_Model_Config')->getAclAssert($rule['assert_type'])->getClassName(); + $assert = new $assertClass(unserialize($rule['assert_data'])); + } + try { + if ($rule['api_permission'] == 'allow') { + $acl->allow($role, $resource, $privileges, $assert); + } else if ($rule['api_permission'] == 'deny') { + $acl->deny($role, $resource, $privileges, $assert); + } + } catch (Exception $e) { + // TODO: properly process exception + } + } + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Acl/Role.php b/app/code/core/Mage/Api/Model/Resource/Acl/Role.php new file mode 100755 index 00000000000..7cb39b0aa1f --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Acl/Role.php @@ -0,0 +1,59 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * ACL role resource + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Acl_Role extends Mage_Core_Model_Resource_Db_Abstract +{ + /** + * Resource initialization + * + */ + protected function _construct() + { + $this->_init('api_role', 'role_id'); + } + + /** + * Action before save + * + * @param Mage_Core_Model_Abstract $object + * @return Mage_Api_Model_Resource_Acl_Role + */ + protected function _beforeSave(Mage_Core_Model_Abstract $object) + { + if (!$object->getId()) { + $this->setCreated(Mage::getSingleton('Mage_Core_Model_Date')->gmtDate()); + } + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Acl/Role/Collection.php b/app/code/core/Mage/Api/Model/Resource/Acl/Role/Collection.php new file mode 100755 index 00000000000..9eb406b78b2 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Acl/Role/Collection.php @@ -0,0 +1,45 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Acl Role Resource Collection + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Acl_Role_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +{ + /** + * Resource collection initialization + * + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_Role', 'Mage_Api_Model_Resource_Role'); + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Permissions/Collection.php b/app/code/core/Mage/Api/Model/Resource/Permissions/Collection.php new file mode 100755 index 00000000000..b637787a41f --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Permissions/Collection.php @@ -0,0 +1,45 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Permissions Resource Collection + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Permissions_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +{ + /** + * Resource collection initialization + * + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_Rules', 'Mage_Api_Model_Resource_Rules'); + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Role.php b/app/code/core/Mage/Api/Model/Resource/Role.php new file mode 100755 index 00000000000..6a7e0154d92 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Role.php @@ -0,0 +1,76 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * ACL role resource + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Role extends Mage_Core_Model_Resource_Db_Abstract +{ + /** + * Resource initialization + * + */ + protected function _construct() + { + $this->_init('api_role', 'role_id'); + } + + /** + * Action before save + * + * @param Mage_Core_Model_Abstract $object + * @return Mage_Api_Model_Resource_Role + */ + protected function _beforeSave(Mage_Core_Model_Abstract $object) + { + if (!$object->getId()) { + $object->setCreated(now()); + } + $object->setModified(now()); + return $this; + } + + /** + * Load an object + * + * @param Mage_Core_Model_Abstract $object + * @param mixed $value + * @param string $field field to load by (defaults to model id) + * @return Mage_Core_Model_Resource_Db_Abstract + */ + public function load(Mage_Core_Model_Abstract $object, $value, $field = null) + { + if (!intval($value) && is_string($value)) { + $field = 'role_id'; + } + return parent::load($object, $value, $field); + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Role/Collection.php b/app/code/core/Mage/Api/Model/Resource/Role/Collection.php new file mode 100755 index 00000000000..7af32b391cf --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Role/Collection.php @@ -0,0 +1,69 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Api Role Resource Collection + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Role_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +{ + /** + * Resource collection initialization + * + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_Role', 'Mage_Api_Model_Resource_Role'); + } + + /** + * Aet user filter + * + * @param int $userId + * @return Mage_Api_Model_Resource_Role_Collection + */ + public function setUserFilter($userId) + { + $this->addFieldToFilter('user_id', $userId); + $this->addFieldToFilter('role_type', Mage_Api_Model_Acl::ROLE_TYPE_GROUP); + return $this; + } + + /** + * Set roles filter + * + * @return Mage_Api_Model_Resource_Role_Collection + */ + public function setRolesFilter() + { + $this->addFieldToFilter('role_type', Mage_Api_Model_Acl::ROLE_TYPE_GROUP); + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Roles.php b/app/code/core/Mage/Api/Model/Resource/Roles.php new file mode 100755 index 00000000000..9676fe097a5 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Roles.php @@ -0,0 +1,151 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * ACL roles resource + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Roles extends Mage_Core_Model_Resource_Db_Abstract +{ + /** + * User table name + * + * @var unknown + */ + protected $_usersTable; + + /** + * Rule table name + * + * @var unknown + */ + protected $_ruleTable; + + /** + * Resource initialization + * + */ + protected function _construct() + { + $this->_init('api_role', 'role_id'); + + $this->_usersTable = $this->getTable('api_user'); + $this->_ruleTable = $this->getTable('api_rule'); + } + + /** + * Action before save + * + * @param Mage_Core_Model_Abstract $role + * @return Mage_Api_Model_Resource_Roles + */ + protected function _beforeSave(Mage_Core_Model_Abstract $role) + { + if ($role->getId() == '') { + if ($role->getIdFieldName()) { + $role->unsetData($role->getIdFieldName()); + } else { + $role->unsetData('id'); + } + } + + if ($role->getPid() > 0) { + $row = $this->load($role->getPid()); + } else { + $row = array('tree_level' => 0); + } + $role->setTreeLevel($row['tree_level'] + 1); + $role->setRoleName($role->getName()); + return $this; + } + + /** + * Action after save + * + * @param Mage_Core_Model_Abstract $role + * @return Mage_Api_Model_Resource_Roles + */ + protected function _afterSave(Mage_Core_Model_Abstract $role) + { + $this->_updateRoleUsersAcl($role); + Mage::app()->getCache()->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG); + return $this; + } + + /** + * Action after delete + * + * @param Mage_Core_Model_Abstract $role + * @return Mage_Api_Model_Resource_Roles + */ + protected function _afterDelete(Mage_Core_Model_Abstract $role) + { + $adapter = $this->_getWriteAdapter(); + $adapter->delete($this->getMainTable(), array('parent_id=?'=>$role->getId())); + $adapter->delete($this->_ruleTable, array('role_id=?'=>$role->getId())); + return $this; + } + + /** + * Get role users + * + * @param Mage_Api_Model_Roles $role + * @return unknown + */ + public function getRoleUsers(Mage_Api_Model_Roles $role) + { + $adapter = $this->_getReadAdapter(); + $select = $adapter->select() + ->from($this->getMainTable(), array('user_id')) + ->where('parent_id = ?', $role->getId()) + ->where('role_type = ?', Mage_Api_Model_Acl::ROLE_TYPE_USER) + ->where('user_id > 0'); + return $adapter->fetchCol($select); + } + + /** + * Update role users + * + * @param Mage_Api_Model_Roles $role + * @return boolean + */ + private function _updateRoleUsersAcl(Mage_Api_Model_Roles $role) + { + $users = $this->getRoleUsers($role); + $rowsCount = 0; + if (sizeof($users) > 0) { + $rowsCount = $this->_getWriteAdapter()->update( + $this->_usersTable, + array('reload_acl_flag' => 1), + array('user_id IN(?)' => $users)); + } + return ($rowsCount > 0) ? true : false; + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Roles/Collection.php b/app/code/core/Mage/Api/Model/Resource/Roles/Collection.php new file mode 100755 index 00000000000..b302d527928 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Roles/Collection.php @@ -0,0 +1,67 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Api Roles Resource Collection + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Roles_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +{ + /** + * Resource collection initialization + * + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_Role', 'Mage_Api_Model_Resource_Role'); + } + + /** + * Convert items array to array for select options + * + * @return array + */ + public function toOptionArray() + { + return $this->_toOptionArray('role_id', 'role_name'); + } + + /** + * Init collection select + * + * @return Mage_Api_Model_Resource_Roles_Collection + */ + protected function _initSelect() + { + parent::_initSelect(); + $this->getSelect()->where('main_table.role_type = ?', Mage_Api_Model_Acl::ROLE_TYPE_GROUP); + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Roles/User/Collection.php b/app/code/core/Mage/Api/Model/Resource/Roles/User/Collection.php new file mode 100755 index 00000000000..9349e9a6b9a --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Roles/User/Collection.php @@ -0,0 +1,59 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Roles User Resource Collection + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Roles_User_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +{ + /** + * Resource collection initialization + * + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_User', 'Mage_Api_Model_Resource_User'); + } + + /** + * Init collection select + * + * @return Mage_Api_Model_Resource_Roles_User_Collection + */ + protected function _initSelect() + { + parent::_initSelect(); + + $this->getSelect()->where("user_id > 0"); + + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Rules.php b/app/code/core/Mage/Api/Model/Resource/Rules.php new file mode 100755 index 00000000000..7756864fe32 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Rules.php @@ -0,0 +1,87 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Rules resource model + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Rules extends Mage_Core_Model_Resource_Db_Abstract +{ + /** + * Resource initialization + * + */ + protected function _construct() + { + $this->_init('api_rule', 'rule_id'); + } + + /** + * Save rule + * + * @param Mage_Api_Model_Rules $rule + */ + public function saveRel(Mage_Api_Model_Rules $rule) + { + $adapter = $this->_getWriteAdapter(); + $adapter->beginTransaction(); + + try { + $roleId = $rule->getRoleId(); + $adapter->delete($this->getMainTable(), array('role_id = ?' => $roleId)); + $masterResources = Mage::getModel('Mage_Api_Model_Roles')->getResourcesList2D(); + $masterAdmin = false; + if ($postedResources = $rule->getResources()) { + foreach ($masterResources as $index => $resName) { + if (!$masterAdmin) { + $permission = (in_array($resName, $postedResources))? 'allow' : 'deny'; + $adapter->insert($this->getMainTable(), array( + 'role_type' => 'G', + 'resource_id' => trim($resName, '/'), + 'api_privileges' => null, + 'assert_id' => 0, + 'role_id' => $roleId, + 'api_permission' => $permission + )); + } + if ($resName == 'all' && $permission == 'allow') { + $masterAdmin = true; + } + } + } + + $adapter->commit(); + } catch (Mage_Core_Exception $e) { + throw $e; + } catch (Exception $e) { + $adapter->rollBack(); + } + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/Rules/Collection.php b/app/code/core/Mage/Api/Model/Resource/Rules/Collection.php new file mode 100755 index 00000000000..9c13b1f73ea --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/Rules/Collection.php @@ -0,0 +1,69 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Api Rules Resource Collection + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_Rules_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +{ + /** + * Resource collection initialization + * + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_Rules', 'Mage_Api_Model_Resource_Rules'); + } + + /** + * Retrieve rules by role + * + * @param int $id + * @return Mage_Api_Model_Resource_Rules_Collection + */ + public function getByRoles($id) + { + $this->getSelect()->where("role_id = ?", (int)$id); + return $this; + } + + /** + * Add sort by length + * + * @return Mage_Api_Model_Resource_Rules_Collection + */ + public function addSortByLength() + { + $this->getSelect()->columns(array('length' => $this->getConnection()->getLengthSql('resource_id'))) + ->order('length DESC'); + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/User.php b/app/code/core/Mage/Api/Model/Resource/User.php new file mode 100755 index 00000000000..811d1cce262 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/User.php @@ -0,0 +1,435 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * ACL user resource + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_User extends Mage_Core_Model_Resource_Db_Abstract +{ + /** + * Resource initialization + * + */ + protected function _construct() + { + $this->_init('api_user', 'user_id'); + } + + /** + * Initialize unique fields + * + * @return Mage_Api_Model_Resource_User + */ + protected function _initUniqueFields() + { + $this->_uniqueFields = array( + array( + 'field' => 'email', + 'title' => Mage::helper('Mage_Api_Helper_Data')->__('Email') + ), + array( + 'field' => 'username', + 'title' => Mage::helper('Mage_Api_Helper_Data')->__('User Name') + ), + ); + return $this; + } + + /** + * Authenticate user by $username and $password + * + * @param Mage_Api_Model_User $user + * @return Mage_Api_Model_Resource_User + */ + public function recordLogin(Mage_Api_Model_User $user) + { + $data = array( + 'lognum' => $user->getLognum()+1, + ); + $condition = $this->_getReadAdapter()->quoteInto('user_id=?', $user->getUserId()); + $this->_getWriteAdapter()->update($this->getTable('api_user'), $data, $condition); + return $this; + } + + /** + * Record api user session + * + * @param Mage_Api_Model_User $user + * @return Mage_Api_Model_Resource_User + */ + public function recordSession(Mage_Api_Model_User $user) + { + $readAdapter = $this->_getReadAdapter(); + $writeAdapter = $this->_getWriteAdapter(); + $select = $readAdapter->select() + ->from($this->getTable('api_session'), 'user_id') + ->where('user_id = ?', $user->getId()) + ->where('sessid = ?', $user->getSessid()); + $loginDate = now(); + if ($readAdapter->fetchRow($select)) { + $writeAdapter->update( + $this->getTable('api_session'), + array ('logdate' => $loginDate), + $readAdapter->quoteInto('user_id = ?', $user->getId()) . ' AND ' + . $readAdapter->quoteInto('sessid = ?', $user->getSessid()) + ); + } else { + $writeAdapter->insert( + $this->getTable('api_session'), + array( + 'user_id' => $user->getId(), + 'logdate' => $loginDate, + 'sessid' => $user->getSessid() + ) + ); + } + $user->setLogdate($loginDate); + return $this; + } + + /** + * Clean old session + * + * @param Mage_Api_Model_User $user + * @return Mage_Api_Model_Resource_User + */ + public function cleanOldSessions(Mage_Api_Model_User $user) + { + $readAdapter = $this->_getReadAdapter(); + $writeAdapter = $this->_getWriteAdapter(); + $timeout = Mage::getStoreConfig('api/config/session_timeout'); + $timeSubtract = $readAdapter->getDateAddSql( + 'logdate', + $timeout, + Varien_Db_Adapter_Interface::INTERVAL_SECOND); + $writeAdapter->delete( + $this->getTable('api_session'), + array('user_id = ?' => $user->getId(), $readAdapter->quote(now()) . ' > '.$timeSubtract) + ); + return $this; + } + + /** + * Load data by username + * + * @param string $username + * @return array + */ + public function loadByUsername($username) + { + $adapter = $this->_getReadAdapter(); + $select = $adapter->select()->from($this->getTable('api_user')) + ->where('username=:username'); + return $adapter->fetchRow($select, array('username'=>$username)); + } + + /** + * load by session id + * + * @param string $sessId + * @return array + */ + public function loadBySessId($sessId) + { + $result = array(); + $adapter = $this->_getReadAdapter(); + $select = $adapter->select() + ->from($this->getTable('api_session')) + ->where('sessid = ?', $sessId); + if ($apiSession = $adapter->fetchRow($select)) { + $selectUser = $adapter->select() + ->from($this->getTable('api_user')) + ->where('user_id = ?', $apiSession['user_id']); + if ($user = $adapter->fetchRow($selectUser)) { + $result = array_merge($user, $apiSession); + } + } + return $result; + } + + /** + * Clear by session + * + * @param string $sessid + * @return Mage_Api_Model_Resource_User + */ + public function clearBySessId($sessid) + { + $this->_getWriteAdapter()->delete( + $this->getTable('api_session'), + array('sessid = ?' => $sessid) + ); + return $this; + } + + /** + * Retrieve api user role data if it was assigned to role + * + * @param int | Mage_Api_Model_User $user + * @return null | array + */ + public function hasAssigned2Role($user) + { + $userId = null; + $result = null; + if (is_numeric($user)) { + $userId = $user; + } else if ($user instanceof Mage_Core_Model_Abstract) { + $userId = $user->getUserId(); + } + + if ($userId) { + $adapter = $this->_getReadAdapter(); + $select = $adapter->select(); + $select->from($this->getTable('api_role')) + ->where('parent_id > 0 AND user_id = ?', $userId); + $result = $adapter->fetchAll($select); + } + return $result; + } + + /** + * Action before save + * + * @param Mage_Core_Model_Abstract $user + * @return Mage_Api_Model_Resource_User + */ + protected function _beforeSave(Mage_Core_Model_Abstract $user) + { + if (!$user->getId()) { + $user->setCreated(now()); + } + $user->setModified(now()); + return $this; + } + + /** + * Delete the object + * + * @param Mage_Core_Model_Abstract $user + * @return boolean + */ + public function delete(Mage_Core_Model_Abstract $user) + { + $dbh = $this->_getWriteAdapter(); + $uid = (int) $user->getId(); + $dbh->beginTransaction(); + try { + $dbh->delete($this->getTable('api_user'), array('user_id = ?' => $uid)); + $dbh->delete($this->getTable('api_role'), array('user_id = ?' => $uid)); + } catch (Mage_Core_Exception $e) { + throw $e; + return false; + } catch (Exception $e) { + $dbh->rollBack(); + return false; + } + $dbh->commit(); + return true; + } + + /** + * Save user roles + * + * @param Mage_Core_Model_Abstract $user + * @return unknown + */ + public function _saveRelations(Mage_Core_Model_Abstract $user) + { + $rolesIds = $user->getRoleIds(); + if (!is_array($rolesIds) || count($rolesIds) == 0) { + return $user; + } + + $adapter = $this->_getWriteAdapter(); + + $adapter->beginTransaction(); + + try { + $adapter->delete( + $this->getTable('api_role'), + array('user_id = ?' => (int) $user->getId())); + foreach ($rolesIds as $rid) { + $rid = intval($rid); + if ($rid > 0) { + //$row = $this->load($user, $rid); + } else { + $row = array('tree_level' => 0); + } + $row = array('tree_level' => 0); + + $data = array( + 'parent_id' => $rid, + 'tree_level' => $row['tree_level'] + 1, + 'sort_order' => 0, + 'role_type' => Mage_Api_Model_Acl::ROLE_TYPE_USER, + 'user_id' => $user->getId(), + 'role_name' => $user->getFirstname() + ); + $adapter->insert($this->getTable('api_role'), $data); + } + $adapter->commit(); + } catch (Mage_Core_Exception $e) { + throw $e; + } catch (Exception $e) { + $adapter->rollBack(); + } + return $this; + } + + /** + * Retrieve roles data + * + * @param Mage_Core_Model_Abstract $user + * @return array + */ + public function _getRoles(Mage_Core_Model_Abstract $user) + { + if (!$user->getId()) { + return array(); + } + $table = $this->getTable('api_role'); + $adapter = $this->_getReadAdapter(); + $select = $adapter->select() + ->from($table, array()) + ->joinLeft( + array('ar' => $table), + $adapter->quoteInto( + "ar.role_id = {$table}.parent_id AND ar.role_type = ?", + Mage_Api_Model_Acl::ROLE_TYPE_GROUP), + array('role_id')) + ->where("{$table}.user_id = ?", $user->getId()); + + return (($roles = $adapter->fetchCol($select)) ? $roles : array()); + } + + /** + * Add Role + * + * @param Mage_Core_Model_Abstract $user + * @return Mage_Api_Model_Resource_User + */ + public function add(Mage_Core_Model_Abstract $user) + { + $adapter = $this->_getWriteAdapter(); + $aRoles = $this->hasAssigned2Role($user); + if (sizeof($aRoles) > 0) { + foreach ($aRoles as $idx => $data) { + $adapter->delete( + $this->getTable('api_role'), + array('role_id = ?' => $data['role_id']) + ); + } + } + + if ($user->getId() > 0) { + $role = Mage::getModel('Mage_Api_Model_Role')->load($user->getRoleId()); + } else { + $role = new Varien_Object(array('tree_level' => 0)); + } + $adapter->insert($this->getTable('api_role'), array( + 'parent_id' => $user->getRoleId(), + 'tree_level'=> ($role->getTreeLevel() + 1), + 'sort_order'=> 0, + 'role_type' => Mage_Api_Model_Acl::ROLE_TYPE_USER, + 'user_id' => $user->getUserId(), + 'role_name' => $user->getFirstname() + )); + + return $this; + } + + /** + * Delete from role + * + * @param Mage_Core_Model_Abstract $user + * @return Mage_Api_Model_Resource_User + */ + public function deleteFromRole(Mage_Core_Model_Abstract $user) + { + if ($user->getUserId() <= 0) { + return $this; + } + if ($user->getRoleId() <= 0) { + return $this; + }; + + $adapter = $this->_getWriteAdapter(); + $table = $this->getTable('api_role'); + + $condition = array( + "{$table}.user_id = ?" => $user->getUserId(), + "{$table}.parent_id = ?"=> $user->getRoleId() + ); + $adapter->delete($table, $condition); + return $this; + } + + /** + * Retrieve roles which exists for user + * + * @param Mage_Core_Model_Abstract $user + * @return array + */ + public function roleUserExists(Mage_Core_Model_Abstract $user) + { + $result = array(); + if ($user->getUserId() > 0) { + $adapter = $this->_getReadAdapter(); + $select = $adapter->select()->from($this->getTable('api_role')) + ->where('parent_id = ?', $user->getRoleId()) + ->where('user_id = ?', $user->getUserId()); + $result = $adapter->fetchCol($select); + } + return $result; + } + + /** + * Check if user not unique + * + * @param Mage_Core_Model_Abstract $user + * @return array + */ + public function userExists(Mage_Core_Model_Abstract $user) + { + $usersTable = $this->getTable('api_user'); + $adapter = $this->_getReadAdapter(); + $condition = array( + $adapter->quoteInto("{$usersTable}.username = ?", $user->getUsername()), + $adapter->quoteInto("{$usersTable}.email = ?", $user->getEmail()), + ); + $select = $adapter->select() + ->from($usersTable) + ->where(implode(' OR ', $condition)) + ->where($usersTable.'.user_id != ?', (int) $user->getId()); + return $adapter->fetchRow($select); + } +} diff --git a/app/code/core/Mage/Api/Model/Resource/User/Collection.php b/app/code/core/Mage/Api/Model/Resource/User/Collection.php new file mode 100755 index 00000000000..50459268f5e --- /dev/null +++ b/app/code/core/Mage/Api/Model/Resource/User/Collection.php @@ -0,0 +1,45 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Api User Resource Collection + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Resource_User_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +{ + /** + * Resource collection initialization + * + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_User', 'Mage_Api_Model_Resource_User'); + } +} diff --git a/app/code/core/Mage/Api/Model/Role.php b/app/code/core/Mage/Api/Model/Role.php new file mode 100644 index 00000000000..7363ffc260e --- /dev/null +++ b/app/code/core/Mage/Api/Model/Role.php @@ -0,0 +1,58 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Role item model + * + * @method Mage_Api_Model_Resource_Role _getResource() + * @method Mage_Api_Model_Resource_Role getResource() + * @method int getParentId() + * @method Mage_Api_Model_Role setParentId(int $value) + * @method int getTreeLevel() + * @method Mage_Api_Model_Role setTreeLevel(int $value) + * @method int getSortOrder() + * @method Mage_Api_Model_Role setSortOrder(int $value) + * @method string getRoleType() + * @method Mage_Api_Model_Role setRoleType(string $value) + * @method int getUserId() + * @method Mage_Api_Model_Role setUserId(int $value) + * @method string getRoleName() + * @method Mage_Api_Model_Role setRoleName(string $value) + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Role extends Mage_Core_Model_Abstract +{ + /** + * Initialize resource + */ + protected function _construct() + { + $this->_init('Mage_Api_Model_Resource_Role'); + } +} diff --git a/app/code/core/Mage/Api/Model/Roles.php b/app/code/core/Mage/Api/Model/Roles.php new file mode 100644 index 00000000000..6af4054c984 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Roles.php @@ -0,0 +1,181 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Enter description here ... + * + * @method Mage_Api_Model_Resource_Roles _getResource() + * @method Mage_Api_Model_Resource_Roles getResource() + * @method int getParentId() + * @method Mage_Api_Model_Roles setParentId(int $value) + * @method int getTreeLevel() + * @method Mage_Api_Model_Roles setTreeLevel(int $value) + * @method int getSortOrder() + * @method Mage_Api_Model_Roles setSortOrder(int $value) + * @method string getRoleType() + * @method Mage_Api_Model_Roles setRoleType(string $value) + * @method int getUserId() + * @method Mage_Api_Model_Roles setUserId(int $value) + * @method string getRoleName() + * @method Mage_Api_Model_Roles setRoleName(string $value) + * @method string getName() + * @method Mage_Api_Model_Role setName() setName(string $name) + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Roles extends Mage_Core_Model_Abstract +{ + /** + * Filters + * + * @var array + */ + protected $_filters; + + + protected function _construct() + { + $this->_init('Mage_Api_Model_Resource_Roles'); + } + + public function update() + { + $this->getResource()->update($this); + return $this; + } + + public function getUsersCollection() + { + return Mage::getResourceModel('Mage_Api_Model_Resource_Roles_User_Collection'); + } + + public function getResourcesTree() + { + return $this->_buildResourcesArray(null, null, null, null, true); + } + + public function getResourcesList() + { + return $this->_buildResourcesArray(); + } + + public function getResourcesList2D() + { + return $this->_buildResourcesArray(null, null, null, true); + } + + public function getRoleUsers() + { + return $this->getResource()->getRoleUsers($this); + } + + protected function _buildResourcesArray( + Varien_Simplexml_Element $resource = null, $parentName = null, $level = 0, $represent2Darray = null, + $rawNodes = false, $module = 'Mage_Adminhtml' + ) { + static $result; + + if (is_null($resource)) { + $resource = Mage::getSingleton('Mage_Api_Model_Config')->getNode('acl/resources'); + $resourceName = null; + $level = -1; + } else { + $resourceName = $parentName; + if ($resource->getName()!='title' && $resource->getName()!='sort_order' + && $resource->getName() != 'children' + ) { + $resourceName = (is_null($parentName) ? '' : $parentName.'/').$resource->getName(); + + //assigning module for its' children nodes + if ($resource->getAttribute('module')) { + $module = (string)$resource->getAttribute('module'); + } + + if ($rawNodes) { + $resource->addAttribute("aclpath", $resourceName); + } + + $resource->title = Mage::helper($module)->__((string)$resource->title); + + if ( is_null($represent2Darray) ) { + $result[$resourceName]['name'] = (string)$resource->title; + $result[$resourceName]['level'] = $level; + } else { + $result[] = $resourceName; + } + } + } + + $children = $resource->children(); + if (empty($children)) { + if ($rawNodes) { + return $resource; + } else { + return $result; + } + } + foreach ($children as $child) { + $this->_buildResourcesArray($child, $resourceName, $level+1, $represent2Darray, $rawNodes, $module); + } + if ($rawNodes) { + return $resource; + } else { + return $result; + } + } + + /** + * Filter data before save + * + * @return Mage_Api_Model_Roles + */ + protected function _beforeSave() + { + $this->filter(); + parent::_beforeSave(); + return $this; + } + + /** + * Filter set data + * + * @return Mage_Api_Model_Roles + */ + public function filter() + { + $data = $this->getData(); + if (!$this->_filters || !$data) { + return $this; + } + /** @var $filter Mage_Core_Model_Input_Filter */ + $filter = Mage::getModel('Mage_Core_Model_Input_Filter'); + $filter->setFilters($this->_filters); + $this->setData($filter->filter($data)); + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Rules.php b/app/code/core/Mage/Api/Model/Rules.php new file mode 100644 index 00000000000..fd3f412e84e --- /dev/null +++ b/app/code/core/Mage/Api/Model/Rules.php @@ -0,0 +1,69 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Enter description here ... + * + * @method Mage_Api_Model_Resource_Rules _getResource() + * @method Mage_Api_Model_Resource_Rules getResource() + * @method int getRoleId() + * @method Mage_Api_Model_Rules setRoleId(int $value) + * @method string getResourceId() + * @method Mage_Api_Model_Rules setResourceId(string $value) + * @method string getPrivileges() + * @method Mage_Api_Model_Rules setPrivileges(string $value) + * @method int getAssertId() + * @method Mage_Api_Model_Rules setAssertId(int $value) + * @method string getRoleType() + * @method Mage_Api_Model_Rules setRoleType(string $value) + * @method string getPermission() + * @method Mage_Api_Model_Rules setPermission(string $value) + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Rules extends Mage_Core_Model_Abstract +{ + protected function _construct() + { + $this->_init('Mage_Api_Model_Resource_Rules'); + } + + public function update() { + $this->getResource()->update($this); + return $this; + } + + public function getCollection() { + return Mage::getResourceModel('Mage_Api_Model_Resource_Permissions_Collection'); + } + + public function saveRel() { + $this->getResource()->saveRel($this); + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Server.php b/app/code/core/Mage/Api/Model/Server.php new file mode 100644 index 00000000000..b3859b94d1e --- /dev/null +++ b/app/code/core/Mage/Api/Model/Server.php @@ -0,0 +1,161 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Webservice api abstract + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Server +{ + + /** + * Api Name by Adapter + * @var string + */ + protected $_api = ""; + + /** + * Web service adapter + * + * @var Mage_Api_Model_Server_Adapter_Soap + */ + protected $_adapter; + + /** + * Complex retrieve adapter code by calling auxiliary model method + * + * @param string $alias Alias name + * @return string|null Returns NULL if no alias found + */ + public function getAdapterCodeByAlias($alias) + { + /** @var $config Mage_Api_Model_Config */ + $config = Mage::getSingleton('Mage_Api_Model_Config'); + $aliases = $config->getAdapterAliases(); + + if (!isset($aliases[$alias])) { + return null; + } + $object = Mage::getModel($aliases[$alias][0]); + $method = $aliases[$alias][1]; + + if (!method_exists($object, $method)) { + Mage::throwException(Mage::helper('Mage_Api_Helper_Data')->__('Can not find webservice adapter.')); + } + return $object->$method(); + } + + /** + * Initialize server components + * + * @param Mage_Api_Controller_Action $controller + * @param string $adapter Adapter name + * @param string $handler Handler name + * @return Mage_Api_Model_Server + */ + public function init(Mage_Api_Controller_Action $controller, $adapter = 'default', $handler = 'default') + { + $this->initialize($adapter, $handler); + + $this->_adapter->setController($controller); + + return $this; + } + + /** + * Initialize server components. Lightweight implementation of init() method + * + * @param string $adapterCode Adapter code + * @param string $handler OPTIONAL Handler name (if not specified, it will be found from config) + * @return Mage_Api_Model_Server + */ + public function initialize($adapterCode, $handler = null) + { + /** @var $helper Mage_Api_Model_Config */ + $helper = Mage::getSingleton('Mage_Api_Model_Config'); + $adapters = $helper->getActiveAdapters(); + + if (isset($adapters[$adapterCode])) { + /** @var $adapterModel Mage_Api_Model_Server_Adapter_Soap */ + $adapterModel = Mage::getModel((string) $adapters[$adapterCode]->model); + + if (!($adapterModel instanceof Mage_Api_Model_Server_Adapter_Soap)) { + Mage::throwException(Mage::helper('Mage_Api_Helper_Data')->__('Invalid webservice adapter specified.')); + } + $this->_adapter = $adapterModel; + $this->_api = $adapterCode; + + // get handler code from config if no handler passed as argument + if (null === $handler && !empty($adapters[$adapterCode]->handler)) { + $handler = (string) $adapters[$adapterCode]->handler; + } + $handlers = $helper->getHandlers(); + + if (!isset($handlers->$handler)) { + Mage::throwException(Mage::helper('Mage_Api_Helper_Data')->__('Invalid webservice handler specified.')); + } + $handlerClassName = Mage::getConfig()->getModelClassName((string) $handlers->$handler->model); + + $this->_adapter->setHandler($handlerClassName); + } else { + Mage::throwException(Mage::helper('Mage_Api_Helper_Data')->__('Invalid webservice adapter specified.')); + } + return $this; + } + + /** + * Run server + * + */ + public function run() + { + $this->getAdapter()->run(); + } + + /** + * Get Api name by Adapter + * @return string + */ + public function getApiName() + { + return $this->_api; + } + + /** + * Retrieve web service adapter + * + * @return Mage_Api_Model_Server_Adapter_Soap + */ + public function getAdapter() + { + return $this->_adapter; + } + + +} // Class Mage_Api_Model_Server_Abstract End diff --git a/app/code/core/Mage/Api/Model/Server/Adapter/Soap.php b/app/code/core/Mage/Api/Model/Server/Adapter/Soap.php new file mode 100644 index 00000000000..58649ff834f --- /dev/null +++ b/app/code/core/Mage/Api/Model/Server/Adapter/Soap.php @@ -0,0 +1,241 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * SOAP adapter. + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Server_Adapter_Soap extends Varien_Object +{ + /** + * Soap server + * + * @var SoapServer + */ + protected $_soap = null; + + /** + * Set handler class name for webservice + * + * @param string $handler + * @return Mage_Api_Model_Server_Adapter_Soap + */ + public function setHandler($handler) + { + $this->setData('handler', $handler); + return $this; + } + + /** + * Retrive handler class name for webservice + * + * @return string + */ + public function getHandler() + { + return $this->getData('handler'); + } + + /** + * Set webservice api controller + * + * @param Mage_Api_Controller_Action $controller + * @return Mage_Api_Model_Server_Adapter_Soap + */ + public function setController(Mage_Api_Controller_Action $controller) + { + $this->setData('controller', $controller); + return $this; + } + + /** + * Retrive webservice api controller. If no controller have been set - emulate it by the use of Varien_Object + * + * @return Mage_Api_Controller_Action|Varien_Object + */ + public function getController() + { + $controller = $this->getData('controller'); + + if (null === $controller) { + $controller = new Varien_Object( + array('request' => Mage::app()->getRequest(), 'response' => Mage::app()->getResponse()) + ); + + $this->setData('controller', $controller); + } + return $controller; + } + + public function run() + { + $apiConfigCharset = Mage::getStoreConfig("api/config/charset"); + + if ($this->getController()->getRequest()->getParam('wsdl') !== null) { + $wsdlConfig = Mage::getModel('Mage_Api_Model_Wsdl_Config'); + $wsdlConfig->setHandler($this->getHandler()) + ->setCacheId('wsdl_config_global_soap') + ->init(); + $this->getController()->getResponse() + ->clearHeaders() + ->setHeader('Content-Type', 'text/xml; charset=' . $apiConfigCharset) + ->setBody( + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '<?xml version="$1" encoding="' . $apiConfigCharset . '"?>', + $wsdlConfig->getWsdlContent() + ) + ); + } else { + try { + $this->_instantiateServer(); + + $this->getController()->getResponse() + ->clearHeaders() + ->setHeader('Content-Type', 'text/xml; charset=' . $apiConfigCharset) + ->setBody( + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '<?xml version="$1" encoding="' . $apiConfigCharset . '"?>', + $this->_soap->handle() + ) + ); + } catch (Zend_Soap_Server_Exception $e) { + $this->fault($e->getCode(), $e->getMessage()); + } catch (Exception $e) { + $this->fault($e->getCode(), $e->getMessage()); + } + } + + return $this; + } + + /** + * Dispatch webservice fault + * + * @param int $code + * @param string $message + */ + public function fault($code, $message) + { + if ($this->_extensionLoaded()) { + throw new SoapFault($code, $message); + } else { + die('<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> + <SOAP-ENV:Body> + <SOAP-ENV:Fault> + <faultcode>' . $code . '</faultcode> + <faultstring>' . $message . '</faultstring> + </SOAP-ENV:Fault> + </SOAP-ENV:Body> + </SOAP-ENV:Envelope>'); + } + + } + + /** + * Check whether Soap extension is loaded + * + * @return boolean + */ + protected function _extensionLoaded() + { + return class_exists('SoapServer', false); + } + + /** + * Transform wsdl url if $_SERVER["PHP_AUTH_USER"] is set + * + * @param array + * @return String + */ + protected function getWsdlUrl($params = null, $withAuth = true) + { + $urlModel = Mage::getModel('Mage_Core_Model_Url') + ->setUseSession(false); + + $wsdlUrl = $params !== null + ? $urlModel->getUrl('*/*/*', array('_current' => true, '_query' => $params)) + : $urlModel->getUrl('*/*/*'); + + if ($withAuth) { + $phpAuthUser = urlencode($this->getController()->getRequest()->getServer('PHP_AUTH_USER', false)); + $phpAuthPw = urlencode($this->getController()->getRequest()->getServer('PHP_AUTH_PW', false)); + + if ($phpAuthUser && $phpAuthPw) { + $wsdlUrl = sprintf("http://%s:%s@%s", $phpAuthUser, $phpAuthPw, str_replace('http://', '', $wsdlUrl)); + } + } + + return $wsdlUrl; + } + + /** + * Try to instantiate Zend_Soap_Server + * If schema import error is caught, it will retry in 1 second. + * + * @throws Zend_Soap_Server_Exception + */ + protected function _instantiateServer() + { + $apiConfigCharset = Mage::getStoreConfig('api/config/charset'); + $wsdlCacheEnabled = (bool)Mage::getStoreConfig('api/config/wsdl_cache_enabled'); + + if ($wsdlCacheEnabled) { + ini_set('soap.wsdl_cache_enabled', '1'); + } else { + ini_set('soap.wsdl_cache_enabled', '0'); + } + + $tries = 0; + do { + $retry = false; + try { + $this->_soap = new \Zend\Soap\Server($this->getWsdlUrl(array("wsdl" => 1)), + array('encoding' => $apiConfigCharset)); + } catch (SoapFault $e) { + if (false !== strpos( + $e->getMessage(), + "can't import schema from 'http://schemas.xmlsoap.org/soap/encoding/'" + ) + ) { + $retry = true; + sleep(1); + } else { + throw $e; + } + $tries++; + } + } while ($retry && $tries < 5); + use_soap_error_handler(false); + $this->_soap + ->setReturnResponse(true) + ->setClass($this->getHandler()); + } +} diff --git a/app/code/core/Mage/Api/Model/Server/Adapter/Soap/Wsi.php b/app/code/core/Mage/Api/Model/Server/Adapter/Soap/Wsi.php new file mode 100644 index 00000000000..d3d62dca236 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Server/Adapter/Soap/Wsi.php @@ -0,0 +1,104 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * SOAP WS-I compatible adapter + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Server_Adapter_Soap_Wsi extends Mage_Api_Model_Server_Adapter_Soap +{ + /** + * Run webservice + * + * @param Mage_Api_Controller_Action $controller + * @return Mage_Api_Model_Server_Adapter_Soap + */ + public function run() + { + $apiConfigCharset = Mage::getStoreConfig("api/config/charset"); + + if ($this->getController()->getRequest()->getParam('wsdl') !== null) { + $wsdlConfig = Mage::getModel('Mage_Api_Model_Wsdl_Config'); + $wsdlConfig->setHandler($this->getHandler()) + ->setCacheId('wsdl_config_global_soap_wsi') + ->init(); + $this->getController()->getResponse() + ->clearHeaders() + ->setHeader('Content-Type', 'text/xml; charset=' . $apiConfigCharset) + ->setBody( + preg_replace( + '/(\>\<)/i', + ">\n<", + str_replace( + '<soap:operation soapAction=""></soap:operation>', + "<soap:operation soapAction=\"\" />\n", + str_replace( + '<soap:body use="literal"></soap:body>', + "<soap:body use=\"literal\" />\n", + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '<?xml version="$1" encoding="' . $apiConfigCharset . '"?>', + $wsdlConfig->getWsdlContent() + ) + ) + ) + ) + ); + } else { + try { + $this->_instantiateServer(); + + $this->getController()->getResponse() + ->clearHeaders() + ->setHeader('Content-Type', 'text/xml; charset=' . $apiConfigCharset) + ->setBody( + str_replace( + '<soap:operation soapAction=""></soap:operation>', + "<soap:operation soapAction=\"\" />\n", + str_replace( + '<soap:body use="literal"></soap:body>', + "<soap:body use=\"literal\" />\n", + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '<?xml version="$1" encoding="' . $apiConfigCharset . '"?>', + $this->_soap->handle() + ) + ) + ) + ); + } catch (Zend_Soap_Server_Exception $e) { + $this->fault($e->getCode(), $e->getMessage()); + } catch (Exception $e) { + $this->fault($e->getCode(), $e->getMessage()); + } + } + + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Server/Handler/Soap.php b/app/code/core/Mage/Api/Model/Server/Handler/Soap.php new file mode 100644 index 00000000000..376b016693e --- /dev/null +++ b/app/code/core/Mage/Api/Model/Server/Handler/Soap.php @@ -0,0 +1,60 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Webservices server handler v2 + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Server_Handler_Soap extends Mage_Api_Model_Server_HandlerAbstract +{ + protected $_resourceSuffix = '_V2'; + + /** + * Interceptor for all interfaces + * + * @param string $function + * @param array $args + * @return mixed + */ + + public function __call($function, $args) + { + $sessionId = array_shift($args); + $apiKey = ''; + $nodes = Mage::getSingleton('Mage_Api_Model_Config')->getNode('v2/resources_function_prefix')->children(); + foreach ($nodes as $resource => $prefix) { + $prefix = $prefix->asArray(); + if (false !== strpos($function, $prefix)) { + $method = substr($function, strlen($prefix)); + $apiKey = $resource . '.' . strtolower($method[0]) . substr($method, 1); + } + } + return $this->_call($sessionId, $apiKey, $args); + } +} diff --git a/app/code/core/Mage/Api/Model/Server/Handler/Soap/Wsi.php b/app/code/core/Mage/Api/Model/Server/Handler/Soap/Wsi.php new file mode 100644 index 00000000000..4cd286f41ea --- /dev/null +++ b/app/code/core/Mage/Api/Model/Server/Handler/Soap/Wsi.php @@ -0,0 +1,182 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Webservices server handler WSI + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Server_Handler_Soap_Wsi extends Mage_Api_Model_Server_HandlerAbstract +{ + protected $_resourceSuffix = '_V2'; + + /** + * Interceptor for all interfaces + * + * @param string $function + * @param array $args + */ + + public function __call($function, $args) + { + $args = $args[0]; + + /** @var Mage_Api_Helper_Data */ + $helper = Mage::helper('Mage_Api_Helper_Data'); + + $helper->wsiArrayUnpacker($args); + $args = get_object_vars($args); + + if (isset($args['sessionId'])) { + $sessionId = $args['sessionId']; + unset($args['sessionId']); + } else { + // Was left for backward compatibility. + $sessionId = array_shift($args); + } + + $apiKey = ''; + $nodes = Mage::getSingleton('Mage_Api_Model_Config')->getNode('v2/resources_function_prefix')->children(); + foreach ($nodes as $resource => $prefix) { + $prefix = $prefix->asArray(); + if (false !== strpos($function, $prefix)) { + $method = substr($function, strlen($prefix)); + $apiKey = $resource . '.' . strtolower($method[0]) . substr($method, 1); + } + } + + list($modelName, $methodName) = $this->_getResourceName($apiKey); + $methodParams = $this->getMethodParams($modelName, $methodName); + + $args = $this->prepareArgs($methodParams, $args); + + $res = $this->call($sessionId, $apiKey, $args); + + $obj = $helper->wsiArrayPacker($res); + $stdObj = new stdClass(); + $stdObj->result = $obj; + + return $stdObj; + } + + /** + * Login user and Retrieve session id + * + * @param string $username + * @param string $apiKey + * @return string + */ + public function login($username, $apiKey = null) + { + if (is_object($username)) { + $apiKey = $username->apiKey; + $username = $username->username; + } + + $stdObject = new stdClass(); + $stdObject->result = parent::login($username, $apiKey); + return $stdObject; + } + + /** + * Return called class and method names + * + * @param String $apiPath + * @return Array + */ + protected function _getResourceName($apiPath) + { + + list($resourceName, $methodName) = explode('.', $apiPath); + + if (empty($resourceName) || empty($methodName)) { + return $this->_fault('resource_path_invalid'); + } + + $resourcesAlias = $this->_getConfig()->getResourcesAlias(); + $resources = $this->_getConfig()->getResources(); + if (isset($resourcesAlias->$resourceName)) { + $resourceName = (string)$resourcesAlias->$resourceName; + } + + $methodInfo = $resources->$resourceName->methods->$methodName; + + $modelName = $this->_prepareResourceModelName((string)$resources->$resourceName->model); + + $modelClass = Mage::getConfig()->getModelClassName($modelName); + + $method = (isset($methodInfo->method) ? (string)$methodInfo->method : $methodName); + + return array($modelClass, $method); + } + + /** + * Return an array of parameters for the callable method. + * + * @param String $modelName + * @param String $methodName + * @return Array of ReflectionParameter + */ + public function getMethodParams($modelName, $methodName) + { + + $method = new ReflectionMethod($modelName, $methodName); + + return $method->getParameters(); + } + + /** + * Prepares arguments for the method calling. Sort in correct order, set default values for omitted parameters. + * + * @param Array $params + * @param Array $args + * @return Array + */ + public function prepareArgs($params, $args) + { + + $callArgs = array(); + + /** @var $parameter ReflectionParameter */ + foreach ($params AS $parameter) { + $pName = $parameter->getName(); + if (isset($args[$pName])) { + $callArgs[$pName] = $args[$pName]; + } else { + if ($parameter->isOptional()) { + $callArgs[$pName] = $parameter->getDefaultValue(); + } else { + Mage::logException(new Exception("Required parameter \"$pName\" is missing.", 0)); + $this->_fault('invalid_request_param'); + } + } + } + return $callArgs; + } + +} diff --git a/app/code/core/Mage/Api/Model/Server/HandlerAbstract.php b/app/code/core/Mage/Api/Model/Server/HandlerAbstract.php new file mode 100644 index 00000000000..6552147c922 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Server/HandlerAbstract.php @@ -0,0 +1,416 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Webservice default handler + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +abstract class Mage_Api_Model_Server_HandlerAbstract +{ + protected $_resourceSuffix = null; + + public function __construct() + { + set_error_handler(array($this, 'handlePhpError'), E_ALL); + Mage::app()->loadAreaPart(Mage_Core_Model_App_Area::AREA_ADMIN, Mage_Core_Model_App_Area::PART_EVENTS); + } + + public function handlePhpError($errorCode, $errorMessage, $errorFile) + { + Mage::log($errorMessage . $errorFile); + if (in_array($errorCode, array(E_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR))) { + $this->_fault('internal'); + } + return true; + } + + + /** + * Retrive webservice session + * + * @return Mage_Api_Model_Session + */ + protected function _getSession() + { + return Mage::getSingleton('Mage_Api_Model_Session'); + } + + /** + * Retrive webservice configuration + * + * @return Mage_Api_Model_Config + */ + protected function _getConfig() + { + return Mage::getSingleton('Mage_Api_Model_Config'); + } + + /** + * Retrive webservice server + * + * @return Mage_Api_Model_Server + */ + protected function _getServer() + { + return Mage::getSingleton('Mage_Api_Model_Server'); + } + + /** + * Start webservice session + * + * @param string $sessionId + * @return Mage_Api_Model_Server_HandlerAbstract + */ + protected function _startSession($sessionId = null) + { + $this->_getSession()->setSessionId($sessionId); + $this->_getSession()->init('api', 'api'); + return $this; + } + + /** + * Check current user permission on resource and privilege + * + * + * @param string $resource + * @param string $privilege + * @return bool + */ + protected function _isAllowed($resource, $privilege = null) + { + return $this->_getSession()->isAllowed($resource, $privilege); + } + + /** + * Dispatch webservice fault + * + * @param string $faultName + * @param string $resourceName + * @param string $customMessage + */ + protected function _fault($faultName, $resourceName = null, $customMessage = null) + { + $faults = $this->_getConfig()->getFaults($resourceName); + if (!isset($faults[$faultName]) && !is_null($resourceName)) { + $this->_fault($faultName); + return; + } elseif (!isset($faults[$faultName])) { + $this->_fault('unknown'); + return; + } + $this->_getServer()->getAdapter()->fault( + $faults[$faultName]['code'], + (is_null($customMessage) ? $faults[$faultName]['message'] : $customMessage) + ); + } + + /** + * Retrive webservice fault as array + * + * @param string $faultName + * @param string $resourceName + * @param string $customMessage + * @return array + */ + protected function _faultAsArray($faultName, $resourceName = null, $customMessage = null) + { + $faults = $this->_getConfig()->getFaults($resourceName); + if (!isset($faults[$faultName]) && !is_null($resourceName)) { + return $this->_faultAsArray($faultName); + } elseif (!isset($faults[$faultName])) { + return $this->_faultAsArray('unknown'); + } + + return array( + 'isFault' => true, + 'faultCode' => $faults[$faultName]['code'], + 'faultMessage' => (is_null($customMessage) ? $faults[$faultName]['message'] : $customMessage) + ); + } + + /** + * Start web service session + * + * @return string + */ + public function startSession() + { + $this->_startSession(); + return $this->_getSession()->getSessionId(); + } + + + /** + * End web service session + * + * @param string $sessionId + * @return boolean + */ + public function endSession($sessionId) + { + $this->_startSession($sessionId); + $this->_getSession()->clear(); + return true; + } + + /** + * Enter description here... + * + * @param string $resource + * @return string + */ + protected function _prepareResourceModelName($resource) + { + if (null !== $this->_resourceSuffix) { + return $resource . $this->_resourceSuffix; + } + return $resource; + } + + /** + * Login user and Retrieve session id + * + * @param string $username + * @param string $apiKey + * @return string + */ + public function login($username, $apiKey = null) + { + if (empty($username) || empty($apiKey)) { + return $this->_fault('invalid_request_param'); + } + + try { + $this->_startSession(); + $this->_getSession()->login($username, $apiKey); + } catch (Exception $e) { + return $this->_fault('access_denied'); + } + return $this->_getSession()->getSessionId(); + } + + /** + * Call resource functionality + * + * @param string $sessionId + * @param string $apiPath + * @param array $args + * @return mixed + * @throws Mage_Api_Exception + */ + protected function _call($sessionId, $apiPath, $args = array()) + { + $this->_startSession($sessionId); + + if (!$this->_getSession()->isLoggedIn($sessionId)) { + return $this->_fault('session_expired'); + } + + list($resourceName, $methodName) = explode('.', $apiPath); + + if (empty($resourceName) || empty($methodName)) { + return $this->_fault('resource_path_invalid'); + } + + $resourcesAlias = $this->_getConfig()->getResourcesAlias(); + $resources = $this->_getConfig()->getResources(); + if (isset($resourcesAlias->$resourceName)) { + $resourceName = (string)$resourcesAlias->$resourceName; + } + + if (!isset($resources->$resourceName) + || !isset($resources->$resourceName->methods->$methodName) + ) { + return $this->_fault('resource_path_invalid'); + } + + if (!isset($resources->$resourceName->public) + && isset($resources->$resourceName->acl) + && !$this->_isAllowed((string)$resources->$resourceName->acl) + ) { + return $this->_fault('access_denied'); + + } + + + if (!isset($resources->$resourceName->methods->$methodName->public) + && isset($resources->$resourceName->methods->$methodName->acl) + && !$this->_isAllowed((string)$resources->$resourceName->methods->$methodName->acl) + ) { + return $this->_fault('access_denied'); + } + + $methodInfo = $resources->$resourceName->methods->$methodName; + + try { + $method = (isset($methodInfo->method) ? (string)$methodInfo->method : $methodName); + + $modelName = $this->_prepareResourceModelName((string)$resources->$resourceName->model); + try { + $model = Mage::getModel($modelName); + if ($model instanceof Mage_Api_Model_Resource_Abstract) { + $model->setResourceConfig($resources->$resourceName); + } + } catch (Exception $e) { + throw new Mage_Api_Exception('resource_path_not_callable'); + } + + if (method_exists($model, $method)) { + if (isset($methodInfo->arguments) && ((string)$methodInfo->arguments) == 'array') { + return $model->$method((is_array($args) ? $args : array($args))); + } elseif (!is_array($args)) { + return $model->$method($args); + } else { + return call_user_func_array(array(&$model, $method), $args); + } + } else { + throw new Mage_Api_Exception('resource_path_not_callable'); + } + } catch (Mage_Api_Exception $e) { + return $this->_fault($e->getMessage(), $resourceName, $e->getCustomMessage()); + } catch (Exception $e) { + Mage::logException($e); + return $this->_fault('internal', null, $e->getMessage()); + } + } + + /** + * List of available resources + * + * @param string $sessionId + * @return array + */ + public function resources($sessionId) + { + $this->_startSession($sessionId); + + if (!$this->_getSession()->isLoggedIn($sessionId)) { + return $this->_fault('session_expired'); + } + + $resources = array(); + + $resourcesAlias = array(); + foreach ($this->_getConfig()->getResourcesAlias() as $alias => $resourceName) { + $resourcesAlias[(string)$resourceName][] = $alias; + } + + + foreach ($this->_getConfig()->getResources() as $resourceName => $resource) { + if (isset($resource->acl) && !$this->_isAllowed((string)$resource->acl)) { + continue; + } + + $methods = array(); + foreach ($resource->methods->children() as $methodName => $method) { + if (isset($method->acl) && !$this->_isAllowed((string)$method->acl)) { + continue; + } + $methodAliases = array(); + if (isset($resourcesAlias[$resourceName])) { + foreach ($resourcesAlias[$resourceName] as $alias) { + $methodAliases[] = $alias . '.' . $methodName; + } + } + + $methods[] = array( + 'title' => (string)$method->title, + 'description' => (isset($method->description) ? (string)$method->description : null), + 'path' => $resourceName . '.' . $methodName, + 'name' => $methodName, + 'aliases' => $methodAliases + ); + } + + if (count($methods) == 0) { + continue; + } + + $resources[] = array( + 'title' => (string)$resource->title, + 'description' => (isset($resource->description) ? (string)$resource->description : null), + 'name' => $resourceName, + 'aliases' => (isset($resourcesAlias[$resourceName]) ? $resourcesAlias[$resourceName] : array()), + 'methods' => $methods + ); + } + + return $resources; + } + + /** + * List of resource faults + * + * @param string $sessionId + * @param string $resourceName + * @return array + */ + public function resourceFaults($sessionId, $resourceName) + { + $this->_startSession($sessionId); + + if (!$this->_getSession()->isLoggedIn($sessionId)) { + return $this->_fault('session_expired'); + } + + $resourcesAlias = $this->_getConfig()->getResourcesAlias(); + $resources = $this->_getConfig()->getResources(); + + if (isset($resourcesAlias->$resourceName)) { + $resourceName = (string)$resourcesAlias->$resourceName; + } + + + if (empty($resourceName) + || !isset($resources->$resourceName) + ) { + return $this->_fault('resource_path_invalid'); + } + + if (isset($resources->$resourceName->acl) + && !$this->_isAllowed((string)$resources->$resourceName->acl) + ) { + return $this->_fault('access_denied'); + } + + return array_values($this->_getConfig()->getFaults($resourceName)); + } + + /** + * List of global faults + * + * @param string $sessionId + * @return array + */ + public function globalFaults($sessionId) + { + $this->_startSession($sessionId); + return array_values($this->_getConfig()->getFaults()); + } +} // Class Mage_Api_Model_Server_HandlerAbstract End diff --git a/app/code/core/Mage/Api/Model/Session.php b/app/code/core/Mage/Api/Model/Session.php new file mode 100644 index 00000000000..d9dfae0fe69 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Session.php @@ -0,0 +1,207 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Webservice api session + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Session extends Mage_Core_Model_Session_Abstract +{ + public $sessionIds = array(); + protected $_currentSessId = null; + + public function start($sessionName=null) + { +// parent::start($sessionName=null); + $this->_currentSessId = md5(time() . uniqid('', true) . $sessionName); + $this->sessionIds[] = $this->getSessionId(); + return $this; + } + + public function init($namespace, $sessionName=null) + { + if (is_null($this->_currentSessId)) { + $this->start(); + } + return $this; + } + + public function getSessionId() + { + return $this->_currentSessId; + } + + public function setSessionId($sessId = null) + { + if (!is_null($sessId)) { + $this->_currentSessId = $sessId; + } + return $this; + } + + public function revalidateCookie() + { + // In api we don't use cookies + } + + public function clear() { + if ($sessId = $this->getSessionId()) { + try { + Mage::getModel('Mage_Api_Model_User')->logoutBySessId($sessId); + } catch (Exception $e) { + return false; + } + } + return true; + } + + public function login($username, $apiKey) + { + $user = Mage::getModel('Mage_Api_Model_User') + ->setSessid($this->getSessionId()) + ->login($username, $apiKey); + + if ( $user->getId() && $user->getIsActive() != '1' ) { + Mage::throwException(Mage::helper('Mage_Api_Helper_Data')->__('Your account has been deactivated.')); + } elseif (!Mage::getModel('Mage_Api_Model_User')->hasAssigned2Role($user->getId())) { + Mage::throwException(Mage::helper('Mage_Api_Helper_Data')->__('Access denied.')); + } else { + if ($user->getId()) { + $this->setUser($user); + $this->setAcl(Mage::getResourceModel('Mage_Api_Model_Resource_Acl')->loadAcl()); + } else { + Mage::throwException(Mage::helper('Mage_Api_Helper_Data')->__('Unable to login.')); + } + } + + return $user; + } + + public function refreshAcl($user=null) + { + if (is_null($user)) { + $user = $this->getUser(); + } + if (!$user) { + return $this; + } + if (!$this->getAcl() || $user->getReloadAclFlag()) { + $this->setAcl(Mage::getResourceModel('Mage_Api_Model_Resource_Acl')->loadAcl()); + } + if ($user->getReloadAclFlag()) { + $user->unsetData('api_key'); + $user->setReloadAclFlag('0')->save(); + } + return $this; + } + + /** + * Check current user permission on resource and privilege + * + * + * @param string $resource + * @param string $privilege + * @return bool + */ + public function isAllowed($resource, $privilege=null) + { + $user = $this->getUser(); + $acl = $this->getAcl(); + + if ($user && $acl) { + try { + if ($acl->isAllowed($user->getAclRole(), 'all', null)){ + return true; + } + } catch (Exception $e) {} + + try { + return $acl->isAllowed($user->getAclRole(), $resource, $privilege); + } catch (Exception $e) { + return false; + } + } + return false; + } + + /** + * Check session expiration + * + * @return boolean + */ + public function isSessionExpired ($user) + { + if (!$user->getId()) { + return true; + } + $timeout = strtotime( now() ) - strtotime( $user->getLogdate() ); + return $timeout > Mage::getStoreConfig('api/config/session_timeout'); + } + + + public function isLoggedIn($sessId = false) + { + $userExists = $this->getUser() && $this->getUser()->getId(); + + if (!$userExists && $sessId !== false) { + return $this->_renewBySessId($sessId); + } + + if ($userExists) { + Mage::register('isSecureArea', true, true); + } + return $userExists; + } + + /** + * Renew user by session ID if session not expired + * + * @param string $sessId + * @return boolean + */ + protected function _renewBySessId ($sessId) + { + $user = Mage::getModel('Mage_Api_Model_User')->loadBySessId($sessId); + if (!$user->getId() || !$user->getSessid()) { + return false; + } + + if ($user->getSessid() == $sessId && !$this->isSessionExpired($user)) { + $this->setUser($user); + $this->setAcl(Mage::getResourceModel('Mage_Api_Model_Resource_Acl')->loadAcl()); + + $user->getResource()->recordLogin($user) + ->recordSession($user); + + return true; + } + return false; + } + +} // Class Mage_Api_Model_Session End diff --git a/app/code/core/Mage/Api/Model/User.php b/app/code/core/Mage/Api/Model/User.php new file mode 100644 index 00000000000..a3101d94f9f --- /dev/null +++ b/app/code/core/Mage/Api/Model/User.php @@ -0,0 +1,254 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Enter description here ... + * + * @method Mage_Api_Model_Resource_User _getResource() + * @method Mage_Api_Model_Resource_User getResource() + * @method string getFirstname() + * @method Mage_Api_Model_User setFirstname(string $value) + * @method string getLastname() + * @method Mage_Api_Model_User setLastname(string $value) + * @method string getEmail() + * @method Mage_Api_Model_User setEmail(string $value) + * @method string getUsername() + * @method Mage_Api_Model_User setUsername(string $value) + * @method string getApiKey() + * @method Mage_Api_Model_User setApiKey(string $value) + * @method string getCreated() + * @method Mage_Api_Model_User setCreated(string $value) + * @method string getModified() + * @method Mage_Api_Model_User setModified(string $value) + * @method int getLognum() + * @method Mage_Api_Model_User setLognum(int $value) + * @method int getReloadAclFlag() + * @method Mage_Api_Model_User setReloadAclFlag(int $value) + * @method int getIsActive() + * @method Mage_Api_Model_User setIsActive(int $value) + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_User extends Mage_Core_Model_Abstract +{ + /** + * Prefix of model events names + * + * @var string + */ + protected $_eventPrefix = 'api_user'; + + protected function _construct() + { + $this->_init('Mage_Api_Model_Resource_User'); + } + + public function save() + { + $this->_beforeSave(); + $data = array( + 'firstname' => $this->getFirstname(), + 'lastname' => $this->getLastname(), + 'email' => $this->getEmail(), + 'modified' => Mage::getSingleton('Mage_Core_Model_Date')->gmtDate() + ); + + if($this->getId() > 0) { + $data['user_id'] = $this->getId(); + } + + if( $this->getUsername() ) { + $data['username'] = $this->getUsername(); + } + + if ($this->getApiKey()) { + $data['api_key'] = $this->_getEncodedApiKey($this->getApiKey()); + } + + if ($this->getNewApiKey()) { + $data['api_key'] = $this->_getEncodedApiKey($this->getNewApiKey()); + } + + if ( !is_null($this->getIsActive()) ) { + $data['is_active'] = intval($this->getIsActive()); + } + + $this->setData($data); + $this->_getResource()->save($this); + $this->_afterSave(); + return $this; + } + + public function delete() + { + $this->_beforeDelete(); + $this->_getResource()->delete($this); + $this->_afterDelete(); + return $this; + } + + public function saveRelations() + { + $this->_getResource()->_saveRelations($this); + return $this; + } + + public function getRoles() + { + return $this->_getResource()->_getRoles($this); + } + + public function deleteFromRole() + { + $this->_getResource()->deleteFromRole($this); + return $this; + } + + public function roleUserExists() + { + $result = $this->_getResource()->roleUserExists($this); + return ( is_array($result) && count($result) > 0 ) ? true : false; + } + + public function add() + { + $this->_getResource()->add($this); + return $this; + } + + public function userExists() + { + $result = $this->_getResource()->userExists($this); + return ( is_array($result) && count($result) > 0 ) ? true : false; + } + + public function getCollection() { + return Mage::getResourceModel('Mage_Api_Model_Resource_User_Collection'); + } + + public function getName($separator=' ') + { + return $this->getFirstname().$separator.$this->getLastname(); + } + + public function getId() + { + return $this->getUserId(); + } + + /** + * Get user ACL role + * + * @return string + */ + public function getAclRole() + { + return 'U'.$this->getUserId(); + } + + /** + * Authenticate user name and api key and save loaded record + * + * @param string $username + * @param string $apiKey + * @return boolean + */ + public function authenticate($username, $apiKey) + { + $this->loadByUsername($username); + if (!$this->getId()) { + return false; + } + $auth = Mage::helper('Mage_Core_Helper_Data')->validateHash($apiKey, $this->getApiKey()); + if ($auth) { + return true; + } else { + $this->unsetData(); + return false; + } + } + + /** + * Login user + * + * @param string $login + * @param string $apiKey + * @return Mage_Api_Model_User + */ + public function login($username, $apiKey) + { + $sessId = $this->getSessid(); + if ($this->authenticate($username, $apiKey)) { + $this->setSessid($sessId); + $this->getResource()->cleanOldSessions($this) + ->recordLogin($this) + ->recordSession($this); + Mage::dispatchEvent('api_user_authenticated', array( + 'model' => $this, + 'api_key' => $apiKey, + )); + } + + return $this; + } + + public function reload() + { + $this->load($this->getId()); + return $this; + } + + public function loadByUsername($username) + { + $this->setData($this->getResource()->loadByUsername($username)); + return $this; + } + + public function loadBySessId ($sessId) + { + $this->setData($this->getResource()->loadBySessId($sessId)); + return $this; + } + + public function logoutBySessId($sessid) + { + $this->getResource()->clearBySessId($sessid); + return $this; + } + + public function hasAssigned2Role($user) + { + return $this->getResource()->hasAssigned2Role($user); + } + + protected function _getEncodedApiKey($apiKey) + { + return Mage::helper('Mage_Core_Helper_Data')->getHash($apiKey, 2); + } + +} diff --git a/app/code/core/Mage/Api/Model/Wsdl/Config.php b/app/code/core/Mage/Api/Model/Wsdl/Config.php new file mode 100644 index 00000000000..b9a5e525cd2 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Wsdl/Config.php @@ -0,0 +1,140 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Wsdl config model + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Wsdl_Config extends Mage_Api_Model_Wsdl_Config_Base +{ + protected static $_namespacesPrefix = null; + + public function __construct($sourceData = null) + { + $this->setCacheId('wsdl_config_global'); + parent::__construct($sourceData); + } + + /** + * Return wsdl content + * + * @return string + */ + public function getWsdlContent() + { + return $this->_xml->asXML(); + } + + /** + * Return namespaces with their prefix + * + * @return array + */ + public static function getNamespacesPrefix() + { + if (is_null(self::$_namespacesPrefix)) { + self::$_namespacesPrefix = array(); + $config = Mage::getSingleton('Mage_Api_Model_Config')->getNode('v2/wsdl/prefix')->children(); + foreach ($config as $prefix => $namespace) { + self::$_namespacesPrefix[$namespace->asArray()] = $prefix; + } + } + return self::$_namespacesPrefix; + } + + public function getCache() + { + return Mage::app()->getCache(); + } + + protected function _loadCache($id) + { + return Mage::app()->loadCache($id); + } + + protected function _saveCache($data, $id, $tags = array(), $lifetime = false) + { + return Mage::app()->saveCache($data, $id, $tags, $lifetime); + } + + protected function _removeCache($id) + { + return Mage::app()->removeCache($id); + } + + public function init() + { + $this->setCacheChecksum(null); + $saveCache = true; + + if (Mage::app()->useCache('config')) { + $loaded = $this->loadCache(); + if ($loaded) { + return $this; + } + } + + $mergeWsdl = new Mage_Api_Model_Wsdl_Config_Base(); + $mergeWsdl->setHandler($this->getHandler()); + + /** @var Mage_Api_Helper_Data $helper */ + $helper = Mage::helper('Mage_Api_Helper_Data'); + if ($helper->isWsiCompliant()) { + /** + * Exclude Mage_Api wsdl xml file because it used for previous version + * of API wsdl declaration + */ + $mergeWsdl->addLoadedFile(Mage::getConfig()->getModuleDir('etc', "Mage_Api") . DS . 'wsi.xml'); + + $baseWsdlFile = Mage::getConfig()->getModuleDir('etc', "Mage_Api") . DS . 'wsi.xml'; + $this->loadFile($baseWsdlFile); + Mage::getConfig()->loadModulesConfiguration('wsi.xml', $this, $mergeWsdl); + } else { + $baseWsdlFile = Mage::getConfig()->getModuleDir('etc', "Mage_Api") . DS . 'wsdl.xml'; + $this->loadFile($baseWsdlFile); + Mage::getConfig()->loadModulesConfiguration('wsdl.xml', $this, $mergeWsdl); + } + + if (Mage::app()->useCache('config')) { + $this->saveCache(array('config')); + } + + return $this; + } + + /** + * Return Xml of node as string + * + * @return string + */ + public function getXmlString() + { + return $this->getNode()->asXML(); + } +} diff --git a/app/code/core/Mage/Api/Model/Wsdl/Config/Base.php b/app/code/core/Mage/Api/Model/Wsdl/Config/Base.php new file mode 100644 index 00000000000..3f251767854 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Wsdl/Config/Base.php @@ -0,0 +1,136 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Wsdl base config + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Model_Wsdl_Config_Base extends Varien_Simplexml_Config +{ + protected $_handler = ''; + + /** + * @var Varien_Object + */ + protected $_wsdlVariables = null; + + protected $_loadedFiles = array(); + + public function __construct($sourceData=null) + { + $this->_elementClass = 'Mage_Api_Model_Wsdl_Config_Element'; + + // remove wsdl parameter from query + $queryParams = Mage::app()->getRequest()->getQuery(); + unset($queryParams['wsdl']); + + // set up default WSDL template variables + $this->_wsdlVariables = new Varien_Object( + array( + 'name' => 'Magento', + 'url' => htmlspecialchars(Mage::getUrl('*/*/*', array('_query' => $queryParams))) + ) + ); + parent::__construct($sourceData); + } + + /** + * Set handler + * + * @param string $handler + * @return Mage_Api_Model_Wsdl_Config_Base + */ + public function setHandler($handler) + { + $this->_handler = $handler; + return $this; + } + + /** + * Get handler + * + * @return string + */ + public function getHandler() + { + return $this->_handler; + } + + /** + * Processing file data + * + * @param string $text + * @return string + */ + public function processFileData($text) + { + /** @var $template Mage_Core_Model_Email_Template_Filter */ + $template = Mage::getModel('Mage_Core_Model_Email_Template_Filter'); + + $this->_wsdlVariables->setHandler($this->getHandler()); + + $template->setVariables(array('wsdl'=>$this->_wsdlVariables)); + + return $template->filter($text); + } + + public function addLoadedFile($file) + { + if (!in_array($file, $this->_loadedFiles)) { + $this->_loadedFiles[] = $file; + } + return $this; + } + + public function loadFile($file) + { + if (in_array($file, $this->_loadedFiles)) { + return false; + } + $res = parent::loadFile($file); + if ($res) { + $this->addLoadedFile($file); + } + return $this; + } + + /** + * Set variable to be used in WSDL template processing + * + * @param string $key Varible key + * @param string $value Variable value + * @return Mage_Api_Model_Wsdl_Config_Base + */ + public function setWsdlVariable($key, $value) + { + $this->_wsdlVariables->setData($key, $value); + + return $this; + } +} diff --git a/app/code/core/Mage/Api/Model/Wsdl/Config/Element.php b/app/code/core/Mage/Api/Model/Wsdl/Config/Element.php new file mode 100644 index 00000000000..12040ef47a9 --- /dev/null +++ b/app/code/core/Mage/Api/Model/Wsdl/Config/Element.php @@ -0,0 +1,272 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +/** + * Wsdl element model + * + * @category Mage + * @package Mage_Core + */ +class Mage_Api_Model_Wsdl_Config_Element extends Varien_Simplexml_Element +{ + public function extend($source, $overwrite = false) + { + if (!$source instanceof Varien_Simplexml_Element) { + return $this; + } + + foreach ($this->getChildren($source) as $namespace => $children) { + foreach ($children as $child) { + $this->extendChild($child, $overwrite, $namespace); + } + } + + return $this; + } + + /** + * Extends one node + * + * @param Varien_Simplexml_Element $source + * @param boolean $overwrite + * @return Varien_Simplexml_Element + */ + public function extendChild($source, $overwrite = false, $elmNamespace = '') + { + // this will be our new target node + $targetChild = null; + + // name of the source node + $sourceName = $source->getName(); + + // here we have children of our source node + $sourceChildren = $this->getChildren($source); + + if ($elmNamespace == '') { + $elmNamespace = null; + } + + if (!$source->hasChildren()) { + // handle string node + $elm = $this->getElementByName($source, $elmNamespace); + if (!is_null($elm)) { + + // if target already has children return without regard + if ($this->getChildren($elm)) { + return $this; + } + if ($overwrite) { +// unset($this->$sourceName); + unset($elm); + } else { + return $this; + } + } + $targetChild = $this->addChild($sourceName, $source->xmlentities(), $elmNamespace); + $targetChild->setParent($this); + foreach ($this->getAttributes($source) as $namespace => $attributes) { + foreach ($attributes as $key => $value) { + $_namespacesPrefix = Mage_Api_Model_Wsdl_Config::getNamespacesPrefix(); + if ($namespace == '') { + $namespace = null; + } elseif (array_key_exists($namespace, $_namespacesPrefix)) { + $key = $_namespacesPrefix[$namespace] . ':' . $key; + } + + $targetChild->addAttribute($key, $this->xmlentities($value), $namespace); + } + } + return $this; + } + + $elm = $this->getElementByName($source, $elmNamespace); + if (!is_null($elm)) { + $targetChild = $elm; + } + if (is_null($targetChild)) { + // if child target is not found create new and descend + $targetChild = $this->addChild($sourceName, null, $elmNamespace); + $targetChild->setParent($this); + foreach ($this->getAttributes($source) as $namespace => $attributes) { + foreach ($attributes as $key => $value) { + $_namespacesPrefix = Mage_Api_Model_Wsdl_Config::getNamespacesPrefix(); + if ($namespace == '') { + $namespace = null; + } elseif (array_key_exists($namespace, $_namespacesPrefix)) { + $key = $_namespacesPrefix[$namespace] . ':' . $key; + } + $targetChild->addAttribute($key, $this->xmlentities($value), $namespace); + } + } + } + + foreach ($sourceChildren as $elmNamespace => $children) { + foreach ($children as $childKey => $childNode) { + $targetChild->extendChild($childNode, $overwrite, $elmNamespace); + } + } + + return $this; + } + + /** + * Return attributes of all namespaces + * + * array( + * namespace => array( + * attribute_key => attribute_value, + * ... + * ) + * ) + * + * @param Varien_Simplexml_Element $source + * @return array + */ + public function getAttributes($source, $namespace = null) + { + $attributes = array(); + if (!is_null($namespace)) { + $attributes[$namespace] = $source->attributes($namespace); + return $attributes; + } + $namespaces = $source->getNamespaces(true); + $attributes[''] = $source->attributes(''); + foreach ($namespaces as $key => $value) { + if ($key == '' || $key == 'soap') { + continue; + } + $attributes[$value] = $source->attributes($value); + } + return $attributes; + } + + /** + * Return children of all namespaces + * + * @param Varien_Simplexml_Element $source + */ + public function getChildren($source) + { + $children = array(); + $namespaces = $source->getNamespaces(true); + + /** @var Mage_Api_Helper_Data $helper */ + $helper = Mage::helper('Mage_Api_Helper_Data'); + $isWsi = $helper->isWsiCompliant(); + + foreach ($namespaces as $key => $value) { + if ($key == '' || (!$isWsi && $key == 'wsdl')) { + continue; + } + $children[$value] = $source->children($value); + } + $children[''] = $source->children(''); + return $children; + } + + /** + * Return if has children + * + * @return boolean + */ + public function hasChildren() + { + if (!$this->getChildren($this)) { + return false; + } + + // simplexml bug: @attributes is in children() but invisible in foreach + foreach ($this->getChildren($this) as $namespace => $children) { + foreach ($children as $k => $child) { + return true; + } + } + return false; + } + + /** + * Return element by tag name, and checking attributes with namespaces + * + * @param Varien_Simplexml_Element $source + * @param string $namespace + * @return null|Varien_Simplexml_Element + */ + public function getElementByName($source, $elmNamespace = '') + { + $sourceName = $source->getName(); + $extendElmAttributes = $this->getAttributes($source); + foreach ($this->children($elmNamespace) as $k => $child) { + if ($child->getName() == $sourceName) { + $elm = true; + foreach ($extendElmAttributes as $namespace => $attributes) { + /** + * if count of attributes of extend element is 0 in $namespace, + * and current element has attributes in $namespace - different elements + */ +// if (!count($attributes) && count($this->getAttributes($child, $namespace))) { +// foreach ($this->getAttributes($child, $namespace) as $attribute) { +// $elm = false; +// break; +// } +// } + foreach ($attributes as $key => $value) { + if (is_null($child->getAttribute($key, $namespace)) || $child->getAttribute( + $key, + $namespace + ) != $value + ) { + $elm = false; + } + } + } + /** + * if count of namespaces attributes of element to extend is 0, + * but current element has namespaces attributes - different elements + */ + if (!count($extendElmAttributes) && count($this->getAttributes($child))) { + $elm = false; + } + if ($elm) { + return $child; + } + } + } + return null; + } + + /** + * Returns attribute value by attribute name + * + * @return string + */ + public function getAttribute($name, $namespace = '') + { + $attrs = $this->attributes($namespace); + return isset($attrs[$name]) ? (string)$attrs[$name] : null; + } + +} diff --git a/app/code/core/Mage/Api/controllers/Soap/WsiController.php b/app/code/core/Mage/Api/controllers/Soap/WsiController.php new file mode 100644 index 00000000000..56fe6649657 --- /dev/null +++ b/app/code/core/Mage/Api/controllers/Soap/WsiController.php @@ -0,0 +1,42 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * SOAP WS-I compatible API controller. + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_Soap_WsiController extends Mage_Api_Controller_Action +{ + public function indexAction() + { + $handlerName = 'soap_wsi'; + /* @var $server Mage_Api_Model_Server */ + $this->_getServer()->init($this, $handlerName, $handlerName)->run(); + } +} diff --git a/app/code/core/Mage/Api/controllers/SoapController.php b/app/code/core/Mage/Api/controllers/SoapController.php new file mode 100644 index 00000000000..5e6fbb18d29 --- /dev/null +++ b/app/code/core/Mage/Api/controllers/SoapController.php @@ -0,0 +1,42 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * SOAP API controller. + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Api_SoapController extends Mage_Api_Controller_Action +{ + public function indexAction() + { + $handlerName = 'soap_v2'; + /* @var $server Mage_Api_Model_Server */ + $this->_getServer()->init($this, $handlerName, $handlerName)->run(); + } +} diff --git a/app/code/core/Mage/Api/etc/adminhtml.xml b/app/code/core/Mage/Api/etc/adminhtml.xml new file mode 100644 index 00000000000..2466831fc69 --- /dev/null +++ b/app/code/core/Mage/Api/etc/adminhtml.xml @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <acl> + <resources> + <admin> + <children> + <system> + <children> + <api translate="title" module="Mage_Api"> + <title>Web Services</title> + <sort_order>0</sort_order> + <children> + <users translate="title"> + <title>SOAP - Users</title> + <sort_order>10</sort_order> + </users> + <roles translate="title"> + <title>SOAP - Roles</title> + <sort_order>20</sort_order> + </roles> + </children> + </api> + <config> + <children> + <api translate="title" module="Mage_Api"> + <title>Magento Core API Section</title> + </api> + </children> + </config> + </children> + </system> + </children> + </admin> + </resources> + </acl> +</config> diff --git a/app/code/core/Mage/Api/etc/adminhtml/menu.xml b/app/code/core/Mage/Api/etc/adminhtml/menu.xml new file mode 100644 index 00000000000..c7740c5e0a6 --- /dev/null +++ b/app/code/core/Mage/Api/etc/adminhtml/menu.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <menu> + <add id="Mage_Api::system_legacy_api" title="Legacy Web Services" module="Mage_Api" + sortOrder="25" parent="Mage_Adminhtml::system" resource="Mage_Api::system_legacy_api" /> + <add id="Mage_Api::system_legacy_api_users" title="SOAP Users" module="Mage_Api" + sortOrder="10" parent="Mage_Api::system_legacy_api" action="adminhtml/api_user" + resource = "Mage_Api::system_legacy_api_users" /> + <add id="Mage_Api::system_legacy_api_roles" title="SOAP Roles" module="Mage_Api" + sortOrder="20" parent="Mage_Api::system_legacy_api" action="adminhtml/api_role" + resource ="Mage_Api::system_legacy_api_users" /> + </menu> +</config> diff --git a/app/code/core/Mage/Api/etc/adminhtml/system.xml b/app/code/core/Mage/Api/etc/adminhtml/system.xml new file mode 100644 index 00000000000..ece2e625063 --- /dev/null +++ b/app/code/core/Mage/Api/etc/adminhtml/system.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <system> + <section id="api" translate="label" module="Mage_Api" type="text" sortOrder="101" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Magento Core API</label> + <tab>service</tab> + <resource>Mage_Api::config_api</resource> + <group id="config" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>General Settings</label> + <field id="charset" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Default Response Charset</label> + </field> + <field id="session_timeout" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Client Session Timeout (sec.)</label> + </field> + <field id="wsdl_cache_enabled" translate="label" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Enable WSDL Cache</label> + <source_model>Mage_Backend_Model_Config_Source_Yesno</source_model> + <backend_model>Mage_Backend_Model_Config_Backend_Store</backend_model> + </field> + </group> + </section> + </system> +</config> diff --git a/app/code/core/Mage/Api/etc/api.xml b/app/code/core/Mage/Api/etc/api.xml new file mode 100644 index 00000000000..36495d74f3a --- /dev/null +++ b/app/code/core/Mage/Api/etc/api.xml @@ -0,0 +1,260 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <adapters> + <soap_v2> + <model>Mage_Api_Model_Server_Adapter_Soap</model> + <handler>soap_v2</handler> + <active>1</active> + <required> + <extensions> + <soap /> + </extensions> + </required> + </soap_v2> + <soap_wsi> + <model>Mage_Api_Model_Server_Adapter_Soap_Wsi</model> + <handler>soap_wsi</handler> + <active>1</active> + <required> + <extensions> + <soap /> + </extensions> + </required> + </soap_wsi> + </adapters> + <handlers> + <soap_v2> + <model>Mage_Api_Model_Server_Handler_Soap</model> + </soap_v2> + <soap_wsi> + <model>Mage_Api_Model_Server_Handler_Soap_Wsi</model> + </soap_wsi> + </handlers> + <resources> + </resources> + <resources_alias> + </resources_alias> + <v2> + <wsdl> + <prefix> + <wsdl>http://schemas.xmlsoap.org/wsdl/</wsdl> + </prefix> + </wsdl> + </v2> + <faults> + <unknown> + <code>0</code> + <message>Unknown Error</message> + </unknown> + <internal> + <code>1</code> + <message>Internal Error. Please see log for details.</message> + </internal> + <access_denied> + <code>2</code> + <message>Access is denied.</message> + </access_denied> + <resource_path_invalid> + <code>3</code> + <message>API path is invalid.</message> + </resource_path_invalid> + <resource_path_not_callable> + <code>4</code> + <message>Resource path is not callable.</message> + </resource_path_not_callable> + <session_expired> + <code>5</code> + <message>Session expired. Try to relogin.</message> + </session_expired> + <invalid_request_param> + <code>6</code> + <message>Required parameter is missing, for more details see "exception.log".</message> + </invalid_request_param> + </faults> + <acl> + <resources> + <all> + </all> + </resources> + + <privilegeSets> + <default> + <view descr="View entity"/> + <edit descr="Edit entity"/> + <delete descr="Delete entity"/> + <create descr="Create entity"/> + </default> + </privilegeSets> + </acl> + + <domain_messages> + <!-- module name --> + <core> + <!-- 200 --> + <success> + <ok>Request is executed.</ok> + </success> + <!-- 201 --> + <created> + <created>Request is executed. Created new resource.</created> + </created> + <!-- 202 --> + <processing> + <processing>Request is carried out.</processing> + </processing> + <!-- 400 --> + <validation> + <invalid_param>Parameter "%s" is not valid.</invalid_param> + </validation> + <!-- 400 --> + <request_error> + <!-- Client sent wrong API version --> + <invalid_api_version>API version "%s" not found.</invalid_api_version> + </request_error> + <!-- 401 --> + <authentication> + <protect_resource>You must provide an authenticated user for this method.</protect_resource> + <invalid_token>Token in request is not valid.</invalid_token> + </authentication> + <!-- 403 --> + <forbidden> + <api_key_invalid>Invalid API key</api_key_invalid> + </forbidden> + <!-- 404 --> + <not_found> + <item_not_found>Requested item %s not found.</item_not_found> + <resource_not_found>Requested resource %s not found.</resource_not_found> + </not_found> + <!-- 405 --> + <not_allowed> + <method_not_allowed>Method "%s" is not allowed.</method_not_allowed> + </not_allowed> + <!-- 406 --> + <not_acceptable> + <api_version_required>Api version is required.</api_version_required> + </not_acceptable> + <!-- 410 --> + <gone> + <!-- Message when client trying sent the API version which no longer maintained --> + <api_deprecated>API version "%s" is deprecated.</api_deprecated> + <!-- Message when client trying request the resource which no longer maintained --> + <deprecated>Resource "%s" is deprecated.</deprecated> + </gone> + + <!-- 500 --> + <internal_error> + <!-- Code error message not found or not exist --> + <unknown_error>There was unknown error while processing your request.</unknown_error> + <!-- Internal error when server catch some exception or language error --> + <internal_error>There was internal error while processing your request.</internal_error> + <!-- Developer mode message about error --> + <code_error>Server has internal error. %s: %s</code_error> + </internal_error> + <!-- 501 --> + <not_implemented> + <resource_not_implemented>This resource is not implemented so far.</resource_not_implemented> + <method_not_implemented>This method is not implemented so far.</method_not_implemented> + </not_implemented> + </core> + </domain_messages> + + <!-- Message Domains with relation to HTTP codes --> + <!-- The priority for domains is the HTTP code --> + <domain_codes> + <!-- All success messages except "entry_created", "processing" --> + <success> + <http_code>200</http_code> + <type>notification</type> + </success> + <!-- Messages when created new entry --> + <created> + <http_code>201</http_code> + <type>notification</type> + </created> + <!-- Processing messages --> + <processing> + <http_code>202</http_code> + <type>notification</type> + </processing> + + <!-- Validation messages --> + <validation> + <http_code>400</http_code> + <type>error</type> + </validation> + <!-- Messages when the request from a client has an error --> + <request_error> + <http_code>400</http_code> + <type>error</type> + </request_error> + <!-- Authentication error messages --> + <authentication> + <http_code>401</http_code> + <type>error</type> + </authentication> + <!-- Messages when post request is accepted but cannot performed --> + <forbidden> + <http_code>403</http_code> + <type>error</type> + </forbidden> + <!-- Messages when some data not found --> + <not_found> + <http_code>404</http_code> + <type>error</type> + </not_found> + <!-- Messages when some method is not allowed --> + <not_allowed> + <http_code>405</http_code> + <type>error</type> + </not_allowed> + <!-- Messages when some is not acceptable --> + <not_acceptable> + <http_code>406</http_code> + <type>error</type> + </not_acceptable> + <!-- Messages when some resource are gone --> + <gone> + <http_code>410</http_code> + <type>error</type> + </gone> + <!-- All messages related with internal errors --> + <internal_error> + <http_code>500</http_code> + <type>error</type> + </internal_error> + <!-- Messages when something not implemented --> + <not_implemented> + <http_code>501</http_code> + <type>error</type> + </not_implemented> + </domain_codes> + + </api> +</config> diff --git a/app/code/core/Mage/Api/etc/config.xml b/app/code/core/Mage/Api/etc/config.xml new file mode 100644 index 00000000000..5fa3bfab386 --- /dev/null +++ b/app/code/core/Mage/Api/etc/config.xml @@ -0,0 +1,107 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <modules> + <Mage_Api> + <version>1.6.0.0</version> + <active>true</active> + <codePool>core</codePool> + <depends> + <Mage_Core /> + </depends> + </Mage_Api> + </modules> + <global> + <ignoredModules> + <entities> + <api/> + </entities> + </ignoredModules> + <cache> + <types> + <config_api translate="label,description" module="Mage_Api"> + <label>Legacy API Configuration</label> + <description>Web Services definition files (api.xml).</description> + <tags>CONFIG_API</tags> + </config_api> + </types> + </cache> + <resources> + <api_setup> + <setup> + <module>Mage_Api</module> + </setup> + </api_setup> + </resources> + <request> + <direct_front_name> + <api/> + </direct_front_name> + </request> + </global> + <frontend> + <routers> + <api> + <use>standard</use> + <args> + <module>Mage_Api</module> + <frontName>api</frontName> + </args> + </api> + </routers> + <translate> + <modules> + <Mage_Api> + <files> + <default>Mage_Api.csv</default> + </files> + </Mage_Api> + </modules> + </translate> + </frontend> + <adminhtml> + <translate> + <modules> + <Mage_Api> + <files> + <default>Mage_Api.csv</default> + </files> + </Mage_Api> + </modules> + </translate> + </adminhtml> + <default> + <api> + <config> + <charset>UTF-8</charset> + <session_timeout>3600</session_timeout> + <wsdl_cache_enabled>0</wsdl_cache_enabled> + </config> + </api> + </default> +</config> diff --git a/app/code/core/Mage/Api/etc/wsdl.xml b/app/code/core/Mage/Api/etc/wsdl.xml new file mode 100644 index 00000000000..fd9fe0d5dd3 --- /dev/null +++ b/app/code/core/Mage/Api/etc/wsdl.xml @@ -0,0 +1,242 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="associativeEntity"> + <all> + <element name="key" type="xsd:string" /> + <element name="value" type="xsd:string" /> + </all> + </complexType> + <complexType name="associativeArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:associativeEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="associativeMultiEntity"> + <all> + <element name="key" type="xsd:string" /> + <element name="value" type="typens:ArrayOfString" /> + </all> + </complexType> + <complexType name="associativeMultiArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:associativeMultiEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="filters"> + <all> + <element name="filter" type="typens:associativeArray" minOccurs="0" /> + <element name="complex_filter" type="typens:complexFilterArray" minOccurs="0" /> + </all> + </complexType> + <complexType name="complexFilterArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:complexFilter[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="complexFilter"> + <all> + <element name="key" type="xsd:string" /> + <element name="value" type="typens:associativeEntity" /> + </all> + </complexType> + <complexType name="ArrayOfString"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="ArrayOfInt"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:int[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="apiMethodEntity"> + <all> + <element name="title" type="xsd:string" /> + <element name="path" type="xsd:string" /> + <element name="name" type="xsd:string" /> + <element name="aliases" type="typens:ArrayOfString" /> + </all> + </complexType> + <complexType name="ArrayOfApiMethods"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:apiMethodEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="apiEntity"> + <all> + <element name="title" type="xsd:string" /> + <element name="name" type="xsd:string" /> + <element name="aliases" type="typens:ArrayOfString" /> + <element name="methods" type="typens:ArrayOfApiMethods" /> + </all> + </complexType> + <complexType name="ArrayOfApis"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:apiEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="existsFaltureEntity"> + <all> + <element name="code" type="xsd:string" /> + <element name="message" type="xsd:string" /> + </all> + </complexType> + <complexType name="ArrayOfExistsFaltures"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:existsFaltureEntity[]" /> + </restriction> + </complexContent> + </complexType> + </schema> + </types> + <message name="endSession"> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="endSessionResponse"> + <part name="endSessionReturn" type="xsd:boolean" /> + </message> + <message name="login"> + <part name="username" type="xsd:string" /> + <part name="apiKey" type="xsd:string" /> + </message> + <message name="loginResponse"> + <part name="loginReturn" type="xsd:string" /> + </message> + <message name="resourcesRequest"> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="resourcesResponse"> + <part name="resourcesReturn" type="typens:ArrayOfApis" /> + </message> + <message name="globalFaults"> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="globalFaultsResponse"> + <part name="globalFaultsReturn" type="typens:ArrayOfExistsFaltures" /> + </message> + <message name="resourceFaults"> + <part name="resourceName" type="xsd:string" /> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="resourceFaultsResponse"> + <part name="resourceFaultsReturn" type="typens:ArrayOfExistsFaltures" /> + </message> + <message name="startSession" /> + <message name="startSessionResponse"> + <part name="startSessionReturn" type="xsd:string" /> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="endSession"> + <documentation>End web service session</documentation> + <input message="typens:endSession" /> + <output message="typens:endSessionResponse" /> + </operation> + <operation name="login"> + <documentation>Login user and retrive session id</documentation> + <input message="typens:login" /> + <output message="typens:loginResponse" /> + </operation> + <operation name="startSession"> + <documentation>Start web service session</documentation> + <input message="typens:startSession" /> + <output message="typens:startSessionResponse" /> + </operation> + <operation name="resources"> + <documentation>List of available resources</documentation> + <input message="typens:resourcesRequest" /> + <output message="typens:resourcesResponse" /> + </operation> + <operation name="globalFaults"> + <documentation>List of global faults</documentation> + <input message="typens:globalFaults" /> + <output message="typens:globalFaultsResponse" /> + </operation> + <operation name="resourceFaults"> + <documentation>List of resource faults</documentation> + <input message="typens:resourceFaults" /> + <output message="typens:resourceFaultsResponse" /> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="endSession"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="login"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="startSession"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="resources"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="globalFaults"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="resourceFaults"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/Api/etc/wsi.xml b/app/code/core/Mage/Api/etc/wsi.xml new file mode 100644 index 00000000000..0db28ab2869 --- /dev/null +++ b/app/code/core/Mage/Api/etc/wsi.xml @@ -0,0 +1,381 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="associativeEntity"> + <xsd:sequence> + <xsd:element name="key" type="xsd:string" /> + <xsd:element name="value" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="associativeArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:associativeEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="associativeMultiEntity"> + <xsd:sequence> + <xsd:element name="key" type="xsd:string" /> + <xsd:element name="value" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="associativeMultiArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:associativeMultiEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="complexFilter"> + <xsd:sequence> + <xsd:element name="key" type="xsd:string" /> + <xsd:element name="value" type="typens:associativeEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="complexFilterArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:complexFilter" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="filters"> + <xsd:sequence> + <xsd:element name="filter" type="typens:associativeArray" minOccurs="0" /> + <xsd:element name="complex_filter" type="typens:complexFilterArray" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ArrayOfString"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ArrayOfInt"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="apiMethodEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" /> + <xsd:element name="path" type="xsd:string" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="aliases" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ArrayOfApiMethods"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:apiMethodEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="apiEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="aliases" type="typens:ArrayOfString" /> + <xsd:element name="methods" type="typens:ArrayOfApiMethods" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ArrayOfApis"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:apiEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="existsFaltureEntity"> + <xsd:sequence> + <xsd:element name="code" type="xsd:string" /> + <xsd:element name="message" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ArrayOfExistsFaltures"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:existsFaltureEntity" /> + </xsd:sequence> + </xsd:complexType> + + + + <xsd:element name="callParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="apiPath" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="args" type="xsd:anyType" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="callResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:anyType" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="multiCallParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="calls" type="xsd:anyType" /> + <xsd:element minOccurs="1" maxOccurs="1" name="options" type="xsd:anyType" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="multiCallResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:anyType" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="endSessionParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="endSessionResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="loginParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="username" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="apiKey" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="loginResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="resourcesRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="resourcesResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:ArrayOfApis" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="globalFaultsParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="globalFaultsResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:ArrayOfExistsFaltures" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="resourceFaultsParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="resourceName" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="resourceFaultsResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:ArrayOfExistsFaltures" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="startSessionResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="call"> + <wsdl:part name="parameters" element="typens:callParam" /> + </wsdl:message> + <wsdl:message name="callResponse"> + <wsdl:part name="parameters" element="typens:callResponseParam" /> + </wsdl:message> + <wsdl:message name="multiCall"> + <wsdl:part name="parameters" element="typens:multiCallParam" /> + </wsdl:message> + <wsdl:message name="multiCallResponse"> + <wsdl:part name="parameters" element="typens:multiCallResponseParam" /> + </wsdl:message> + <wsdl:message name="endSession"> + <wsdl:part name="parameters" element="typens:endSessionParam" /> + </wsdl:message> + <wsdl:message name="endSessionResponse"> + <wsdl:part name="parameters" element="typens:endSessionResponseParam" /> + </wsdl:message> + <wsdl:message name="login"> + <wsdl:part name="parameters" element="typens:loginParam" /> + </wsdl:message> + <wsdl:message name="loginResponse"> + <wsdl:part name="parameters" element="typens:loginResponseParam" /> + </wsdl:message> + <wsdl:message name="resourcesRequest"> + <wsdl:part name="parameters" element="typens:resourcesRequestParam" /> + </wsdl:message> + <wsdl:message name="resourcesResponse"> + <wsdl:part name="parameters" element="typens:resourcesResponseParam" /> + </wsdl:message> + <wsdl:message name="globalFaults"> + <wsdl:part name="parameters" element="typens:globalFaultsParam" /> + </wsdl:message> + <wsdl:message name="globalFaultsResponse"> + <wsdl:part name="parameters" element="typens:globalFaultsResponseParam" /> + </wsdl:message> + <wsdl:message name="resourceFaults"> + <wsdl:part name="parameters" element="typens:resourceFaultsParam" /> + </wsdl:message> + <wsdl:message name="resourceFaultsResponse"> + <wsdl:part name="parameters" element="typens:resourceFaultsResponseParam" /> + </wsdl:message> + <wsdl:message name="startSession" /> + <wsdl:message name="startSessionResponse"> + <wsdl:part name="parameters" element="typens:startSessionResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="call"> + <wsdl:documentation>Call api functionality</wsdl:documentation> + <wsdl:input message="typens:call" /> + <wsdl:output message="typens:callResponse" /> + </wsdl:operation> + <wsdl:operation name="multiCall"> + <wsdl:documentation>Multiple calls of resource functionality</wsdl:documentation> + <wsdl:input message="typens:multiCall" /> + <wsdl:output message="typens:multiCallResponse" /> + </wsdl:operation> + <wsdl:operation name="endSession"> + <wsdl:documentation>End web service session</wsdl:documentation> + <wsdl:input message="typens:endSession" /> + <wsdl:output message="typens:endSessionResponse" /> + </wsdl:operation> + <wsdl:operation name="login"> + <wsdl:documentation>Login user and retrive session id</wsdl:documentation> + <wsdl:input message="typens:login" /> + <wsdl:output message="typens:loginResponse" /> + </wsdl:operation> + <wsdl:operation name="startSession"> + <wsdl:documentation>Start web service session</wsdl:documentation> + <wsdl:input message="typens:startSession" /> + <wsdl:output message="typens:startSessionResponse" /> + </wsdl:operation> + <wsdl:operation name="resources"> + <wsdl:documentation>List of available resources</wsdl:documentation> + <wsdl:input message="typens:resourcesRequest" /> + <wsdl:output message="typens:resourcesResponse" /> + </wsdl:operation> + <wsdl:operation name="globalFaults"> + <wsdl:documentation>List of global faults</wsdl:documentation> + <wsdl:input message="typens:globalFaults" /> + <wsdl:output message="typens:globalFaultsResponse" /> + </wsdl:operation> + <wsdl:operation name="resourceFaults"> + <wsdl:documentation>List of resource faults</wsdl:documentation> + <wsdl:input message="typens:resourceFaults" /> + <wsdl:output message="typens:resourceFaultsResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="call"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="multiCall"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="endSession"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="login"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="startSession"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="resources"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="globalFaults"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="resourceFaults"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="{{var wsdl.name}}Service"> + <wsdl:port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/app/code/core/Mage/Api/locale/de_DE/Mage_Api.csv b/app/code/core/Mage/Api/locale/de_DE/Mage_Api.csv new file mode 100644 index 00000000000..4d060c6fd98 --- /dev/null +++ b/app/code/core/Mage/Api/locale/de_DE/Mage_Api.csv @@ -0,0 +1,16 @@ +"Access denied.","Zugang verweigert." +"Client Session Timeout (sec.)","Kunde Session-Timeout (in Sekunden)" +"Default Response Charset","Standard-Schriftsatz für Antwort" +"Email","E-Mail" +"General Settings","Allgemeine Einstellungen" +"Invalid webservice adapter specified.","Ungültiger Webservice Adapter angegeben." +"Invalid webservice handler specified.","Ungültiger Webservice Handler angegeben." +"Magento Core API","Magento Core API" +"Magento Core API Section","Magento Core API Sektion" +"Roles","Rollen" +"Unable to login.","Einloggen nicht möglich." +"User Name","Benutzername" +"Users","Benutzer" +"WS-I Compliance","WS-I Übereinstimmung" +"Web Services","Webdienste" +"Your account has been deactivated.","Ihr Benutzerkonto wurde deaktiviert." diff --git a/app/code/core/Mage/Api/locale/en_US/Mage_Api.csv b/app/code/core/Mage/Api/locale/en_US/Mage_Api.csv new file mode 100644 index 00000000000..5c6674a0d99 --- /dev/null +++ b/app/code/core/Mage/Api/locale/en_US/Mage_Api.csv @@ -0,0 +1,16 @@ +"Access denied.","Access denied." +"Client Session Timeout (sec.)","Client Session Timeout (sec.)" +"Default Response Charset","Default Response Charset" +"Email","Email" +"General Settings","General Settings" +"Invalid webservice adapter specified.","Invalid webservice adapter specified." +"Invalid webservice handler specified.","Invalid webservice handler specified." +"Magento Core API","Magento Core API" +"Magento Core API Section","Magento Core API Section" +"Roles","Roles" +"Unable to login.","Unable to login." +"User Name","User Name" +"Users","Users" +"WS-I Compliance","WS-I Compliance" +"Web Services","Web Services" +"Your account has been deactivated.","Your account has been deactivated." diff --git a/app/code/core/Mage/Api/locale/es_ES/Mage_Api.csv b/app/code/core/Mage/Api/locale/es_ES/Mage_Api.csv new file mode 100644 index 00000000000..972a0ac704b --- /dev/null +++ b/app/code/core/Mage/Api/locale/es_ES/Mage_Api.csv @@ -0,0 +1,16 @@ +"Access denied.","Acceso denegado" +"Client Session Timeout (sec.)","Plazo lÃmite de la sesión cliente (seg.)" +"Default Response Charset","Conjunto de caracteres de respuesta por omisión" +"Email","Correo electrónico" +"General Settings","Opciones generales" +"Invalid webservice adapter specified.","Adaptador de servicio web especificado inválido" +"Invalid webservice handler specified.","Controlador de servicio web especificado inválido" +"Magento Core API","API del núcleo de Magento" +"Magento Core API Section","Apartado de la API (interfaz de programación de aplicaciones) del núcleo de Magento" +"Roles","Roles" +"Unable to login.","No es posible entrar al sistema." +"User Name","Nombre de usuario" +"Users","Usuarios" +"WS-I Compliance","Conformidad con WS-I" +"Web Services","Servicios web" +"Your account has been deactivated.","Se ha desactivado su cuenta." diff --git a/app/code/core/Mage/Api/locale/fr_FR/Mage_Api.csv b/app/code/core/Mage/Api/locale/fr_FR/Mage_Api.csv new file mode 100644 index 00000000000..9389383ef21 --- /dev/null +++ b/app/code/core/Mage/Api/locale/fr_FR/Mage_Api.csv @@ -0,0 +1,16 @@ +"Access denied.","Accès refusé." +"Client Session Timeout (sec.)","Expiration de la session client (secondes)" +"Default Response Charset","Table de caractères de la réponse par défaut" +"Email","Email" +"General Settings","Réglages généraux" +"Invalid webservice adapter specified.","Adaptateur de service web invalide." +"Invalid webservice handler specified.","Gérant de service web invalide." +"Magento Core API","Magento Core API" +"Magento Core API Section","Magento Core API Section" +"Roles","Rôles" +"Unable to login.","Connexion impossible." +"User Name","Nom d'utilisateur" +"Users","Utilisateurs" +"WS-I Compliance","Conforme à WS-I" +"Web Services","Services Web" +"Your account has been deactivated.","Votre compte a été désactivé." diff --git a/app/code/core/Mage/Api/locale/nl_NL/Mage_Api.csv b/app/code/core/Mage/Api/locale/nl_NL/Mage_Api.csv new file mode 100644 index 00000000000..62570ad76ad --- /dev/null +++ b/app/code/core/Mage/Api/locale/nl_NL/Mage_Api.csv @@ -0,0 +1,16 @@ +"Access denied.","Toegang geweigerd." +"Client Session Timeout (sec.)","Klant Sessie Time out (sec.)" +"Default Response Charset","Karakterset standaard antwoord" +"Email","Email" +"General Settings","Algemene instellingen" +"Invalid webservice adapter specified.","Ongeldige webdienst adapter gespecificeerd." +"Invalid webservice handler specified.","Ongeldige webservice handler gespecificeerd." +"Magento Core API","Magento Core API" +"Magento Core API Section","Magento Core API Sectie" +"Roles","Rollen" +"Unable to login.","Kan niet inloggen." +"User Name","Gebruikersnaam" +"Users","Gebruikers" +"WS-I Compliance","WS-I naleving" +"Web Services","Web Diensten" +"Your account has been deactivated.","Uw account is gedeactiveerd." diff --git a/app/code/core/Mage/Api/locale/pt_BR/Mage_Api.csv b/app/code/core/Mage/Api/locale/pt_BR/Mage_Api.csv new file mode 100644 index 00000000000..bebef0b86a0 --- /dev/null +++ b/app/code/core/Mage/Api/locale/pt_BR/Mage_Api.csv @@ -0,0 +1,16 @@ +"Access denied.","Acesso negado." +"Client Session Timeout (sec.)","Tempo Limite da Sessão de Cliente (seg.)" +"Default Response Charset","Conjunto de Caracteres Predefinido de Resposta" +"Email","E-mail" +"General Settings","Definições Gerais" +"Invalid webservice adapter specified.","Adaptador de serviço de rede especificado inválido." +"Invalid webservice handler specified.","Processador de serviço de rede especificado inválido." +"Magento Core API","Núcleo Magento API" +"Magento Core API Section","Seção Núcleo Magento API" +"Roles","Funções" +"Unable to login.","Incapaz de entrar." +"User Name","Nome do Usuário" +"Users","Usuários" +"WS-I Compliance","Conformidade WS-I" +"Web Services","Serviços Web" +"Your account has been deactivated.","Sua conta foi desativada." diff --git a/app/code/core/Mage/Api/locale/zh_CN/Mage_Api.csv b/app/code/core/Mage/Api/locale/zh_CN/Mage_Api.csv new file mode 100644 index 00000000000..9130432dcad --- /dev/null +++ b/app/code/core/Mage/Api/locale/zh_CN/Mage_Api.csv @@ -0,0 +1,16 @@ +"Access denied.","访问被拒ç»" +"Client Session Timeout (sec.)","客户端会è¯è¶…时(秒。)" +"Default Response Charset","默认å“应å—符集" +"Email","电å邮件" +"General Settings","常规设置" +"Invalid webservice adapter specified.","指定的WebæœåС适é…å™¨æ— æ•ˆã€‚" +"Invalid webservice handler specified.","指定的WebæœåС处ç†ç¨‹åºæ— 效。" +"Magento Core API","Magento Core API" +"Magento Core API Section","Magento Core API 部分" +"Roles","角色" +"Unable to login.","æ— æ³•ç™»å½•ã€‚" +"User Name","用户å" +"Users","用户" +"WS-I Compliance","WS-I 兼容" +"Web Services","WebæœåŠ¡" +"Your account has been deactivated.","æ‚¨çš„å¸æˆ·å·²è¢«æ’¤é”€ã€‚" diff --git a/app/code/core/Mage/Api/sql/api_setup/install-1.6.0.0.php b/app/code/core/Mage/Api/sql/api_setup/install-1.6.0.0.php new file mode 100644 index 00000000000..d47e2af4001 --- /dev/null +++ b/app/code/core/Mage/Api/sql/api_setup/install-1.6.0.0.php @@ -0,0 +1,208 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Api + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Api install + * + * @category Mage + * @package Mage_Api + * @author Magento Core Team <core@magentocommerce.com> + */ +$installer = $this; +/* @var $installer Mage_Core_Model_Resource_Setup */ + +$installer->startSetup(); + +/** + * Create table 'api_assert' + */ +$table = $installer->getConnection() + ->newTable($installer->getTable('api_assert')) + ->addColumn('assert_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'identity' => true, + 'unsigned' => true, + 'nullable' => false, + 'primary' => true, + ), 'Assert id') + ->addColumn('assert_type', Varien_Db_Ddl_Table::TYPE_TEXT, 20, array( + ), 'Assert type') + ->addColumn('assert_data', Varien_Db_Ddl_Table::TYPE_TEXT, '64k', array( + ), 'Assert additional data') + ->setComment('Api ACL Asserts'); +$installer->getConnection()->createTable($table); + +/** + * Create table 'api_role' + */ +$table = $installer->getConnection() + ->newTable($installer->getTable('api_role')) + ->addColumn('role_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'identity' => true, + 'unsigned' => true, + 'nullable' => false, + 'primary' => true, + ), 'Role id') + ->addColumn('parent_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'unsigned' => true, + 'nullable' => false, + 'default' => '0', + ), 'Parent role id') + ->addColumn('tree_level', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array( + 'unsigned' => true, + 'nullable' => false, + 'default' => '0', + ), 'Role level in tree') + ->addColumn('sort_order', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array( + 'unsigned' => true, + 'nullable' => false, + 'default' => '0', + ), 'Sort order to display on admin area') + ->addColumn('role_type', Varien_Db_Ddl_Table::TYPE_TEXT, 1, array( + 'nullable' => false, + 'default' => '0', + ), 'Role type') + ->addColumn('user_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'unsigned' => true, + 'nullable' => false, + 'default' => '0', + ), 'User id') + ->addColumn('role_name', Varien_Db_Ddl_Table::TYPE_TEXT, 50, array( + ), 'Role name') + ->addIndex($installer->getIdxName('api_role', array('parent_id', 'sort_order')), + array('parent_id', 'sort_order')) + ->addIndex($installer->getIdxName('api_role', array('tree_level')), + array('tree_level')) + ->setComment('Api ACL Roles'); +$installer->getConnection()->createTable($table); + +/** + * Create table 'api_rule' + */ +$table = $installer->getConnection() + ->newTable($installer->getTable('api_rule')) + ->addColumn('rule_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'identity' => true, + 'unsigned' => true, + 'nullable' => false, + 'primary' => true, + ), 'Api rule Id') + ->addColumn('role_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'unsigned' => true, + 'nullable' => false, + 'default' => '0', + ), 'Api role Id') + ->addColumn('resource_id', Varien_Db_Ddl_Table::TYPE_TEXT, 255, array( + ), 'Module code') + ->addColumn('api_privileges', Varien_Db_Ddl_Table::TYPE_TEXT, 20, array( + ), 'Privileges') + ->addColumn('assert_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'unsigned' => true, + 'nullable' => false, + 'default' => '0', + ), 'Assert id') + ->addColumn('role_type', Varien_Db_Ddl_Table::TYPE_TEXT, 1, array( + ), 'Role type') + ->addColumn('api_permission', Varien_Db_Ddl_Table::TYPE_TEXT, 10, array( + ), 'Permission') + ->addIndex($installer->getIdxName('api_rule', array('resource_id', 'role_id')), + array('resource_id', 'role_id')) + ->addIndex($installer->getIdxName('api_rule', array('role_id', 'resource_id')), + array('role_id', 'resource_id')) + ->addForeignKey($installer->getFkName('api_rule', 'role_id', 'api_role', 'role_id'), + 'role_id', $installer->getTable('api_role'), 'role_id', + Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE) + ->setComment('Api ACL Rules'); +$installer->getConnection()->createTable($table); + +/** + * Create table 'api_user' + */ +$table = $installer->getConnection() + ->newTable($installer->getTable('api_user')) + ->addColumn('user_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'identity' => true, + 'unsigned' => true, + 'nullable' => false, + 'primary' => true, + ), 'User id') + ->addColumn('firstname', Varien_Db_Ddl_Table::TYPE_TEXT, 32, array( + ), 'First name') + ->addColumn('lastname', Varien_Db_Ddl_Table::TYPE_TEXT, 32, array( + ), 'Last name') + ->addColumn('email', Varien_Db_Ddl_Table::TYPE_TEXT, 128, array( + ), 'Email') + ->addColumn('username', Varien_Db_Ddl_Table::TYPE_TEXT, 40, array( + ), 'Nickname') + ->addColumn('api_key', Varien_Db_Ddl_Table::TYPE_TEXT, 40, array( + ), 'Api key') + ->addColumn('created', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array( + 'nullable' => false, + ), 'User record create date') + ->addColumn('modified', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array( + ), 'User record modify date') + ->addColumn('lognum', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array( + 'unsigned' => true, + 'nullable' => false, + 'default' => '0', + ), 'Quantity of log ins') + ->addColumn('reload_acl_flag', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array( + 'nullable' => false, + 'default' => '0', + ), 'Refresh ACL flag') + ->addColumn('is_active', Varien_Db_Ddl_Table::TYPE_SMALLINT, null, array( + 'nullable' => false, + 'default' => '1', + ), 'Account status') + ->setComment('Api Users'); +$installer->getConnection()->createTable($table); + +/** + * Create table 'api_session' + */ +$table = $installer->getConnection() + ->newTable($installer->getTable('api_session')) + ->addColumn('user_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( + 'unsigned' => true, + 'nullable' => false, + ), 'User id') + ->addColumn('logdate', Varien_Db_Ddl_Table::TYPE_TIMESTAMP, null, array( + 'nullable' => false, + ), 'Login date') + ->addColumn('sessid', Varien_Db_Ddl_Table::TYPE_TEXT, 40, array( + ), 'Sessioin id') + ->addIndex($installer->getIdxName('api_session', array('user_id')), + array('user_id')) + ->addIndex($installer->getIdxName('api_session', array('sessid')), + array('sessid')) + ->addForeignKey($installer->getFkName('api_session', 'user_id', 'api_user', 'user_id'), + 'user_id', $installer->getTable('api_user'), 'user_id', + Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE) + ->setComment('Api Sessions'); +$installer->getConnection()->createTable($table); + + + +$installer->endSetup(); diff --git a/app/code/core/Mage/Backend/Block/Abstract.php b/app/code/core/Mage/Backend/Block/Abstract.php index 3d4d163fb86..6dda3399ee7 100644 --- a/app/code/core/Mage/Backend/Block/Abstract.php +++ b/app/code/core/Mage/Backend/Block/Abstract.php @@ -29,7 +29,9 @@ * * @category Mage * @package Mage_Backend - * @author Magento Core Team <core@magentocommerce.com> + * @author Magento Core Team <core@magentocommerce.com> + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Mage_Backend_Block_Abstract extends Mage_Core_Block_Template { @@ -45,6 +47,8 @@ class Mage_Backend_Block_Abstract extends Mage_Core_Block_Template * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param array $data * @@ -62,11 +66,13 @@ class Mage_Backend_Block_Abstract extends Mage_Core_Block_Template Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); } } diff --git a/app/code/core/Mage/Backend/Block/Catalog/Product/Tab/Container.php b/app/code/core/Mage/Backend/Block/Catalog/Product/Tab/Container.php new file mode 100644 index 00000000000..c1a695ea5e5 --- /dev/null +++ b/app/code/core/Mage/Backend/Block/Catalog/Product/Tab/Container.php @@ -0,0 +1,70 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Backend + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Backend_Block_Catalog_Product_Tab_Container extends Mage_Backend_Block_Template + implements Mage_Backend_Block_Widget_Tab_Interface +{ + + /** + * Return Tab label + * + * @return string + */ + public function getTabLabel() + { + return ''; + } + + /** + * Return Tab title + * + * @return string + */ + public function getTabTitle() + { + return $this->getTabLabel(); + } + + /** + * Can show tab in tabs + * + * @return boolean + */ + public function canShowTab() + { + return true; + } + + /** + * Tab is hidden + * + * @return boolean + */ + public function isHidden() + { + return false; + } +} diff --git a/app/code/core/Mage/Backend/Block/Store/Switcher.php b/app/code/core/Mage/Backend/Block/Store/Switcher.php index e899dc9f8cb..23f4d599cf7 100644 --- a/app/code/core/Mage/Backend/Block/Store/Switcher.php +++ b/app/code/core/Mage/Backend/Block/Store/Switcher.php @@ -92,6 +92,8 @@ class Mage_Backend_Block_Store_Switcher extends Mage_Backend_Block_Template protected $_storeGroupFactory; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -103,6 +105,8 @@ class Mage_Backend_Block_Store_Switcher extends Mage_Backend_Block_Template * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $application * @param Mage_Core_Model_Website_Factory $websiteFactory @@ -123,6 +127,8 @@ class Mage_Backend_Block_Store_Switcher extends Mage_Backend_Block_Template Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_App $application, Mage_Core_Model_Website_Factory $websiteFactory, @@ -130,7 +136,7 @@ class Mage_Backend_Block_Store_Switcher extends Mage_Backend_Block_Template array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data); $this->_application = $application; $this->_websiteFactory = $websiteFactory; $this->_storeGroupFactory = $storeGroupFactory; diff --git a/app/code/core/Mage/Backend/Block/System/Config/Edit.php b/app/code/core/Mage/Backend/Block/System/Config/Edit.php index 481459bdd67..11437b020fd 100644 --- a/app/code/core/Mage/Backend/Block/System/Config/Edit.php +++ b/app/code/core/Mage/Backend/Block/System/Config/Edit.php @@ -69,6 +69,8 @@ class Mage_Backend_Block_System_Config_Edit extends Mage_Backend_Block_Widget * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Backend_Model_Config_Structure $configStructure * @param array $data @@ -87,12 +89,14 @@ class Mage_Backend_Block_System_Config_Edit extends Mage_Backend_Block_Widget Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Backend_Model_Config_Structure $configStructure, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); $this->_configStructure = $configStructure; } diff --git a/app/code/core/Mage/Backend/Block/System/Config/Form.php b/app/code/core/Mage/Backend/Block/System/Config/Form.php index 9248b2bde74..513d5d98775 100644 --- a/app/code/core/Mage/Backend/Block/System/Config/Form.php +++ b/app/code/core/Mage/Backend/Block/System/Config/Form.php @@ -133,6 +133,8 @@ class Mage_Backend_Block_System_Config_Form extends Mage_Backend_Block_Widget_Fo protected $_coreConfig; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -144,6 +146,8 @@ class Mage_Backend_Block_System_Config_Form extends Mage_Backend_Block_Widget_Fo * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Backend_Model_Config_Factory $configFactory * @param Varien_Data_Form_Factory $formFactory @@ -168,6 +172,8 @@ class Mage_Backend_Block_System_Config_Form extends Mage_Backend_Block_Widget_Fo Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Backend_Model_Config_Factory $configFactory, Varien_Data_Form_Factory $formFactory, @@ -179,7 +185,8 @@ class Mage_Backend_Block_System_Config_Form extends Mage_Backend_Block_Widget_Fo array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); $this->_configFactory = $configFactory; $this->_formFactory = $formFactory; $this->_cloneModelFactory = $cloneModelFactory; diff --git a/app/code/core/Mage/Backend/Block/System/Config/Form/Field.php b/app/code/core/Mage/Backend/Block/System/Config/Form/Field.php index 87d6c11fb5b..1d2239516bb 100644 --- a/app/code/core/Mage/Backend/Block/System/Config/Form/Field.php +++ b/app/code/core/Mage/Backend/Block/System/Config/Form/Field.php @@ -34,7 +34,7 @@ * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Mage_Backend_Block_System_Config_Form_Field - extends Mage_Backend_Block_Abstract + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { /** @@ -45,6 +45,8 @@ class Mage_Backend_Block_System_Config_Form_Field protected $_application; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -56,6 +58,8 @@ class Mage_Backend_Block_System_Config_Form_Field * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $application * @param array $data @@ -74,13 +78,15 @@ class Mage_Backend_Block_System_Config_Form_Field Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_App $application, array $data = array() ) { $this->_application = $application; parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); } diff --git a/app/code/core/Mage/Backend/Block/System/Config/Form/Field/Heading.php b/app/code/core/Mage/Backend/Block/System/Config/Form/Field/Heading.php index 037b7de0a44..6a532dcfcb4 100644 --- a/app/code/core/Mage/Backend/Block/System/Config/Form/Field/Heading.php +++ b/app/code/core/Mage/Backend/Block/System/Config/Form/Field/Heading.php @@ -31,7 +31,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Backend_Block_System_Config_Form_Field_Heading - extends Mage_Backend_Block_Abstract implements Varien_Data_Form_Element_Renderer_Interface + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { /** * Render element html diff --git a/app/code/core/Mage/Backend/Block/System/Config/Form/Fieldset.php b/app/code/core/Mage/Backend/Block/System/Config/Form/Fieldset.php index d27d31ecbd8..64386ce1b16 100644 --- a/app/code/core/Mage/Backend/Block/System/Config/Form/Fieldset.php +++ b/app/code/core/Mage/Backend/Block/System/Config/Form/Fieldset.php @@ -33,7 +33,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Backend_Block_System_Config_Form_Fieldset - extends Mage_Backend_Block_Abstract + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { diff --git a/app/code/core/Mage/Backend/Block/System/Config/Tabs.php b/app/code/core/Mage/Backend/Block/System/Config/Tabs.php index e72e8eb0326..edc23dd8c7b 100644 --- a/app/code/core/Mage/Backend/Block/System/Config/Tabs.php +++ b/app/code/core/Mage/Backend/Block/System/Config/Tabs.php @@ -73,6 +73,8 @@ class Mage_Backend_Block_System_Config_Tabs extends Mage_Backend_Block_Widget protected $_storeCode; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -84,6 +86,8 @@ class Mage_Backend_Block_System_Config_Tabs extends Mage_Backend_Block_Widget * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Backend_Model_Config_Structure $configStructure * @param array $data @@ -102,12 +106,15 @@ class Mage_Backend_Block_System_Config_Tabs extends Mage_Backend_Block_Widget Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Backend_Model_Config_Structure $configStructure, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); $this->_tabs = $configStructure->getTabs(); $this->setId('system_config_tabs'); diff --git a/app/code/core/Mage/Backend/Block/Template.php b/app/code/core/Mage/Backend/Block/Template.php index 8bcdb7dcc50..5a125de297a 100644 --- a/app/code/core/Mage/Backend/Block/Template.php +++ b/app/code/core/Mage/Backend/Block/Template.php @@ -49,6 +49,8 @@ class Mage_Backend_Block_Template extends Mage_Core_Block_Template * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param array $data * @@ -66,11 +68,13 @@ class Mage_Backend_Block_Template extends Mage_Core_Block_Template Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data); } /** diff --git a/app/code/core/Mage/Backend/Block/Widget/Form/Element/Dependence.php b/app/code/core/Mage/Backend/Block/Widget/Form/Element/Dependence.php index 9429e122de3..464ccd6377d 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Form/Element/Dependence.php +++ b/app/code/core/Mage/Backend/Block/Widget/Form/Element/Dependence.php @@ -29,7 +29,7 @@ * Assumes that one element may depend on other element values. * Will toggle as "enabled" only if all elements it depends from toggle as true. */ -class Mage_Backend_Block_Widget_Form_Element_Dependence extends Mage_Backend_Block_Abstract +class Mage_Backend_Block_Widget_Form_Element_Dependence extends Mage_Core_Block_Template { /** * name => id mapper diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Column.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Column.php index 7c45a2c456f..5f9d1502f7d 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Grid/Column.php +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Column.php @@ -67,24 +67,26 @@ class Mage_Backend_Block_Widget_Grid_Column extends Mage_Backend_Block_Widget * @var array */ protected $_rendererTypes = array( - 'date' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Date', - 'datetime' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Datetime', - 'number' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Number', - 'currency' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Currency', - 'price' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Price', - 'country' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Country', - 'concat' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Concat', - 'action' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Action', - 'options' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Options', - 'checkbox' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Checkbox', + 'action' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Action', + 'button' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Button', + 'checkbox' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Checkbox', + 'concat' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Concat', + 'country' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Country', + 'currency' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Currency', + 'date' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Date', + 'datetime' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Datetime', + 'default' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Text', + 'grip' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Grip', + 'input' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Input', 'massaction' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Massaction', - 'radio' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Radio', - 'input' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Input', - 'select' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Select', - 'text' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Longtext', - 'store' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Store', - 'wrapline' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Wrapline', - 'default' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Text', + 'number' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Number', + 'options' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Options', + 'price' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Price', + 'radio' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Radio', + 'select' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Select', + 'store' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Store', + 'text' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Longtext', + 'wrapline' => 'Mage_Backend_Block_Widget_Grid_Column_Renderer_Wrapline', ); /** diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Filter/Abstract.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Filter/Abstract.php index 8ffe8e65435..d1255f36132 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Filter/Abstract.php +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Filter/Abstract.php @@ -31,7 +31,7 @@ * @package Mage_Backend * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Backend_Block_Widget_Grid_Column_Filter_Abstract extends Mage_Backend_Block_Abstract +class Mage_Backend_Block_Widget_Grid_Column_Filter_Abstract extends Mage_Core_Block_Template implements Mage_Backend_Block_Widget_Grid_Column_Filter_Interface { diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Multistore.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Multistore.php index 378c20fafd0..4b0eac884b1 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Multistore.php +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Multistore.php @@ -41,6 +41,8 @@ class Mage_Backend_Block_Widget_Grid_Column_Multistore extends Mage_Backend_Bloc protected $_app; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -52,6 +54,8 @@ class Mage_Backend_Block_Widget_Grid_Column_Multistore extends Mage_Backend_Bloc * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $application * @param array $data @@ -70,12 +74,14 @@ class Mage_Backend_Block_Widget_Grid_Column_Multistore extends Mage_Backend_Bloc Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_App $application, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); $this->_app = $application; } diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Abstract.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Abstract.php index 3d5d3b39490..cacd32d8e99 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Abstract.php +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Abstract.php @@ -33,7 +33,7 @@ */ abstract class Mage_Backend_Block_Widget_Grid_Column_Renderer_Abstract - extends Mage_Backend_Block_Abstract implements Mage_Backend_Block_Widget_Grid_Column_Renderer_Interface + extends Mage_Core_Block_Template implements Mage_Backend_Block_Widget_Grid_Column_Renderer_Interface { protected $_defaultWidth; protected $_column; diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Button.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Button.php new file mode 100644 index 00000000000..51f6e5772d3 --- /dev/null +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Button.php @@ -0,0 +1,45 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Backend + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Backend_Block_Widget_Grid_Column_Renderer_Button + extends Mage_Backend_Block_Widget_Grid_Column_Renderer_Abstract +{ + /** + * Render grid row + * + * @param Varien_Object $row + * @return string + */ + public function render(Varien_Object $row) + { + $buttonType = $this->getColumn()->getButtonType(); + return '<button' + . ($buttonType ? ' type="' . $buttonType . '"' : '') + .'>' + . $this->getColumn()->getHeader() + . '</button>'; + } +} diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Currency.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Currency.php index 7d6cf0f49a8..70b849f819b 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Currency.php +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Currency.php @@ -62,6 +62,8 @@ class Mage_Backend_Block_Widget_Grid_Column_Renderer_Currency protected $_currencyLocator; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -73,8 +75,10 @@ class Mage_Backend_Block_Widget_Grid_Column_Renderer_Currency * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem - * @param Mage_Core_MOdel_App $app + * @param Mage_Core_Model_App $app * @param Mage_Core_Model_Locale $locale * @param Mage_Directory_Model_Currency_DefaultLocator $currencyLocator * @param array $data @@ -93,14 +97,17 @@ class Mage_Backend_Block_Widget_Grid_Column_Renderer_Currency Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, - Mage_Core_MOdel_App $app, + Mage_Core_Model_App $app, Mage_Core_Model_Locale $locale, Mage_Directory_Model_Currency_DefaultLocator $currencyLocator, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); $this->_app = $app; $this->_locale = $locale; $this->_currencyLocator = $currencyLocator; diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Grip.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Grip.php new file mode 100644 index 00000000000..9d6f8f9dc29 --- /dev/null +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Column/Renderer/Grip.php @@ -0,0 +1,42 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Backend + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Backend_Block_Widget_Grid_Column_Renderer_Grip + extends Mage_Backend_Block_Widget_Grid_Column_Renderer_Abstract +{ + /** + * Render grid row + * + * @param Varien_Object $row + * @return string + */ + public function render(Varien_Object $row) + { + return '<span class="' . $this->getColumn()->getInlineCss() . '"></span>' + . '<input type="hidden" name="entity_id" value="' . $row->getData($this->getColumn()->getIndex()) . '"/>' + . '<input type="hidden" name="position" value=""/>'; + } +} diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/ColumnSet.php b/app/code/core/Mage/Backend/Block/Widget/Grid/ColumnSet.php index 43ff0f47db5..b5acc9dcc7b 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Grid/ColumnSet.php +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/ColumnSet.php @@ -121,6 +121,8 @@ class Mage_Backend_Block_Widget_Grid_ColumnSet extends Mage_Core_Block_Template protected $_totals = null; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -132,6 +134,8 @@ class Mage_Backend_Block_Widget_Grid_ColumnSet extends Mage_Core_Block_Template * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Backend_Helper_Data $helper * @param Mage_Backend_Model_Widget_Grid_Row_UrlGeneratorFactory $generatorFactory @@ -154,6 +158,8 @@ class Mage_Backend_Block_Widget_Grid_ColumnSet extends Mage_Core_Block_Template Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Backend_Helper_Data $helper, Mage_Backend_Model_Widget_Grid_Row_UrlGeneratorFactory $generatorFactory, @@ -178,7 +184,7 @@ class Mage_Backend_Block_Widget_Grid_ColumnSet extends Mage_Core_Block_Template ); parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data); $this->setEmptyText($this->_helper->__( isset($data['empty_text'])? $data['empty_text'] : 'No records found.' diff --git a/app/code/core/Mage/Backend/Block/Widget/Grid/Massaction/Abstract.php b/app/code/core/Mage/Backend/Block/Widget/Grid/Massaction/Abstract.php index 69edb6106b7..40e83c96eeb 100644 --- a/app/code/core/Mage/Backend/Block/Widget/Grid/Massaction/Abstract.php +++ b/app/code/core/Mage/Backend/Block/Widget/Grid/Massaction/Abstract.php @@ -331,8 +331,11 @@ abstract class Mage_Backend_Block_Widget_Grid_Massaction_Abstract extends Mage_B ->setGrid($gridBlock) ->setId($columnId); + /** @var $columnSetBlock Mage_Backend_Block_Widget_Grid_ColumnSet */ $columnSetBlock = $gridBlock->getColumnSet(); - $columnSetBlock->insert($massactionColumn, count($columnSetBlock->getColumns()) + 1, false, $columnId); + $childNames = $columnSetBlock->getChildNames(); + $siblingElement = count($childNames) ? current($childNames) : 0; + $columnSetBlock->insert($massactionColumn, $siblingElement, false, $columnId); return $this; } } diff --git a/app/code/core/Mage/Backend/Model/Config/Backend/Baseurl.php b/app/code/core/Mage/Backend/Model/Config/Backend/Baseurl.php index fd7aef02d15..2871c24a2c4 100644 --- a/app/code/core/Mage/Backend/Model/Config/Backend/Baseurl.php +++ b/app/code/core/Mage/Backend/Model/Config/Backend/Baseurl.php @@ -18,42 +18,163 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Mage - * @package Mage_Backend * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - - class Mage_Backend_Model_Config_Backend_Baseurl extends Mage_Core_Model_Config_Data { + /** + * Validate a base URL field value + * + * @return Mage_Backend_Model_Config_Backend_Baseurl + * @throws Mage_Core_Exception + */ protected function _beforeSave() { $value = $this->getValue(); - - if (!preg_match('#^{{((un)?secure_)?(base|public)_url}}#', $value)) { - $parsedUrl = parse_url($value); - if (!isset($parsedUrl['scheme']) || !isset($parsedUrl['host'])) { - $fieldConfig = $this->getFieldConfig(); - $exceptionMsg = Mage::helper('Mage_Core_Helper_Data') - ->__('The %s you entered is invalid. Please make sure that it follows "http://domain.com/" format.', - $fieldConfig['label'] - ); - Mage::throwException($exceptionMsg); + try { + if (!$this->_validateUnsecure($value) && !$this->_validateSecure($value)) { + $this->_validateFullyQualifiedUrl($value); } + } catch (Mage_Core_Exception $e) { + $field = $this->getFieldConfig(); + $label = ($field && is_array($field) ? $field['label'] : 'value'); + $msg = Mage::helper('Mage_Backend_Helper_Data')->__('Invalid %s. %s', $label, $e->getMessage()); + $error = new Mage_Core_Exception($msg, 0, $e); + throw $error; + } + } + + /** + * Validation sub-routine for unsecure base URLs + * + * @param string $value + * @return bool + */ + private function _validateUnsecure($value) + { + $placeholders = array('{{unsecure_base_url}}'); + switch ($this->getPath()) { + case Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL: + $this->_assertValuesOrUrl(array('{{base_url}}'), $value); + break; + case Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LINK_URL: + $this->_assertStartsWithValuesOrUrl($placeholders, $value); + break; + case Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_MEDIA_URL: + case Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LIB_URL: + $this->_assertStartsWithValuesOrUrlOrEmpty($placeholders, $value); + break; + default: + return false; + } + return true; + } + + /** + * Validation sub-routine for secure base URLs + * + * @param string $value + * @return bool + */ + private function _validateSecure($value) + { + $placeholders = array('{{unsecure_base_url}}', '{{secure_base_url}}'); + switch ($this->getPath()) { + case Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL: + $this->_assertValuesOrUrl(array('{{base_url}}', '{{unsecure_base_url}}'), $value); + break; + case Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL: + $this->_assertStartsWithValuesOrUrl($placeholders, $value); + break; + case Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL: + case Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL: + $this->_assertStartsWithValuesOrUrlOrEmpty($placeholders, $value); + break; + default: + return false; + } + return true; + } + + /** + * Value equals to one of provided items or is a URL + * + * @param array $values + * @param string $value + * @throws Mage_Core_Exception + */ + private function _assertValuesOrUrl(array $values, $value) + { + if (!in_array($value, $values) && !$this->_isFullyQualifiedUrl($value)) { + throw new Mage_Core_Exception(Mage::helper('Mage_Backend_Helper_Data') + ->__('Value must be a URL or one of placeholders: %s', implode(',', $values))); } + } - $value = rtrim($value, '/'); - /** - * If value is special ({{}}) we don't need add slash - */ - if (!preg_match('#}}$#', $value)) { - $value.= '/'; + /** + * Value starts with one of provided items or is a URL + * + * @param array $values + * @param string $value + * @throws Mage_Core_Exception + */ + private function _assertStartsWithValuesOrUrl(array $values, $value) + { + $quoted = array_map('preg_quote', $values, array_fill(0, count($values), '/')); + if (!preg_match('/^(' . implode('|', $quoted) . ')(.+\/)?$/', $value) && !$this->_isFullyQualifiedUrl($value)) { + throw new Mage_Core_Exception(Mage::helper('Mage_Backend_Helper_Data') + ->__('Specify a URL or path that starts with placeholder(s): %s.', implode(', ', $values))); + } + } + + /** + * Value starts with, empty or is a URL + * + * @param array $values + * @param string $value + * @throws Mage_Core_Exception + */ + private function _assertStartsWithValuesOrUrlOrEmpty(array $values, $value) + { + if (empty($value)) { + return; } + try { + $this->_assertStartsWithValuesOrUrl($values, $value); + } catch (Mage_Core_Exception $e) { + $msg = Mage::helper('Mage_Backend_Helper_Data') + ->__('%s An empty value is allowed as well.', $e->getMessage()); + $error = new Mage_Core_Exception($msg, 0, $e); + throw $error; + } + } + /** + * Default validation of a URL + * + * @param string $value + * @throws Mage_Core_Exception + */ + private function _validateFullyQualifiedUrl($value) + { + if (!$this->_isFullyQualifiedUrl($value)) { + throw new Mage_Core_Exception( + Mage::helper('Mage_Backend_Helper_Data')->__('Specify a fully qualified URL.') + ); + } + } - $this->setValue($value); - return $this; + /** + * Whether the provided value can be considered as a fully qualified URL + * + * @param string $value + * @return bool + */ + private function _isFullyQualifiedUrl($value) + { + $url = parse_url($value); + return isset($url['scheme']) && isset($url['host']) && preg_match('/\/$/', $value); } /** @@ -62,7 +183,16 @@ class Mage_Backend_Model_Config_Backend_Baseurl extends Mage_Core_Model_Config_D protected function _afterSave() { if ($this->isValueChanged()) { - Mage::getModel('Mage_Core_Model_Design_Package')->cleanMergedJsCss(); + switch ($this->getPath()) { + case Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL: + case Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_MEDIA_URL: + case Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LIB_URL: + case Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL: + case Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL: + case Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL: + Mage::getDesign()->cleanMergedJsCss(); + break; + } } } } diff --git a/app/code/core/Mage/Backend/etc/adminhtml/system.xml b/app/code/core/Mage/Backend/etc/adminhtml/system.xml index fade2e4deb1..dec72875b4b 100644 --- a/app/code/core/Mage/Backend/etc/adminhtml/system.xml +++ b/app/code/core/Mage/Backend/etc/adminhtml/system.xml @@ -126,6 +126,7 @@ <label>Design Theme</label> <source_model>Mage_Core_Model_Theme::getLabelsCollectionForSystemConfiguration</source_model> <backend_model>Mage_Core_Model_Design_Backend_Theme</backend_model> + <comment><![CDATA[If no value is specified, the system default will be used. The system default may be modified by third party extensions.]]></comment> </field> <field id="ua_regexp" translate="label comment tooltip" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1"> <label>User-Agent Exceptions</label> @@ -498,45 +499,51 @@ </field> </group> <group id="unsecure" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Unsecure</label> - <field id="base_url" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Base URLs</label> + <comment>Any of the fields allow fully qualified URLs that end with '/' (slash) e.g. http://example.com/magento/</comment> + <field id="base_url" translate="label comment" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Base URL</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> + <comment>Specify URL or {{base_url}} placeholder.</comment> </field> <field id="base_link_url" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Base Link URL</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> + <comment>May start with {{unsecure_base_url}} placeholder.</comment> </field> - <field id="base_public_url" translate="label comment" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Base URL for Public Static Files</label> + <field id="base_lib_url" translate="label comment" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Base URL for Library Files</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> - <comment><strong style="color:red">Warning!</strong> When using CDN, in some cases JavaScript may not run properly if CDN is not in your subdomain</comment> + <comment>May be empty or start with {{unsecure_base_url}} placeholder. <br/> <strong style="color:red">Warning!</strong> When using CDN, in some cases JavaScript may not run properly if CDN is not in your subdomain</comment> </field> <field id="base_media_url" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Base Media URL</label> + <label>Base URL for Media Files</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> + <comment>May be empty or start with {{unsecure_base_url}} placeholder.</comment> </field> </group> <group id="secure" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Secure</label> + <label>Base URLs (Secure)</label> + <comment>Any of the fields allow fully qualified URLs that end with '/' (slash) e.g. http://example.com/magento/</comment> <field id="base_url" translate="label comment" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Base URL</label> + <label>Secure Base URL</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> - <comment>Make sure that base URL ends with '/' (slash), e.g. http://yourdomain/magento/</comment> + <comment>Specify URL or {{base_url}}, or {{unsecure_base_url}} placeholder.</comment> </field> - <field id="base_link_url" translate="label comment" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Base Link URL</label> + <field id="base_link_url" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Secure Base Link URL</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> - <comment>Make sure that base URL ends with '/' (slash), e.g. http://yourdomain/magento/</comment> + <comment>May start with {{secure_base_url}} or {{unsecure_base_url}} placeholder.</comment> </field> - <field id="base_public_url" translate="label comment" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Base URL for Public Static Files</label> + <field id="base_lib_url" translate="label comment" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Secure Base URL for Library Files</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> - <comment><strong style="color:red">Warning!</strong> When using CDN, in some cases JavaScript may not run properly if CDN is not in your subdomain</comment> + <comment>May be empty or start with {{secure_base_url}}, or {{unsecure_base_url}} placeholder.</comment> </field> <field id="base_media_url" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1"> - <label>Base Media URL</label> + <label>Secure Base URL for Media Files</label> <backend_model>Mage_Backend_Model_Config_Backend_Baseurl</backend_model> + <comment>May be empty or start with {{secure_base_url}}, or {{unsecure_base_url}} placeholder.</comment> </field> <field id="use_in_frontend" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Use Secure URLs in Frontend</label> diff --git a/app/code/core/Mage/Backend/view/adminhtml/widget/grid.phtml b/app/code/core/Mage/Backend/view/adminhtml/widget/grid.phtml index f102cb97032..dbff31c365f 100644 --- a/app/code/core/Mage/Backend/view/adminhtml/widget/grid.phtml +++ b/app/code/core/Mage/Backend/view/adminhtml/widget/grid.phtml @@ -134,6 +134,10 @@ $numColumns = sizeof($this->getColumns()); <?php if ($this->getCheckboxCheckCallback()): ?> <?php echo $this->getJsObjectName() ?>.checkboxCheckCallback = <?php echo $this->getCheckboxCheckCallback() ?>; <?php endif; ?> + <?php if ($this->getSortableUpdateCallback()): ?> + <?php echo $this->getJsObjectName() ?>.sortableUpdateCallback = <?php echo $this->getSortableUpdateCallback()?>; + <?php endif; ?> + <?php echo $this->getJsObjectName() ?>.bindSortable(); <?php if ($this->getRowInitCallback()): ?> <?php echo $this->getJsObjectName() ?>.initRowCallback = <?php echo $this->getRowInitCallback() ?>; <?php echo $this->getJsObjectName() ?>.initGridRows(); diff --git a/app/code/core/Mage/Backend/view/adminhtml/widget/grid/serializer.phtml b/app/code/core/Mage/Backend/view/adminhtml/widget/grid/serializer.phtml index db1ff39699d..9260fc85e3d 100644 --- a/app/code/core/Mage/Backend/view/adminhtml/widget/grid/serializer.phtml +++ b/app/code/core/Mage/Backend/view/adminhtml/widget/grid/serializer.phtml @@ -26,7 +26,7 @@ ?> <?php /** - * @var Mage_Backend_Block_Widget_Grid_Serializer + * @var $this Mage_Backend_Block_Widget_Grid_Serializer */ ?> <?php $_id = 'id_' . md5(microtime()) ?> diff --git a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php index b8e4b8540ba..dc44094df0c 100644 --- a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php +++ b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php @@ -85,8 +85,8 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Attributes_Extend $('" . $this->getAttribute()->getAttributeCode() . "').removeClassName('required-entry'); } - if ($('dynamic-price-warrning')) { - $('dynamic-price-warrning').show(); + if ($('dynamic-price-warning')) { + $('dynamic-price-warning').show(); } } else { if ($('" . $this->getAttribute()->getAttributeCode() . "')) {"; @@ -105,8 +105,8 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Attributes_Extend $html .= "} - if ($('dynamic-price-warrning')) { - $('dynamic-price-warrning').hide(); + if ($('dynamic-price-warning')) { + $('dynamic-price-warning').hide(); } } }"; diff --git a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle.php b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle.php index 3cfa4a58f23..21bc64d7c13 100644 --- a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle.php +++ b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle.php @@ -63,7 +63,7 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle extends Mage_A protected function _prepareLayout() { $this->addChild('add_button', 'Mage_Adminhtml_Block_Widget_Button', array( - 'label' => Mage::helper('Mage_Bundle_Helper_Data')->__('Add New Option'), + 'label' => Mage::helper('Mage_Bundle_Helper_Data')->__('Create New Option'), 'class' => 'add', 'id' => 'add_new_option', 'on_click' => 'bOption.add()' diff --git a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option.php b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option.php index a618e8245bc..7cb28967d4e 100644 --- a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option.php +++ b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option.php @@ -125,10 +125,9 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option extends protected function _prepareLayout() { $this->addChild('add_selection_button', 'Mage_Adminhtml_Block_Widget_Button', array( - 'id' => $this->getFieldId().'_{{index}}_add_button', - 'label' => Mage::helper('Mage_Bundle_Helper_Data')->__('Add Selection'), - 'on_click' => 'bSelection.showSearch(event)', - 'class' => 'add' + 'id' => $this->getFieldId() . '_{{index}}_add_button', + 'label' => Mage::helper('Mage_Bundle_Helper_Data')->__('Add Products to Option'), + 'class' => 'add add-selection' )); $this->addChild('close_search_button', 'Mage_Adminhtml_Block_Widget_Button', array( @@ -144,7 +143,10 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option extends 'on_click' => 'bOption.remove(event)' )); - $this->addChild('selection_template', 'Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selection'); + $this->addChild( + 'selection_template', + 'Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selection' + ); return parent::_prepareLayout(); } @@ -217,7 +219,7 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option extends public function getTypeSelectHtml() { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setData(array( 'id' => $this->getFieldId().'_{{index}}_type', 'class' => 'select select-product-option-type required-option-select', @@ -231,7 +233,7 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option extends public function getRequireSelectHtml() { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setData(array( 'id' => $this->getFieldId().'_{{index}}_required', 'class' => 'select' @@ -244,6 +246,6 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option extends public function isDefaultStore() { - return ($this->getProduct()->getStoreId() == '0'); + return $this->getProduct()->getStoreId() == '0'; } } diff --git a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search.php b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search.php index 8936a2f809c..e8dbf667f01 100644 --- a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search.php +++ b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search.php @@ -34,52 +34,42 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search extends Mage_Adminhtml_Block_Widget { - + /** + * @var string + */ protected $_template = 'product/edit/bundle/option/search.phtml'; protected function _construct() { $this->setId('bundle_option_selection_search'); - - } - - public function getHeaderText() - { - return Mage::helper('Mage_Bundle_Helper_Data')->__('Please Select Products to Add'); } + /** + * Create search grid + * + * @return Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search + */ protected function _prepareLayout() { $this->setChild( 'grid', $this->getLayout()->createBlock( 'Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_Grid', - 'adminhtml.catalog.product.edit.tab.bundle.option.search.grid') + 'adminhtml.catalog.product.edit.tab.bundle.option.search.grid' + ) ); return parent::_prepareLayout(); } + /** + * Prepare search grid + * + * @return Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search + */ protected function _beforeToHtml() { $this->getChildBlock('grid')->setIndex($this->getIndex()) ->setFirstShow($this->getFirstShow()); - return parent::_beforeToHtml(); } - - public function getButtonsHtml() - { - $addButtonData = array( - 'id' => 'add_button_' . $this->getIndex(), - 'label' => Mage::helper('Mage_Sales_Helper_Data')->__('Add Selected Product(s) to Option'), - 'onclick' => 'bSelection.productGridAddSelected(event)', - 'class' => 'add', - ); - return $this->getLayout()->createBlock('Mage_Adminhtml_Block_Widget_Button')->setData($addButtonData)->toHtml(); - } - - public function getHeaderCssClass() - { - return 'head-catalog-product'; - } } diff --git a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/Grid.php b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/Grid.php index b3e679acf48..fb88eb4faf6 100644 --- a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/Grid.php +++ b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/Grid.php @@ -31,9 +31,9 @@ * @package Mage_Bundle * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_Grid extends Mage_Adminhtml_Block_Widget_Grid +class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_Grid + extends Mage_Adminhtml_Block_Widget_Grid { - protected function _construct() { parent::_construct(); @@ -45,18 +45,31 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_ $this->setUseAjax(true); } - protected function _beforeToHtml() + /** + * Prepare grid filter buttons + */ + protected function _prepareFilterButtons() { - $this->setId($this->getId().'_'.$this->getIndex()); - $this->getChildBlock('reset_filter_button')->setData('onclick', $this->getJsObjectName().'.resetFilter()'); - $this->getChildBlock('search_button')->setData('onclick', $this->getJsObjectName().'.doFilter()'); + $this->getChildBlock('reset_filter_button')->setData( + 'onclick', + $this->getJsObjectName() . '.resetFilter(bSelection.gridUpdateCallback)' + ); + $this->getChildBlock('search_button')->setData( + 'onclick', + $this->getJsObjectName() . '.doFilter(bSelection.gridUpdateCallback)' + ); + } + protected function _beforeToHtml() + { + $this->setId($this->getId() . '_' . $this->getIndex()); return parent::_beforeToHtml(); } protected function _prepareCollection() { $collection = Mage::getModel('Mage_Catalog_Model_Product')->getCollection() + ->setOrder('id') ->setStore($this->getStore()) ->addAttributeToSelect('name') ->addAttributeToSelect('sku') @@ -66,10 +79,6 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_ ->addFilterByRequiredOptions() ->addStoreFilter(); - if ($products = $this->_getProducts()) { - $collection->addIdFilter($this->_getProducts(), true); - } - if ($this->getFirstShow()) { $collection->addIdFilter('-1'); $this->setEmptyText($this->__('Please enter search conditions to view products.')); @@ -82,32 +91,19 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_ protected function _prepareColumns() { - $this->addColumn('id', array( - 'header' => Mage::helper('Mage_Sales_Helper_Data')->__('ID'), - 'sortable' => true, - 'width' => '60px', - 'index' => 'entity_id' + $this->addColumn('is_selected', array( + 'header_css_class' => 'a-center', + 'type' => 'checkbox', + 'name' => 'in_selected', + 'align' => 'center', + 'values' => $this->_getSelectedProducts(), + 'index' => 'entity_id', )); $this->addColumn('name', array( 'header' => Mage::helper('Mage_Sales_Helper_Data')->__('Product Name'), 'index' => 'name', 'column_css_class'=> 'name' )); - - $sets = Mage::getResourceModel('Mage_Eav_Model_Resource_Entity_Attribute_Set_Collection') - ->setEntityTypeFilter(Mage::getModel('Mage_Catalog_Model_Product')->getResource()->getTypeId()) - ->load() - ->toOptionHash(); - - $this->addColumn('set_name', - array( - 'header'=> Mage::helper('Mage_Catalog_Helper_Data')->__('Attrib. Set Name'), - 'width' => '100px', - 'index' => 'attribute_set_id', - 'type' => 'options', - 'options' => $sets, - )); - $this->addColumn('sku', array( 'header' => Mage::helper('Mage_Sales_Helper_Data')->__('SKU'), 'width' => '80px', @@ -122,29 +118,6 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_ 'rate' => $this->getStore()->getBaseCurrency()->getRate($this->getStore()->getCurrentCurrencyCode()), 'index' => 'price' )); - - $this->addColumn('is_selected', array( - 'header_css_class' => 'a-center', - 'type' => 'checkbox', - 'name' => 'in_selected', - 'align' => 'center', - 'values' => $this->_getSelectedProducts(), - 'index' => 'entity_id', - )); - - $this->addColumn('qty', array( - 'filter' => false, - 'sortable' => false, - 'header' => Mage::helper('Mage_Sales_Helper_Data')->__('Qty to Add'), - 'name' => 'qty', - 'inline_css'=> 'qty', - 'align' => 'right', - 'type' => 'input', - 'validate_class' => 'validate-number', - 'index' => 'qty', - 'width' => '130px', - )); - return parent::_prepareColumns(); } @@ -155,7 +128,10 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search_ protected function _getSelectedProducts() { - $products = $this->getRequest()->getPost('selected_products', array()); + $products = $this->getRequest()->getPost( + 'selected_products', + explode(',', $this->getRequest()->getParam('productss')) + ); return $products; } diff --git a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Selection.php b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Selection.php index 482e8817b96..1aaacc3843d 100644 --- a/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Selection.php +++ b/app/code/core/Mage/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Selection.php @@ -97,7 +97,7 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selecti */ public function getPriceTypeSelectHtml() { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setData(array( 'id' => $this->getFieldId() . '_{{index}}_price_type', 'class' => 'select select-product-option-type required-option-select' @@ -117,7 +117,7 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selecti */ public function getQtyTypeSelectHtml() { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setData(array( 'id' => $this->getFieldId().'_{{index}}_can_change_qty', 'class' => 'select' @@ -135,7 +135,7 @@ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selecti */ public function getSelectionSearchUrl() { - return $this->getUrl('*/bundle_selection/search'); + return $this->getUrl('*/bundle_selection/grid'); } /** diff --git a/app/code/core/Mage/Bundle/view/adminhtml/css/bundle-product.css b/app/code/core/Mage/Bundle/view/adminhtml/css/bundle-product.css new file mode 100644 index 00000000000..0ca525c5a28 --- /dev/null +++ b/app/code/core/Mage/Bundle/view/adminhtml/css/bundle-product.css @@ -0,0 +1,84 @@ +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Bundle + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ + +#bundle_product_container { + padding-bottom: 15px; +} + +#bundle_product_container .entry-edit > fieldset { + margin-bottom: 0; +} + +#bundle_product_container .ui-icon-grip-dotted-vertical { + float: left; +} + +#bundle_product_container .ui-icon-circle-triangle-s, +#bundle_product_container .ui-icon-circle-close { + cursor: pointer; + float: right; + margin-left: 4px; +} + +#bundle_product_container .option-box { + padding: 0; +} + +#bundle_product_container .option-box .entry-edit-head .input-text { + width: 300px; +} + +#bundle_product_container .option-box .option-header .select-product-option-type { + width: 120px; +} + +#bundle_product_container .option-box .entry-edit-head .is-required { + margin-left: 4px; +} + +#bundle_product_container .qty-box { + text-align: center; +} + +#bundle_product_container .option-header .opt-input-type { + width: 130px; +} + +#bundle_product_container .selection .product-sku { + width: 250px; +} + +#add_new_option { + font-size: 18px; +} + +#bundle_product_container .no-products-message { + border: #dadfe0 1px solid; + background: #fff; + margin: 10px 30px 0; + padding: 20px 40px; + text-align: center; + vertical-align: middle; +} diff --git a/app/code/core/Mage/Bundle/view/adminhtml/js/bundle-product.js b/app/code/core/Mage/Bundle/view/adminhtml/js/bundle-product.js new file mode 100644 index 00000000000..c3decb6dbf3 --- /dev/null +++ b/app/code/core/Mage/Bundle/view/adminhtml/js/bundle-product.js @@ -0,0 +1,206 @@ +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Bundle + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +/*jshint browser:true jquery:true*/ +/*global FORM_KEY*/ +/*global bSelection*/ +(function($) { + $.widget('mage.bundleProduct', { + _create: function () { + this._initOptionBoxes(); + this._initSortableSelections(); + this._bindCheckboxHandlers(); + this._bindAddSelectionDialog(); + this._hideProductTypeSwitcher(); + this._bindPanelVisibilityToggler(); + }, + _initOptionBoxes: function () { + this.element.sortable({ + axis: 'y', + handle: '.entry-edit-head > .ui-icon-grip-dotted-vertical', + items: '.option-box', + update: this._updateOptionBoxPositions, + tolerance: 'pointer' + }); + + var syncOptionTitle = function (event) { + $(event.target).closest('.option-box').find('.head-edit-form').text($(event.target).val()); + }; + this._on({ + 'click .remove': function (event) { + $(event.target).closest('.option-box').find('.delete-product-option').trigger('click'); + }, + 'click .toggle': function (event) { + $(event.target).closest('.option-box').find('.option-header,.form-list,.selection-search').toggle(); + }, + 'change .option-box input[name$="[title]"]': syncOptionTitle, + 'keyup .option-box input[name$="[title]"]': syncOptionTitle + }); + }, + _initSortableSelections: function () { + this.element.find('.option-box .form-list tbody').sortable({ + axis: 'y', + handle: '.ui-icon-grip-dotted-vertical', + helper: function(event, ui) { + ui.children().each(function() { + $(this).width($(this).width()); + }); + return ui; + }, + update: this._updateSelectionsPositions, + tolerance: 'pointer' + }); + this.element.find('.option-box').each(function () { + $(this).find('.add-selection').appendTo($(this)); + }); + }, + _bindAddSelectionDialog: function () { + var widget = this; + this._on({'click .add-selection': function (event) { + var $optionBox = $(event.target).closest('.option-box'), + $selectionGrid = $optionBox.find('.selection-search'), + optionIndex = $optionBox.attr('id').replace('bundle_option_', ''), + productIds = [], + productSkus = []; + + $optionBox.find('[name$="[product_id]"]').each(function () { + if (!$(this).closest('tr').find('[name$="[delete]"]').val()) { + productIds.push($(this).val()); + productSkus.push($(this).closest('tr').find('.product-sku').text()); + } + }); + + bSelection.gridSelection.set(optionIndex, $H({})); + bSelection.gridRemoval = $H({}); + bSelection.gridSelectedProductSkus = productSkus; + $selectionGrid.dialog({ + title: $optionBox.find('input[name$="[title]"]').val() === '' ? + 'Add Products to New Option' : + 'Add Products to Option "' + $optionBox.find('input[name$="[title]"]').val() + '"', + autoOpen: false, + minWidth: 980, + modal: true, + resizable: true, + buttons: [{ + text: 'Cancel', + click: function() { + $selectionGrid.dialog('close'); + } + }, { + text: 'Apply Changes', + 'class': 'add', + click: function() { + bSelection.gridSelection.get(optionIndex).each( + function(pair) { + bSelection.addRow(optionIndex, { + name: pair.value.get('name'), + selection_price_value: 0, + selection_qty: 1, + sku: pair.value.get('sku'), + product_id: pair.key, + option_id: $('bundle_selection_id_' + optionIndex).val() + }); + } + ); + bSelection.gridRemoval.each( + function(pair) { + $optionBox.find('.product-sku').filter(function () { + return $.trim($(this).text()) == pair.key; // find row by SKU + }).closest('tr').find('button.delete').trigger('click'); + } + ); + widget.refreshSortableElements(); + widget._updateSelectionsPositions.apply(widget.element); + $selectionGrid.dialog('close'); + } + }], + close: function() { + $(this).dialog('destroy'); + } + }); + + $.ajax({ + url: bSelection.selectionSearchUrl, + dataType: 'html', + data: { + index: optionIndex, + products: productIds, + selected_products: productIds, + form_key: FORM_KEY + }, + success: function(data) { + $selectionGrid.html(data).dialog('open'); + }, + context: $('body'), + showLoader: true + }); + }}); + }, + _hideProductTypeSwitcher: function () { + $('#weight_and_type_switcher, label[for=weight_and_type_switcher]').hide(); + }, + _bindPanelVisibilityToggler: function () { + var element = this.element; + this._on('#product_info_tabs', { + tabsbeforeactivate: function (event, ui) { + element[$(ui.newPanel).find('#attribute-name-container').length ? 'show' : 'hide'](); + } + }); + }, + _bindCheckboxHandlers: function () { + this._on({ + 'change .is-required': function (event) { + var $this = $(event.target); + $this.closest('.option-box').find('[name$="[required]"]').val($this.is(':checked') ? 1 : 0); + }, + 'change .is-user-defined-qty': function (event) { + var $this = $(event.target); + $this.closest('.qty-box').find('.select').val($this.is(':checked') ? 1 : 0); + } + }); + this.element.find('.is-required').each(function () { + $(this).prop('checked', $(this).closest('.option-box').find('[name$="[required]"]').val() > 0); + }); + this.element.find('.is-user-defined-qty').each(function () { + $(this).prop('checked', $(this).closest('.qty-box').find('.select').val() > 0); + }); + }, + _updateOptionBoxPositions: function () { + $(this).find('[name^=bundle_options][name$="[position]"]').each(function (index) { + $(this).val(index); + }); + }, + _updateSelectionsPositions: function () { + $(this).find('[name^=bundle_selections][name$="[position]"]').each(function (index) { + $(this).val(index); + }); + }, + refreshSortableElements: function () { + this.element.sortable('refresh'); + this._updateOptionBoxPositions.apply(this.element); + this._initSortableSelections(); + return this; + } + }); +})(jQuery); diff --git a/app/code/core/Mage/Bundle/view/adminhtml/layout.xml b/app/code/core/Mage/Bundle/view/adminhtml/layout.xml index b2584771ca6..6b42eaef507 100644 --- a/app/code/core/Mage/Bundle/view/adminhtml/layout.xml +++ b/app/code/core/Mage/Bundle/view/adminhtml/layout.xml @@ -29,7 +29,7 @@ <layout> <!-- -Layout handle for budle products +Layout handle for bundle products --> <!--<default> @@ -39,9 +39,11 @@ Layout handle for budle products </default>--> <adminhtml_catalog_product_bundle> - <reference name="product_tabs"> - <action method="addTab"><name>bundle_items</name><block>Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle</block></action> - <action method="bindShadowTabs"><first>bundle_items</first><second>customer_options</second></action> + <reference name="head"> + <action method="addCss"><file>Mage_Bundle::css/bundle-product.css</file></action> + </reference> + <reference name="product-type-tabs"> + <block type="Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle" name="bundle_items" /> </reference> </adminhtml_catalog_product_bundle> diff --git a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle.phtml b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle.phtml index d5653c16673..7b02d320e23 100644 --- a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle.phtml +++ b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle.phtml @@ -23,6 +23,8 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ + +/** @var $this Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle */ ?> <script type="text/javascript"> if(typeof Bundle=='undefined') { @@ -30,34 +32,28 @@ if(typeof Bundle=='undefined') { } </script> -<div class="entry-edit"> +<div class="entry-edit" id="bundle_product_container"> <div class="entry-edit-head"> - <h4 class="icon-head head-edit-form fieldset-legend"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Shipment') ?></h4> + <h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->getTabLabel() ?></h4> </div> <fieldset> <table cellspacing="0" class="form-list"> - <tr> - <td class="label"><label for="shipment_type"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Ship Bundle Items') ?></label></td> - <td class="value"><select <?php if ($this->isReadonly()): ?>disabled="disabled" <?php endif;?>id="shipment_type" name="<?php echo $this->getFieldSuffix() ?>[shipment_type]" class="select"> - <option value="1"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Separately') ?></option> - <option value="0"<?php if ($this->getProduct()->getShipmentType() == 0): ?> selected="selected"<?php endif; ?>><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Together') ?></option> - </select> - </td> - </tr> + <tr> + <td class="label"><label for="shipment_type"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Ship Bundle Items') ?></label></td> + <td class="value"><select <?php if ($this->isReadonly()): ?>disabled="disabled" <?php endif;?>id="shipment_type" name="<?php echo $this->getFieldSuffix() ?>[shipment_type]" class="select"> + <option value="1"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Separately') ?></option> + <option value="0"<?php if ($this->getProduct()->getShipmentType() == 0): ?> selected="selected"<?php endif; ?>><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Together') ?></option> + </select> + </td> + </tr> </table> - </fieldset> -</div> -<div class="entry-edit custom-options bundle" id="product_bundle_container"> - <div class="entry-edit-head"> - <h4><?php echo $this->__('Bundle Items') ?></h4> - <div class="right"><?php echo $this->getAddButtonHtml() ?></div> - </div> + <div class="entry-edit custom-options bundle" id="product_bundle_container"> + <?php echo $this->getOptionsBoxHtml() ?> + </div> - <div id="product_options_container" class="box"> - <div id="product_bundle_container_top"></div> - <?php echo $this->getOptionsBoxHtml() ?> - </div> + <div class="a-center"><?php echo $this->getAddButtonHtml() ?></div> + </fieldset> </div> <script type="text/javascript"> @@ -80,6 +76,12 @@ Validation.add('validate-greater-zero-based-on-option', '<?php echo $this->__('P } return true; }); + +jQuery(function($) { + head.js("<?php echo $this->getViewFileUrl('Mage_Bundle::js/bundle-product.js') ?>", function () { + $('#bundle_product_container').mage('bundleProduct'); + }); +}); </script> <div><input type="hidden" name="affect_bundle_product_selections" value="1" /></div> diff --git a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option.phtml b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option.phtml index 9554a172974..7295ff398a5 100644 --- a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option.phtml +++ b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option.phtml @@ -23,53 +23,100 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ + +/** @var $this Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option */ +$columnCount = 5; ?> -<script type="text/javascript"> -optionTemplate = '<div id="<?php echo $this->getFieldId() ?>_{{index}}" class="option-box"> ' + -'<div class="option-title"> ' + - '<label for="<?php echo $this->getFieldName() ?>[{{index}}][title]"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Default Title') ?> <span class="required">*</span></label>' + - <?php if ($this->isDefaultStore()): ?> - '<input class="input-text required-entry" type="text" name="<?php echo $this->getFieldName() ?>[{{index}}][title]" id="id_<?php echo $this->getFieldName() ?>_{{index}}_title" value="{{title}}">' + - <?php else: ?> - '<input class="input-text required-entry" type="text" name="<?php echo $this->getFieldName() ?>[{{index}}][default_title]" id="id_<?php echo $this->getFieldName() ?>_{{index}}_default_title" value="{{default_title}}">' + - <?php endif; ?> -<?php echo Mage::helper('Mage_Core_Helper_Data')->jsonEncode($this->getOptionDeleteButtonHtml()) ?> + -'</div>' + - '<table class="option-header" cellpadding="0" cellspacing="0">' + - '<thead>' + - '<tr>' + - <?php if (!$this->isDefaultStore()): ?> - '<th class="opt-title"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Store View Title') ?> <span class="required">*</span></th>' + - <?php endif; ?> - '<th class="opt-type"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Input Type') ?></th>' + - '<th class="opt-req"><?php echo $this->jsQuoteEscape(Mage::helper('Mage_Bundle_Helper_Data')->__('Is Required')) ?></th>' + - '<th class="opt-order"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Position') ?></th>' + - '<th> </th>' + - '</tr>' + - '</thead>' + - '<tbody>' + - '<tr>' + - '<input type="hidden" id="<?php echo $this->getFieldId() ?>_id_{{index}}" name="<?php echo $this->getFieldName() ?>[{{index}}][option_id]" value="{{option_id}}">' + - '<input type="hidden" name="<?php echo $this->getFieldName() ?>[{{index}}][delete]" value="" class="delete">' + - <?php if (!$this->isDefaultStore()): ?> - '<td><input class="input-text required-entry" type="text" name="<?php echo $this->getFieldName() ?>[{{index}}][title]" id="id_<?php echo $this->getFieldName() ?>_{{index}}_title_store" value="{{title}}"></td>' + +<script id="bundle-option-template" type="text/x-jquery-tmpl"> + <div id="<?php echo $this->getFieldId() ?>_{{index}}" class="option-box"> + <div class="option-title" style="display:none"> + <?php echo $this->getOptionDeleteButtonHtml() ?> + </div> + <div class="entry-edit-head"> + <span class="ui-icon ui-icon-grip-dotted-vertical"></span> + <h4 class="icon-head head-edit-form fieldset-legend">{{title}}</h4> + <span class="ui-icon ui-icon-circle-triangle-s toggle"></span> + <span class="ui-icon ui-icon-circle-close remove"></span> + </div> + <table class="option-header" cellpadding="0" cellspacing="0"> + <thead> + <tr> + <th class="opt-title"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Default Title') ?> + <span class="required">*</span> + </th> + <?php if (!$this->isDefaultStore()): $columnCount++; ?> + <th class="opt-title"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Store View Title') ?> + <span class="required">*</span> + </th> + <?php endif; ?> + <th class="opt-input-type"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Input Type') ?></th> + <th class="opt-req"> </th> + <th class="opt-order" style="display:none"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Position') ?></th> + <th> </th> + </tr> + </thead> + <tbody> + <tr> + <td> + <?php if ($this->isDefaultStore()): ?> + <input class="input-text required-entry" type="text" + name="<?php echo $this->getFieldName() ?>[{{index}}][title]" + id="id_<?php echo $this->getFieldName() ?>_{{index}}_title" value="{{title}}" /> + <?php else: ?> + <input class="input-text required-entry" type="text" + name="<?php echo $this->getFieldName() ?>[{{index}}][default_title]" + id="id_<?php echo $this->getFieldName() ?>_{{index}}_default_title" value="{{default_title}}" /> <?php endif; ?> - '<td><?php echo $this->getTypeSelectHtml() ?></td>' + - '<td><?php echo $this->getRequireSelectHtml() ?></td>' + - '<td><input class="input-text validate-zero-or-greater" type="text" name="<?php echo $this->getFieldName() ?>[{{index}}][position]" value="{{position}}"></td>' + - '<td> ' + <?php echo Mage::helper('Mage_Core_Helper_Data')->jsonEncode($this->getAddSelectionButtonHtml()) ?> + '</td>' + - '</tr>' + - '</tbody>' + - '</table>' + - '<div id="<?php echo $this->getFieldId() ?>_search_{{index}}">' + - '</div>' + -'</div>'; + <input type="hidden" id="<?php echo $this->getFieldId() ?>_id_{{index}}" + name="<?php echo $this->getFieldName() ?>[{{index}}][option_id]" value="{{option_id}}" /> + <input type="hidden" name="<?php echo $this->getFieldName() ?>[{{index}}][delete]" + value="" class="delete" /> + </td> + <?php if (!$this->isDefaultStore()): ?> + <td> + <input class="input-text required-entry" type="text" + name="<?php echo $this->getFieldName() ?>[{{index}}][title]" + id="id_<?php echo $this->getFieldName() ?>_{{index}}_title_store" value="{{title}}" /> + </td> + <?php endif; ?> + <td class="opt-input-type"><?php echo $this->getTypeSelectHtml() ?></td> + <td class="opt-req"> + <label> + <input type="checkbox" class="is-required" checked="checked" /> + <?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Required')?> + </label> + <span style="display:none"><?php echo $this->getRequireSelectHtml() ?></span> + </td> + <td class="opt-order" style="display:none"> + <input class="input-text validate-zero-or-greater" type="text" + name="<?php echo $this->getFieldName() ?>[{{index}}][position]" value="{{position}}" /> + </td> + <td> </td> + </tr> + <tr> + <td colspan="<?php echo $columnCount; ?>"> + <div class="no-products-message"> + <?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('There are no products in this option.')?> + </div> + </td> + </tr> + </tbody> + <tfoot> + <tr> + <td><?php echo $this->getAddSelectionButtonHtml() ?></td> + </tr> + </tfoot> + </table> + <div id="<?php echo $this->getFieldId() ?>_search_{{index}}" class="selection-search"></div> + </div> +</script> +<script type="text/javascript"> + var optionTemplate = jQuery('#bundle-option-template').html(); </script> <?php echo $this->getSelectionHtml() ?> <script type="text/javascript"> - function changeInputType(oldObject, oType) { var newObject = document.createElement('input'); newObject.type = oType; @@ -86,30 +133,26 @@ function changeInputType(oldObject, oType) { Bundle.Option = Class.create(); Bundle.Option.prototype = { idLabel : '<?php echo $this->getFieldId() ?>', - top : '', templateSyntax : /(^|.|\r|\n)({{(\w+)}})/, templateText : '', itemsCount : 0, initialize : function(template) { this.templateText = template; - this.top = $('product_bundle_container_top'); }, add : function(data) { - if(!data){ + if (!data) { data = {}; - this.top = $('product_bundle_container_top'); } else { - data.title = data.title.replace('"', """); + data.title = data.title.replace(/</g, "<"); + data.title = data.title.replace(/"/g, """); } data.index = this.itemsCount++; this.template = new Template(this.templateText, this.templateSyntax); - Element.insert(this.top, {'after':this.template.evaluate(data)}); - - this.top = $(this.idLabel + '_' + data.index); + jQuery('#product_bundle_container').append(jQuery(this.template.evaluate(data))); //set selected type if (data.type) { @@ -127,6 +170,10 @@ Bundle.Option.prototype = { // rebind change notifications varienWindowOnload(true); + if (jQuery && jQuery('#bundle_product_container').data('bundleProduct')) { + jQuery('#bundle_product_container').bundleProduct('refreshSortableElements'); + } + return data.index; }, @@ -203,33 +250,26 @@ Bundle.Option.prototype = { } ); } -} +}; var optionIndex = 0; bOption = new Bundle.Option(optionTemplate); -//adding data to templates -<?php foreach ($this->getOptions() as $_option): ?> -optionIndex = bOption.add(<?php echo $_option->toJson() ?>); -<?php if ($_option->getSelections()):?> - <?php foreach ($_option->getSelections() as $_selection): ?> - <?php $_selection->setName($this->escapeHtml($_selection->getName())); ?> -bSelection.addRow(optionIndex, <?php echo $_selection->toJson() ?>); - <?php endforeach; ?> -<?php endif; ?> -<?php endforeach; ?> -/** - * Adding event on price type select box of product to hide or show prices for selections - */ -function togglePriceType() { - if ($('price_type').value == '1') { - bOption.priceTypeFixed(); - } else { - bOption.priceTypeDynamic(); +<?php + foreach ($this->getOptions() as $_option) { + /** @var $_option Mage_Bundle_Model_Option */ + echo 'optionIndex = bOption.add(', $_option->toJson(), ');', PHP_EOL; + if ($_option->getSelections()) { + foreach ($_option->getSelections() as $_selection) { + /** @var $_selection Mage_Catalog_Model_Product */ + $_selection->setName($this->escapeHtml($_selection->getName())); + echo 'bSelection.addRow(optionIndex,', $_selection->toJson(), ');', PHP_EOL; + } + } } +?> +function togglePriceType() { + bOption['priceType' + ($('price_type').value == '1' ? 'Fixed' : 'Dynamic')](); } - togglePriceType(); - Event.observe('price_type', 'change', togglePriceType); - </script> diff --git a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/search.phtml b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/search.phtml index 88ff45f13cd..e3844c3d7bb 100644 --- a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/search.phtml +++ b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/search.phtml @@ -23,13 +23,6 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ -?> -<div class="entry-edit"> - <div class="entry-edit-head"> - <div style="float: right;"><?php echo $this->getButtonsHtml() ?></div> - <h4 class="fieldset-legend <?php echo ($this->getHeaderCssClass()) ? $this->getHeaderCssClass().' icon-head' : '' ?>"><?php echo $this->getHeaderText() ?></h4> - </div> - <fieldset> - <?php echo $this->getChildHtml() ?> - </fieldset> -</div> + +/** @var $this Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search */ +echo $this->getChildHtml(); diff --git a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/selection.phtml b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/selection.phtml index 27e7ce46814..04ad0b43ac1 100644 --- a/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/selection.phtml +++ b/app/code/core/Mage/Bundle/view/adminhtml/product/edit/bundle/option/selection.phtml @@ -23,54 +23,99 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ + +/** @var $this Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selection */ ?> -<script type="text/javascript"> -//<![CDATA[ - -var bundleTemplateBox = '<table class="border" cellpadding="0" cellspacing="0">' + - ' <thead>' + - ' <tr class="headings">' + - ' <th><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Name') ?></th>' + - <?php if ($this->getCanReadPrice() !== false) : ?> - ' <th class="type-price price-type-box"><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Price') ?></th>' + - ' <th class="type-type price-type-box"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Price Type') ?></th>' + +<script id="bundle-option-selection-box-template" type="text/x-jquery-tmpl"> + <table class="border" cellpadding="0" cellspacing="0"> + <thead> + <tr class="headings"> + <th style="width:1px"> </th> + <th style="width:1px"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Default') ?></th> + <th class="product-name"><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Name') ?></th> + <th class="product-sku"><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('SKU') ?></th> + <?php if ($this->getCanReadPrice() !== false): ?> + <th class="type-price price-type-box"><?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Price') ?></th> + <th class="type-type price-type-box"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Price Type') ?></th> + <?php endif; ?> + <th class="type-price"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Default Qty') ?></th> + <th class="type-uqty qty-box"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('User Defined Qty') ?></th> + <th class="type-order" style="display:none"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Position') ?></th> + <th class="last"> </th> + </tr> + </thead> + <tbody> + </tbody> + </table> +</script> +<script id="bundle-option-selection-row-template" type="text/x-jquery-tmpl"> + <td> + <span class="ui-icon ui-icon-grip-dotted-vertical"></span> + <input type="hidden" id="<?php echo $this->getFieldId() ?>_id_{{index}}" + name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][selection_id]" + value="{{selection_id}}"/> + <input type="hidden" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][option_id]" + value="{{option_id}}"/> + <input type="hidden" class="product" + name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][product_id]" + value="{{product_id}}"/> + <input type="hidden" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][delete]" + value="" class="delete"/> + </td> + <td class="a-center"> + <input onclick="bSelection.checkGroup(event)" type="{{option_type}}" class="default" + name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][is_default]" + value="1" {{checked}} /> + </td> + <td class="product-name">{{name}}</td> + <td class="product-sku">{{sku}}</td> +<?php if ($this->getCanReadPrice() !== false): ?> + <td class="price-type-box"> + <input id="<?php echo $this->getFieldId() ?>_{{index}}_price_value" + class="input-text required-entry validate-zero-or-greater" type="text" + name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][selection_price_value]" + value="{{selection_price_value}}" + <?php if($this->getCanEditPrice() === false): ?> + disabled="disabled" + <?php endif; ?>/> + </td> + <td class="price-type-box"> + <?php echo $this->getPriceTypeSelectHtml() ?> + <div><?php echo $this->getCheckboxScopeHtml() ?></div> + </td> +<?php else: ?> + <input type="hidden" id="<?php echo $this->getFieldId(); ?>_{{index}}_price_value" + name="<?php echo $this->getFieldName(); ?>[{{parentIndex}}][{{index}}][selection_price_value]" value="0" /> + <input type="hidden" id="<?php echo $this->getFieldId(); ?>_{{index}}_price_type" + name="<?php echo $this->getFieldName(); ?>[{{parentIndex}}][{{index}}][selection_price_type]" value="0" /> + <?php if ($this->isUsedWebsitePrice()): ?> + <input type="hidden" id="<?php echo $this->getFieldId(); ?>_{{index}}_price_scope" + name="<?php echo $this->getFieldName(); ?>[{{parentIndex}}][{{index}}][default_price_scope]" value="1" /> <?php endif; ?> - ' <th class="type-price"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Default Qty') ?></th>' + - ' <th class="type-uqty qty-box"><?php echo$this->jsQuoteEscape(Mage::helper('Mage_Bundle_Helper_Data')->__('User Defined Qty')) ?></th>' + - ' <th class="type-order"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Position') ?></th>' + - ' <th style="width:1px"><?php echo Mage::helper('Mage_Bundle_Helper_Data')->__('Default') ?></th>' + - ' <th class="last"> </th>' + - ' </tr>' + - ' </thead> ' + - ' <tbody>' + - ' </tbody>' + - '</table>'; - -var bundleTemplateRow ='<td>' + - ' <input type="hidden" id="<?php echo $this->getFieldId() ?>_id_{{index}}" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][selection_id]" value="{{selection_id}}">' + - ' <input type="hidden" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][option_id]" value="{{option_id}}">' + - ' <input type="hidden" class="product" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][product_id]" value="{{product_id}}">' + - ' <input type="hidden" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][delete]" value="" class="delete">' + - ' {{name}}<br />' + - ' <div class="nobr">' + - ' <strong><?php echo $this->helper('Mage_Sales_Helper_Data')->__('SKU') ?>:</strong> {{sku}}' + - ' </div>' + - '</td>' + - <?php if ($this->getCanReadPrice() !== false) : ?> - '<td class="price-type-box"><input id="<?php echo $this->getFieldId() ?>_{{index}}_price_value" class="input-text required-entry validate-zero-or-greater" type="text" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][selection_price_value]" value="{{selection_price_value}}"<?php if($this->getCanEditPrice() === false) : ?> disabled="disabled"<?php endif; ?>></td>' + - '<td class="price-type-box"><?php echo $this->getPriceTypeSelectHtml() ?><div><?php echo $this->getCheckboxScopeHtml() ?></div></td>' + - <?php else : ?> - '<input type="hidden" id="<?php echo $this->getFieldId(); ?>_{{index}}_price_value" name="<?php echo $this->getFieldName(); ?>[{{parentIndex}}][{{index}}][selection_price_value]" value="0" />' + - '<input type="hidden" id="<?php echo $this->getFieldId(); ?>_{{index}}_price_type" name="<?php echo $this->getFieldName(); ?>[{{parentIndex}}][{{index}}][selection_price_type]" value="0" />' + - <?php if ($this->isUsedWebsitePrice()): ?> - '<input type="hidden" id="<?php echo $this->getFieldId(); ?>_{{index}}_price_scope" name="<?php echo $this->getFieldName(); ?>[{{parentIndex}}][{{index}}][default_price_scope]" value="1" />' + - <?php endif; ?> - <?php endif; ?> - '<td><input class="input-text required-entry validate-greater-zero-based-on-option validate-zero-or-greater" type="text" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][selection_qty]" value="{{selection_qty}}"></td>' + - '<td class="qty-box"><?php echo $this->getQtyTypeSelectHtml() ?></td>' + - '<td><input class="input-text required-entry validate-zero-or-greater" type="text" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][position]" value="{{position}}"></td>' + - '<td class="a-center"><input onclick="bSelection.checkGroup(event)" type="{{option_type}}" class="default" name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][is_default]" value="1" {{checked}}></td>' + - '<td class="last"><span title="Delete Row">' + <?php echo Mage::helper('Mage_Core_Helper_Data')->jsonEncode($this->getSelectionDeleteButtonHtml()) ?> + '</span></td>'; +<?php endif; ?> + <td> + <input class="input-text required-entry validate-greater-zero-based-on-option validate-zero-or-greater" type="text" + name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][selection_qty]" + value="{{selection_qty}}" /> + </td> + <td class="qty-box"> + <input type="checkbox" class="is-user-defined-qty" checked="checked" /> + <span style="display:none"><?php echo $this->getQtyTypeSelectHtml() ?></span> + </td> + <td class="type-order" style="display:none"> + <input class="input-text required-entry validate-zero-or-greater" type="text" + name="<?php echo $this->getFieldName() ?>[{{parentIndex}}][{{index}}][position]" + value="{{position}}" /> + </td> + <td class="last"> + <span title="Delete Row"> + <?php echo $this->getSelectionDeleteButtonHtml() ?> + </span> + </td> +</script> +<script type="text/javascript"> +var bundleTemplateBox = jQuery('#bundle-option-selection-box-template').html(), + bundleTemplateRow = jQuery('#bundle-option-selection-row-template').html(); Bundle.Selection = Class.create(); Bundle.Selection.prototype = { @@ -81,7 +126,10 @@ Bundle.Selection.prototype = { templateRow : '', itemsCount : 0, row : null, - gridSelection : new Hash(), + gridSelection: new Hash(), + gridRemoval: new Hash(), + gridSelectedProductSkus: [], + selectionSearchUrl: '<?php echo $this->getSelectionSearchUrl() ?>', initialize : function() { this.templateBox = '<div class="grid tier form-list" id="' + this.idLabel + '_box_{{parentIndex}}">' + bundleTemplateBox + '</div>'; @@ -89,31 +137,27 @@ Bundle.Selection.prototype = { this.templateRow = '<tr class="selection" id="' + this.idLabel + '_row_{{index}}">' + bundleTemplateRow + '</tr>'; }, - showSearch : function(event) { - var element = Event.findElement(event, 'div'); - var parts = element.id.split('_'); - - var products = new Array(); - - var inputs = $A($$('#' + element.id + ' tr.selection input.product')); - for (i=0; i<inputs.length; i++) { - products.push(inputs[i].value); - } - - this.gridSelection.set(parts[2], $H({})); - - new Ajax.Updater(bOption.idLabel + '_search_' + parts[2], '<?php echo $this->getSelectionSearchUrl() ?>', { - method: 'post', - parameters : {'index' : parts[2], 'products[]' : products, 'form_key': FORM_KEY}, - evalScripts : true - }); + gridUpdateCallback: function () { + (function ($) { + var $grid = $('table[id^=bundle_selection_search_grid_]:visible'); + $grid.find('.checkbox').prop({checked: false}); + + var checkRowBySku = function (sku) { + sku = $.trim(sku); + $grid('.sku').filter(function () { + return $.trim($(this).text()) == sku; + }).closest('tr').find('.checkbox').prop({checked: true}); + }; + $.each(bSelection.gridSelection.values().pop().toArray(), function () { + checkRowBySku(this.pop().get('sku')); + }); - if (Event.element(event).tagName.toLowerCase() != 'button') { - var button = Event.element(event).up('button'); - } else { - var button = Event.element(event); - } - button.hide(); + $.each(bSelection.gridSelectedProductSkus, function () { + if (!bSelection.gridRemoval.get(this)) { + checkRowBySku(this); + } + }); + })(jQuery); }, addRow : function (parentIndex, data) { @@ -153,7 +197,9 @@ Bundle.Selection.prototype = { this.template = new Template(this.templateRow, this.templateSyntax); var tbody = $$('#' + this.idLabel + '_box_' + parentIndex + ' tbody'); - Element.insert(tbody[0], {'bottom':this.template.evaluate(data)}); + // replace <script to avoid evalScripts() execution + var escapedHTML = this.template.evaluate(data).replace(/<(\/?)script/g, '<$1script'); + Element.insert(tbody[0], {bottom: escapedHTML}); if (data.selection_price_type) { $A($(this.idLabel + '_'+data.index+'_price_type').options).each(function(option){ @@ -202,6 +248,8 @@ Bundle.Selection.prototype = { } ); } + + jQuery('#bundle_option_' + parentIndex + ' .no-products-message').closest('tr').hide(); }, bindScopeCheckbox : function(){ @@ -231,7 +279,7 @@ Bundle.Selection.prototype = { }, addBox : function (parentIndex) { - var div = $(bOption.idLabel + '_' + parentIndex) + var div = $(bOption.idLabel + '_' + parentIndex); this.template = new Template(this.templateBox, this.templateSyntax); var data = {'parentIndex' : parentIndex}; Element.insert(div, {'bottom':this.template.evaluate(data)}); @@ -247,12 +295,10 @@ Bundle.Selection.prototype = { Element.removeClassName(element, 'selection'); Element.hide(element); - if (container) { - if ($$('#' + container.id + ' tr.selection')) { - if (!$$('#' + container.id + ' tr.selection').length) { - container.hide(); - } - } + var selection = $$('#' + container.id + ' tr.selection'); + if (container && selection && !selection.length) { + container.hide(); + jQuery(element).closest('.option-box').find('.no-products-message').closest('tr').show(); } } }, @@ -273,54 +319,30 @@ Bundle.Selection.prototype = { } }, - productGridAddSelected : function(event) { - var element = Event.findElement(event, 'button'); - var parts = element.id.split('_'); - - $(bOption.idLabel + '_search_' + parts[2]).innerHTML = ''; - $(bOption.idLabel + '_' + parts[2] + '_add_button').show(); - - this.gridSelection.get(parts[2]).each( - function(pair) { - var qty = pair.value.get('qty'); - var data = { - 'name' : pair.value.get('name'), - 'selection_price_value' : 0, - 'selection_qty' : (qty == '' ? 1 : qty), - 'sku' : pair.value.get('sku'), - 'position' : 0, - 'product_id' : pair.key, - 'option_id' : $(bOption.idLabel + '_id_' + parts[2]).value - }; - bSelection.addRow(parts[2], data); - } - ); - }, - productGridRowInit : function(grid, row){ var checkbox = $(row).getElementsByClassName('checkbox')[0]; var inputs = $(row).getElementsByClassName('input-text'); for (var i = 0; i < inputs.length; i++) { inputs[i].checkbox = checkbox; - Event.observe(inputs[i], 'keyup', this.productGridRowInputChange.bind(this)); - Event.observe(inputs[i], 'change', this.productGridRowInputChange.bind(this)); } }, productGridCheckboxCheck : function(grid, element, checked) { var id = element.up('table').id.split('_')[4]; if (element.value > 0) { + var tr = element.parentNode.parentNode, + sku = jQuery.trim(tr.select('td.sku')[0].innerHTML); if (element.checked) { - var tr = element.parentNode.parentNode; if (!this.gridSelection.get(id)) { - this.gridSelection.set(id, new Hash()); + this.gridSelection.set(id, $H({})); } this.gridSelection.get(id).set(element.value, $H({})); this.gridSelection.get(id).get(element.value).set('name', tr.select('td.name')[0].innerHTML); - this.gridSelection.get(id).get(element.value).set('qty', tr.select('input.qty')[0].value); - this.gridSelection.get(id).get(element.value).set('sku', tr.select('td.sku')[0].innerHTML); + this.gridSelection.get(id).get(element.value).set('sku', sku); + this.gridRemoval.unset(sku); } else { this.gridSelection.get(id).unset(element.value); + this.gridRemoval.set(sku, 1); } } }, @@ -335,18 +357,8 @@ Bundle.Selection.prototype = { grid.setCheckboxChecked(checkbox[0], checked); } } - }, - - productGridRowInputChange : function(event) { - var element = Event.element(event); - if (!element.checkbox.checked) { - return; - } - var id = element.up('table').id.split('_')[4]; - this.gridSelection.get(id).get(element.checkbox.value).set('qty', element.value); } -} +}; bSelection = new Bundle.Selection(); -//]]> </script> diff --git a/app/code/core/Mage/Captcha/Helper/Data.php b/app/code/core/Mage/Captcha/Helper/Data.php index be91d72983c..34131609db0 100755 --- a/app/code/core/Mage/Captcha/Helper/Data.php +++ b/app/code/core/Mage/Captcha/Helper/Data.php @@ -64,11 +64,6 @@ class Mage_Captcha_Helper_Data extends Mage_Core_Helper_Abstract */ protected $_captcha = array(); - /** - * @var Mage_Core_Model_Config_Options - */ - protected $_option; - /** * @var Mage_Core_Model_Config */ @@ -79,21 +74,29 @@ class Mage_Captcha_Helper_Data extends Mage_Core_Helper_Abstract */ protected $_filesystem; + /** + * @var Mage_Core_Model_Dir + */ + protected $_dirs = null; + /** * @var Mage_Core_Model_App */ protected $_app; /** + * @param Mage_Core_Model_Dir $dirs * @param Mage_Core_Model_App $app * @param Mage_Core_Model_Config $config * @param Magento_Filesystem $filesystem */ public function __construct( + Mage_Core_Model_Dir $dirs, Mage_Core_Model_App $app, Mage_Core_Model_Config $config, Magento_Filesystem $filesystem ) { + $this->_dirs = $dirs; $this->_app = $app; $this->_config = $config; $this->_filesystem = $filesystem; @@ -133,7 +136,7 @@ class Mage_Captcha_Helper_Data extends Mage_Core_Helper_Abstract { $store = $this->_app->getStore($store); $areaCode = $store->isAdmin() ? 'admin' : 'customer'; - return $store->getConfig($areaCode . '/captcha/' . $id, $store); + return $store->getConfig($areaCode . '/captcha/' . $id); } /** @@ -149,10 +152,11 @@ class Mage_Captcha_Helper_Data extends Mage_Core_Helper_Abstract $node = $this->_config->getNode(Mage_Captcha_Helper_Data::XML_PATH_CAPTCHA_FONTS); $fonts = array(); if ($node) { + $libDir = $this->_dirs->getDir(Mage_Core_Model_Dir::LIB); foreach ($node->children() as $fontName => $fontNode) { $fonts[$fontName] = array( 'label' => (string)$fontNode->label, - 'path' => $this->_config->getOptions()->getDir('base') . DIRECTORY_SEPARATOR . $fontNode->path + 'path' => $libDir . DIRECTORY_SEPARATOR . $fontNode->path ); } } @@ -167,7 +171,7 @@ class Mage_Captcha_Helper_Data extends Mage_Core_Helper_Abstract */ public function getImgDir($website = null) { - $mediaDir = $this->_config->getOptions()->getDir('media'); + $mediaDir = $this->_dirs->getDir(Mage_Core_Model_Dir::MEDIA); $captchaDir = Magento_Filesystem::getPathFromArray(array($mediaDir, 'captcha', $this->_app->getWebsite($website)->getCode())); $this->_filesystem->setWorkingDirectory($mediaDir); @@ -184,7 +188,7 @@ class Mage_Captcha_Helper_Data extends Mage_Core_Helper_Abstract */ public function getImgUrl($website = null) { - return $this->_app->getStore()->getBaseUrl('media') . 'captcha' + return $this->_app->getStore()->getBaseUrl(Mage_Core_Model_Dir::MEDIA) . 'captcha' . '/' . $this->_app->getWebsite($website)->getCode() . '/'; } } diff --git a/app/code/core/Mage/Captcha/Model/Zend.php b/app/code/core/Mage/Captcha/Model/Zend.php index 063e4862e1c..2d177c89737 100755 --- a/app/code/core/Mage/Captcha/Model/Zend.php +++ b/app/code/core/Mage/Captcha/Model/Zend.php @@ -49,10 +49,9 @@ class Mage_Captcha_Model_Zend extends Zend_Captcha_Image implements Mage_Captcha const DEFAULT_WORD_LENGTH_TO = 5; /** - * Helper Instance - * @var Mage_Captcha_Helper_Data + * @var Magento_ObjectManager|null */ - protected $_helper = null; + protected $_objectManager = null; /** * Captcha expire time @@ -87,16 +86,18 @@ class Mage_Captcha_Model_Zend extends Zend_Captcha_Image implements Mage_Captcha /** * Zend captcha constructor * - * @param array $params + * @param Magento_ObjectManager $objectManager + * @param $params + * @throws Exception */ - public function __construct($params) + public function __construct(Magento_ObjectManager $objectManager, $params) { if (!is_array($params) || !isset($params['formId'])) { throw new Exception('formId is mandatory'); } $this->_formId = $params['formId']; - $this->_helper = isset($params['helper']) ? $params['helper'] : null; + $this->_objectManager = $objectManager; $this->_resourceModel = isset($params['resourceModel']) ? $params['resourceModel'] : null; $this->_session = isset($params['session']) ? $params['session'] : null; } @@ -355,10 +356,7 @@ class Mage_Captcha_Model_Zend extends Zend_Captcha_Image implements Mage_Captcha */ protected function _getHelper() { - if (empty($this->_helper)) { - $this->_helper = Mage::helper('Mage_Captcha_Helper_Data'); - } - return $this->_helper; + return $this->_objectManager->get('Mage_Captcha_Helper_Data'); } /** diff --git a/app/code/core/Mage/Captcha/etc/config.xml b/app/code/core/Mage/Captcha/etc/config.xml index 2603c37b5ef..9dfceb9e55e 100755 --- a/app/code/core/Mage/Captcha/etc/config.xml +++ b/app/code/core/Mage/Captcha/etc/config.xml @@ -226,7 +226,7 @@ <fonts> <linlibertine> <label>LinLibertine</label> - <path>lib/LinLibertineFont/LinLibertine_Bd-2.8.1.ttf</path> + <path>LinLibertineFont/LinLibertine_Bd-2.8.1.ttf</path> </linlibertine> </fonts> <frontend> diff --git a/app/code/core/Mage/Catalog/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSet.php b/app/code/core/Mage/Catalog/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSet.php index 07562d12b8d..410a83d0ec8 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSet.php +++ b/app/code/core/Mage/Catalog/Block/Product/Configurable/AssociatedSelector/Backend/Grid/ColumnSet.php @@ -62,6 +62,8 @@ class Mage_Catalog_Block_Product_Configurable_AssociatedSelector_Backend_Grid_Co * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Backend_Model_Widget_Grid_Row_UrlGeneratorFactory $generatorFactory * @param Mage_Core_Model_Registry $registryManager, @@ -84,6 +86,8 @@ class Mage_Catalog_Block_Product_Configurable_AssociatedSelector_Backend_Grid_Co Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Backend_Model_Widget_Grid_Row_UrlGeneratorFactory $generatorFactory, Mage_Core_Model_Registry $registryManager, @@ -93,7 +97,7 @@ class Mage_Catalog_Block_Product_Configurable_AssociatedSelector_Backend_Grid_Co array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $helperFactory->get('Mage_Backend_Helper_Data'), $generatorFactory, $subtotals, $totals, $data); $this->_registryManager = $registryManager; diff --git a/app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts.php b/app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts.php new file mode 100644 index 00000000000..e63a825b3d1 --- /dev/null +++ b/app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts.php @@ -0,0 +1,44 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Catalog_Block_Product_Grouped_AssociatedProducts extends Mage_Backend_Block_Catalog_Product_Tab_Container +{ + protected function _construct() + { + parent::_construct(); + $this->setId('grouped_product_container'); + } + + /** + * Return Tab label + * + * @return string + */ + public function getTabLabel() + { + return Mage::helper('Mage_Catalog_Helper_Data')->__('Grouped Products'); + } +} diff --git a/app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts/Grid.php b/app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts/Grid.php new file mode 100644 index 00000000000..fe6f85d9229 --- /dev/null +++ b/app/code/core/Mage/Catalog/Block/Product/Grouped/AssociatedProducts/Grid.php @@ -0,0 +1,137 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Products in grouped grid + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Block_Product_Grouped_AssociatedProducts_Grid extends Mage_Backend_Block_Widget_Grid +{ + /** + * Input name product data will be serialized into + */ + protected $_hiddenInputName; + + /** + * Names of the inputs to serialize + */ + protected $_fieldsToSave = array(); + + protected function _construct() + { + parent::_construct(); + $this->setId('super_product_grid'); + $this->setDefaultSort('entity_id'); + $this->setSkipGenerateContent(true); + $this->setUseAjax(true); + } + + /** + * Retrieve grouped products + * + * @return array + */ + public function getAssociatedProducts() + { + $associatedProducts = Mage::registry('current_product')->getTypeInstance() + ->getAssociatedProducts(Mage::registry('current_product')); + $products = array(); + foreach ($associatedProducts as $product) { + $products[$product->getId()] = array( + 'qty' => $product->getQty(), + 'position' => $product->getPosition() + ); + } + return $this->helper('Mage_Core_Helper_Data')->jsonEncode($products); + } + + /** + * Get associated product ids + * + * @return array + */ + public function getAssociatedProductIds() + { + $associatedProducts = Mage::registry('current_product')->getTypeInstance() + ->getAssociatedProducts(Mage::registry('current_product')); + $ids = array(); + foreach ($associatedProducts as $product) { + $ids[] = $product->getId(); + } + return $this->helper('Mage_Core_Helper_Data')->jsonEncode($ids); + } + + /** + * Get hidden input name + * + * @return string + */ + public function getHiddenInputName() + { + return $this->_hiddenInputName; + } + + /** + * Get fields names + * + * @return array + */ + public function getFieldsToSave() + { + return $this->_fieldsToSave; + } + + /** + * Init function + * + * @param string $hiddenInputName + * @param array $fieldsToSave + */ + public function setGridData($hiddenInputName, $fieldsToSave = array()) + { + $this->_hiddenInputName = $hiddenInputName; + $this->_fieldsToSave = $fieldsToSave; + } + + /** + * Callback for jQuery UI sortable update + * + * @return string + */ + public function getSortableUpdateCallback() + { + return <<<SCRIPT +function () { + if(jQuery && jQuery('#grouped-product-container').data('groupedProduct')) { + jQuery('#grouped-product-container').groupedProduct('updateRowsPositions'); + } +} +SCRIPT; + } +} diff --git a/app/code/core/Mage/Catalog/Model/Api/Resource.php b/app/code/core/Mage/Catalog/Model/Api/Resource.php new file mode 100644 index 00000000000..ef968559942 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Api/Resource.php @@ -0,0 +1,135 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog api resource + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Api_Resource extends Mage_Api_Model_Resource_Abstract +{ + /** + * Default ignored attribute codes + * + * @var array + */ + protected $_ignoredAttributeCodes = array('entity_id', 'attribute_set_id', 'entity_type_id'); + + /** + * Default ignored attribute types + * + * @var array + */ + protected $_ignoredAttributeTypes = array(); + + /** + * Field name in session for saving store id + * @var string + */ + protected $_storeIdSessionField = 'store_id'; + + /** + * Check is attribute allowed + * + * @param Mage_Eav_Model_Entity_Attribute_Abstract $attribute + * @param array $attributes + * @return boolean + */ + protected function _isAllowedAttribute($attribute, $attributes = null) + { + if (is_array($attributes) + && !( in_array($attribute->getAttributeCode(), $attributes) + || in_array($attribute->getAttributeId(), $attributes))) { + return false; + } + + return !in_array($attribute->getFrontendInput(), $this->_ignoredAttributeTypes) + && !in_array($attribute->getAttributeCode(), $this->_ignoredAttributeCodes); + } + + /** + * Retrives store id from store code, if no store id specified, + * it use seted session or admin store + * + * @param string|int $store + * @return int + */ + protected function _getStoreId($store = null) + { + if (is_null($store)) { + $store = ($this->_getSession()->hasData($this->_storeIdSessionField) + ? $this->_getSession()->getData($this->_storeIdSessionField) : 0); + } + + try { + $storeId = Mage::app()->getStore($store)->getId(); + } catch (Mage_Core_Model_Store_Exception $e) { + $this->_fault('store_not_exists'); + } + + return $storeId; + } + + /** + * Return loaded product instance + * + * @param int|string $productId (SKU or ID) + * @param int|string $store + * @param string $identifierType + * @return Mage_Catalog_Model_Product + */ + protected function _getProduct($productId, $store = null, $identifierType = null) + { + $product = Mage::helper('Mage_Catalog_Helper_Product')->getProduct($productId, $this->_getStoreId($store), $identifierType); + if (is_null($product->getId())) { + $this->_fault('product_not_exists'); + } + return $product; + } + + /** + * Set current store for catalog. + * + * @param string|int $store + * @return int + */ + public function currentStore($store=null) + { + if (!is_null($store)) { + try { + $storeId = Mage::app()->getStore($store)->getId(); + } catch (Mage_Core_Model_Store_Exception $e) { + $this->_fault('store_not_exists'); + } + + $this->_getSession()->setData($this->_storeIdSessionField, $storeId); + } + + return $this->_getStoreId(); + } +} // Class Mage_Catalog_Model_Api_Resource End diff --git a/app/code/core/Mage/Catalog/Model/Category/Api.php b/app/code/core/Mage/Catalog/Model/Category/Api.php new file mode 100644 index 00000000000..261101ce0bc --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Category/Api.php @@ -0,0 +1,524 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog category api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Category_Api extends Mage_Catalog_Model_Api_Resource +{ + public function __construct() + { + $this->_storeIdSessionField = 'category_store_id'; + } + + /** + * Retrive level of categories for category/store view/website + * + * @param string|int $website + * @param string|int $store + * @param int $categoryId + * @return array + */ + public function level($website = null, $store = null, $categoryId = null) + { + $ids = array(); + $storeId = Mage_Catalog_Model_Category::DEFAULT_STORE_ID; + + // load root categories of website + if (null !== $website) { + try { + $website = Mage::app()->getWebsite($website); + if (null === $store) { + if (null === $categoryId) { + foreach ($website->getStores() as $store) { + /* @var $store Mage_Core_Model_Store */ + $ids[] = $store->getRootCategoryId(); + } + } else { + $ids = $categoryId; + } + } elseif (in_array($store, $website->getStoreIds())) { + $storeId = Mage::app()->getStore($store)->getId(); + $ids = (null === $categoryId)? $store->getRootCategoryId() : $categoryId; + } else { + $this->_fault('store_not_exists'); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('website_not_exists', $e->getMessage()); + } + } + elseif (null !== $store) { + // load children of root category of store + if (null === $categoryId) { + try { + $store = Mage::app()->getStore($store); + $storeId = $store->getId(); + $ids = $store->getRootCategoryId(); + } catch (Mage_Core_Model_Store_Exception $e) { + $this->_fault('store_not_exists'); + } + } + // load children of specified category id + else { + $storeId = $this->_getStoreId($store); + $ids = (int)$categoryId; + } + } + // load all root categories + else { + $ids = (null === $categoryId)? Mage_Catalog_Model_Category::TREE_ROOT_ID : $categoryId; + } + + $collection = Mage::getModel('Mage_Catalog_Model_Category')->getCollection() + ->setStoreId($storeId) + ->addAttributeToSelect('name') + ->addAttributeToSelect('is_active'); + + if (is_array($ids)) { + $collection->addFieldToFilter('entity_id', array('in' => $ids)); + } else { + $collection->addFieldToFilter('parent_id', $ids); + } + + // Only basic category data + $result = array(); + foreach ($collection as $category) { + /* @var $category Mage_Catalog_Model_Category */ + $result[] = array( + 'category_id' => $category->getId(), + 'parent_id' => $category->getParentId(), + 'name' => $category->getName(), + 'is_active' => $category->getIsActive(), + 'position' => $category->getPosition(), + 'level' => $category->getLevel() + ); + } + + return $result; + } + + /** + * Retrieve category tree + * + * @param int|null $parentId + * @param string|int|null $store + * @return array + */ + public function tree($parentId = null, $store = null) + { + if (is_null($parentId) && !is_null($store)) { + $parentId = Mage::app()->getStore($this->_getStoreId($store))->getRootCategoryId(); + } elseif (is_null($parentId)) { + $parentId = 1; + } + + /* @var $tree Mage_Catalog_Model_Resource_Category_Tree */ + $tree = Mage::getResourceSingleton('Mage_Catalog_Model_Resource_Category_Tree') + ->load(); + + $root = $tree->getNodeById($parentId); + + if($root && $root->getId() == 1) { + $root->setName(Mage::helper('Mage_Catalog_Helper_Data')->__('Root')); + } + + $collection = Mage::getModel('Mage_Catalog_Model_Category')->getCollection() + ->setStoreId($this->_getStoreId($store)) + ->addAttributeToSelect('name') + ->addAttributeToSelect('is_active'); + + $tree->addCollectionData($collection, true); + + return $this->_nodeToArray($root); + } + + /** + * Convert node to array + * + * @param Varien_Data_Tree_Node $node + * @return array + */ + protected function _nodeToArray(Varien_Data_Tree_Node $node) + { + // Only basic category data + $result = array(); + $result['category_id'] = $node->getId(); + $result['parent_id'] = $node->getParentId(); + $result['name'] = $node->getName(); + $result['is_active'] = $node->getIsActive(); + $result['position'] = $node->getPosition(); + $result['level'] = $node->getLevel(); + $result['children'] = array(); + + foreach ($node->getChildren() as $child) { + $result['children'][] = $this->_nodeToArray($child); + } + + return $result; + } + + /** + * Initialize and return category model + * + * @param int $categoryId + * @param string|int $store + * @return Mage_Catalog_Model_Category + */ + protected function _initCategory($categoryId, $store = null) + { + $category = Mage::getModel('Mage_Catalog_Model_Category') + ->setStoreId($this->_getStoreId($store)) + ->load($categoryId); + + if (!$category->getId()) { + $this->_fault('not_exists'); + } + + return $category; + } + + /** + * Retrieve category data + * + * @param int $categoryId + * @param string|int $store + * @param array $attributes + * @return array + */ + public function info($categoryId, $store = null, $attributes = null) + { + $category = $this->_initCategory($categoryId, $store); + + // Basic category data + $result = array(); + $result['category_id'] = $category->getId(); + + $result['is_active'] = $category->getIsActive(); + $result['position'] = $category->getPosition(); + $result['level'] = $category->getLevel(); + + foreach ($category->getAttributes() as $attribute) { + if ($this->_isAllowedAttribute($attribute, $attributes)) { + $result[$attribute->getAttributeCode()] = $category->getData($attribute->getAttributeCode()); + } + } + $result['parent_id'] = $category->getParentId(); + $result['children'] = $category->getChildren(); + $result['all_children'] = $category->getAllChildren(); + + return $result; + } + + /** + * Create new category + * + * @param int $parentId + * @param array $categoryData + * @param int|string|null $store + * @return int + */ + public function create($parentId, $categoryData, $store = null) + { + $parent_category = $this->_initCategory($parentId, $store); + $category = Mage::getModel('Mage_Catalog_Model_Category') + ->setStoreId($this->_getStoreId($store)); + + $category->addData(array('path'=>implode('/',$parent_category->getPathIds()))); + + $category ->setAttributeSetId($category->getDefaultAttributeSetId()); + /* @var $category Mage_Catalog_Model_Category */ + + foreach ($category->getAttributes() as $attribute) { + if ($this->_isAllowedAttribute($attribute) + && isset($categoryData[$attribute->getAttributeCode()])) { + $category->setData( + $attribute->getAttributeCode(), + $categoryData[$attribute->getAttributeCode()] + ); + } + } + + $category->setParentId($parent_category->getId()); + + try { + $validate = $category->validate(); + if ($validate !== true) { + foreach ($validate as $code => $error) { + if ($error === true) { + Mage::throwException(Mage::helper('Mage_Catalog_Helper_Data')->__('Attribute "%s" is required.', $code)); + } + else { + Mage::throwException($error); + } + } + } + + $category->save(); + } + catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $category->getId(); + } + + /** + * Update category data + * + * @param int $categoryId + * @param array $categoryData + * @param string|int $store + * @return boolean + */ + public function update($categoryId, $categoryData, $store = null) + { + $category = $this->_initCategory($categoryId, $store); + + foreach ($category->getAttributes() as $attribute) { + if ($this->_isAllowedAttribute($attribute) + && isset($categoryData[$attribute->getAttributeCode()])) { + $category->setData( + $attribute->getAttributeCode(), + $categoryData[$attribute->getAttributeCode()] + ); + } + } + + try { + $validate = $category->validate(); + if ($validate !== true) { + foreach ($validate as $code => $error) { + if ($error === true) { + Mage::throwException(Mage::helper('Mage_Catalog_Helper_Data')->__('Attribute "%s" is required.', $code)); + } + else { + Mage::throwException($error); + } + } + } + + $category->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } catch (Mage_Eav_Model_Entity_Attribute_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Move category in tree + * + * @param int $categoryId + * @param int $parentId + * @param int $afterId + * @return boolean + */ + public function move($categoryId, $parentId, $afterId = null) + { + $category = $this->_initCategory($categoryId); + $parent_category = $this->_initCategory($parentId); + + // if $afterId is null - move category to the down + if ($afterId === null && $parent_category->hasChildren()) { + $parentChildren = $parent_category->getChildren(); + $afterId = array_pop(explode(',', $parentChildren)); + } + + if( strpos($parent_category->getPath(), $category->getPath()) === 0) { + $this->_fault('not_moved', "Operation do not allow to move a parent category to any of children category"); + } + + try { + $category->move($parentId, $afterId); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_moved', $e->getMessage()); + } + + return true; + } + + /** + * Delete category + * + * @param int $categoryId + * @return boolean + */ + public function delete($categoryId) + { + if (Mage_Catalog_Model_Category::TREE_ROOT_ID == $categoryId) { + $this->_fault('not_deleted', 'Cannot remove the system category.'); + } + + $category = $this->_initCategory($categoryId); + + try { + $category->delete(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_deleted', $e->getMessage()); + } + + return true; + } + + /** + * Get product Id from sku or from product id + * + * @param int|string $productId + * @param string $identifierType + * @return int + */ + protected function _getProductId($productId, $identifierType = null) + { + $product = Mage::helper('Mage_Catalog_Helper_Product')->getProduct($productId, null, $identifierType); + if (!$product->getId()) { + $this->_fault('product_not_exists', 'Product not exists.'); + } + return $product->getId(); + } + + + /** + * Retrieve list of assigned products to category + * + * @param int $categoryId + * @param string|int $store + * @return array + */ + public function assignedProducts($categoryId, $store = null) + { + $category = $this->_initCategory($categoryId); + + $storeId = $this->_getStoreId($store); + $collection = $category->setStoreId($storeId)->getProductCollection(); + ($storeId == 0)? $collection->addOrder('position', 'asc') : $collection->setOrder('position', 'asc');; + + $result = array(); + + foreach ($collection as $product) { + $result[] = array( + 'product_id' => $product->getId(), + 'type' => $product->getTypeId(), + 'set' => $product->getAttributeSetId(), + 'sku' => $product->getSku(), + 'position' => $product->getCatIndexPosition() + ); + } + + return $result; + } + + /** + * Assign product to category + * + * @param int $categoryId + * @param int $productId + * @param int $position + * @param string|null $identifierType + * @return boolean + */ + public function assignProduct($categoryId, $productId, $position = null, $identifierType = null) + { + $category = $this->_initCategory($categoryId); + $positions = $category->getProductsPosition(); + $productId = $this->_getProductId($productId, $identifierType); + $positions[$productId] = $position; + $category->setPostedProducts($positions); + + try { + $category->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + + /** + * Update product assignment + * + * @param int $categoryId + * @param int $productId + * @param int $position + * @param string|null $identifierType + * @return boolean + */ + public function updateProduct($categoryId, $productId, $position = null, $identifierType = null) + { + $category = $this->_initCategory($categoryId); + $positions = $category->getProductsPosition(); + $productId = $this->_getProductId($productId, $identifierType); + if (!isset($positions[$productId])) { + $this->_fault('product_not_assigned'); + } + $positions[$productId] = $position; + $category->setPostedProducts($positions); + + try { + $category->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Remove product assignment from category + * + * @param int $categoryId + * @param int $productId + * @param string|null $identifierType + * @return boolean + */ + public function removeProduct($categoryId, $productId, $identifierType = null) + { + $category = $this->_initCategory($categoryId); + $positions = $category->getProductsPosition(); + $productId = $this->_getProductId($productId, $identifierType); + if (!isset($positions[$productId])) { + $this->_fault('product_not_assigned'); + } + + unset($positions[$productId]); + $category->setPostedProducts($positions); + + try { + $category->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + +} diff --git a/app/code/core/Mage/Catalog/Model/Category/Api/V2.php b/app/code/core/Mage/Catalog/Model/Category/Api/V2.php new file mode 100644 index 00000000000..6a1179a77c0 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Category/Api/V2.php @@ -0,0 +1,165 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog category api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Category_Api_V2 extends Mage_Catalog_Model_Category_Api +{ + /** + * Retrieve category data + * + * @param int $categoryId + * @param string|int $store + * @param array $attributes + * @return array + */ + public function info($categoryId, $store = null, $attributes = null) + { + $category = $this->_initCategory($categoryId, $store); + + // Basic category data + $result = array(); + $result['category_id'] = $category->getId(); + + $result['is_active'] = $category->getIsActive(); + $result['position'] = $category->getPosition(); + $result['level'] = $category->getLevel(); + + foreach ($category->getAttributes() as $attribute) { + if ($this->_isAllowedAttribute($attribute, $attributes)) { + $result[$attribute->getAttributeCode()] = $category->getDataUsingMethod($attribute->getAttributeCode()); + } + } + $result['parent_id'] = $category->getParentId(); + $result['children'] = $category->getChildren(); + $result['all_children'] = $category->getAllChildren(); + + return $result; + } + + /** + * Create new category + * + * @param int $parentId + * @param array $categoryData + * @return int + */ + public function create($parentId, $categoryData, $store = null) + { + $parent_category = $this->_initCategory($parentId, $store); + + /* @var $category Mage_Catalog_Model_Category */ + $category = Mage::getModel('Mage_Catalog_Model_Category') + ->setStoreId($this->_getStoreId($store)); + + $category->addData(array('path'=>implode('/',$parent_category->getPathIds()))); + + $category ->setAttributeSetId($category->getDefaultAttributeSetId()); + + + foreach ($category->getAttributes() as $attribute) { + $_attrCode = $attribute->getAttributeCode(); + if ($this->_isAllowedAttribute($attribute) + && isset($categoryData->$_attrCode)) { + $category->setData( + $attribute->getAttributeCode(), + $categoryData->$_attrCode + ); + } + } + $category->setParentId($parent_category->getId()); + try { + $validate = $category->validate(); + if ($validate !== true) { + foreach ($validate as $code => $error) { + if ($error === true) { + Mage::throwException(Mage::helper('Mage_Catalog_Helper_Data')->__('Attribute "%s" is required.', $code)); + } + else { + Mage::throwException($error); + } + } + } + + $category->save(); + } + catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $category->getId(); + } + + /** + * Update category data + * + * @param int $categoryId + * @param array $categoryData + * @param string|int $store + * @return boolean + */ + public function update($categoryId, $categoryData, $store = null) + { + $category = $this->_initCategory($categoryId, $store); + + foreach ($category->getAttributes() as $attribute) { + $_attrCode = $attribute->getAttributeCode(); + if ($this->_isAllowedAttribute($attribute) + && isset($categoryData->$_attrCode)) { + $category->setData( + $attribute->getAttributeCode(), + $categoryData->$_attrCode + ); + } + } + + try { + $validate = $category->validate(); + if ($validate !== true) { + foreach ($validate as $code => $error) { + if ($error === true) { + Mage::throwException(Mage::helper('Mage_Catalog_Helper_Data')->__('Attribute "%s" is required.', $code)); + } + else { + Mage::throwException($error); + } + } + } + $category->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } catch (Mage_Eav_Model_Entity_Attribute_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } +} diff --git a/app/code/core/Mage/Catalog/Model/Category/Attribute/Api.php b/app/code/core/Mage/Catalog/Model/Category/Attribute/Api.php new file mode 100644 index 00000000000..4aa133612a0 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Category/Attribute/Api.php @@ -0,0 +1,109 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog category attribute api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Category_Attribute_Api extends Mage_Catalog_Model_Api_Resource +{ + public function __construct() + { + $this->_storeIdSessionField = 'category_store_id'; + } + + /** + * Retrieve category attributes + * + * @return array + */ + public function items() + { + $attributes = Mage::getModel('Mage_Catalog_Model_Category')->getAttributes(); + $result = array(); + + foreach ($attributes as $attribute) { + /* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + if ($this->_isAllowedAttribute($attribute)) { + if (!$attribute->getId() || $attribute->isScopeGlobal()) { + $scope = 'global'; + } elseif ($attribute->isScopeWebsite()) { + $scope = 'website'; + } else { + $scope = 'store'; + } + + $result[] = array( + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'type' => $attribute->getFrontendInput(), + 'required' => $attribute->getIsRequired(), + 'scope' => $scope + ); + } + } + + return $result; + } + + /** + * Retrieve category attribute options + * + * @param int|string $attributeId + * @param string|int $store + * @return array + */ + public function options($attributeId, $store = null) + { + $attribute = Mage::getModel('Mage_Catalog_Model_Category') + ->setStoreId($this->_getStoreId($store)) + ->getResource() + ->getAttribute($attributeId); + + if (!$attribute) { + $this->_fault('not_exists'); + } + + $result = array(); + if ($attribute->usesSource()) { + foreach ($attribute->getSource()->getAllOptions(false) as $optionId=>$optionValue) { + if (is_array($optionValue)) { + $result[] = $optionValue; + } else { + $result[] = array( + 'value' => $optionId, + 'label' => $optionValue + ); + } + } + } + + return $result; + } +} // Class Mage_Catalog_Model_Category_Attribute_Api End diff --git a/app/code/core/Mage/Catalog/Model/Category/Attribute/Api/V2.php b/app/code/core/Mage/Catalog/Model/Category/Attribute/Api/V2.php new file mode 100644 index 00000000000..771d370171f --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Category/Attribute/Api/V2.php @@ -0,0 +1,36 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog category attribute api V2 + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Category_Attribute_Api_V2 extends Mage_Catalog_Model_Category_Attribute_Api +{ +} diff --git a/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Image.php index 1218dd955f8..ba8fc9dbc79 100644 --- a/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Image.php +++ b/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Image.php @@ -71,7 +71,6 @@ class Mage_Catalog_Model_Category_Attribute_Backend_Image extends Mage_Eav_Model if ($e->getCode() != Mage_Core_Model_File_Uploader::TMP_NAME_EMPTY) { Mage::logException($e); } - /** @TODO ??? */ } return $this; } diff --git a/app/code/core/Mage/Catalog/Model/Config.php b/app/code/core/Mage/Catalog/Model/Config.php index 4e6989b12f3..1943108295d 100644 --- a/app/code/core/Mage/Catalog/Model/Config.php +++ b/app/code/core/Mage/Catalog/Model/Config.php @@ -28,6 +28,7 @@ class Mage_Catalog_Model_Config extends Mage_Eav_Model_Config { const XML_PATH_LIST_DEFAULT_SORT_BY = 'catalog/frontend/default_sort_by'; + const XML_PATH_GROUPED_ALLOWED_PRODUCT_TYPES = 'global/catalog/product/type/grouped/allow_product_types'; protected $_attributeSetsById; protected $_attributeSetsByName; diff --git a/app/code/core/Mage/Catalog/Model/Product/Api.php b/app/code/core/Mage/Catalog/Model/Product/Api.php new file mode 100644 index 00000000000..cacdb4d57ca --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Api.php @@ -0,0 +1,528 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Api extends Mage_Catalog_Model_Api_Resource +{ + protected $_filtersMap = array( + 'product_id' => 'entity_id', + 'set' => 'attribute_set_id', + 'type' => 'type_id' + ); + + protected $_defaultProductAttributeList = array( + 'type_id', + 'category_ids', + 'website_ids', + 'name', + 'description', + 'short_description', + 'sku', + 'weight', + 'status', + 'url_key', + 'url_path', + 'visibility', + 'has_options', + 'gift_message_available', + 'price', + 'special_price', + 'special_from_date', + 'special_to_date', + 'tax_class_id', + 'tier_price', + 'meta_title', + 'meta_keyword', + 'meta_description', + 'custom_design', + 'custom_layout_update', + 'options_container', + 'image_label', + 'small_image_label', + 'thumbnail_label', + 'created_at', + 'updated_at' + ); + + public function __construct() + { + $this->_storeIdSessionField = 'product_store_id'; + $this->_ignoredAttributeTypes[] = 'gallery'; + $this->_ignoredAttributeTypes[] = 'media_image'; + } + + /** + * Retrieve list of products with basic info (id, sku, type, set, name) + * + * @param null|object|array $filters + * @param string|int $store + * @return array + */ + public function items($filters = null, $store = null) + { + $collection = Mage::getModel('Mage_Catalog_Model_Product')->getCollection() + ->addStoreFilter($this->_getStoreId($store)) + ->addAttributeToSelect('name'); + + /** @var $apiHelper Mage_Api_Helper_Data */ + $apiHelper = Mage::helper('Mage_Api_Helper_Data'); + $filters = $apiHelper->parseFilters($filters, $this->_filtersMap); + try { + foreach ($filters as $field => $value) { + $collection->addFieldToFilter($field, $value); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('filters_invalid', $e->getMessage()); + } + $result = array(); + foreach ($collection as $product) { + $result[] = array( + 'product_id' => $product->getId(), + 'sku' => $product->getSku(), + 'name' => $product->getName(), + 'set' => $product->getAttributeSetId(), + 'type' => $product->getTypeId(), + 'category_ids' => $product->getCategoryIds(), + 'website_ids' => $product->getWebsiteIds() + ); + } + return $result; + } + + /** + * Retrieve product info + * + * @param int|string $productId + * @param string|int $store + * @param array $attributes + * @return array + */ + public function info($productId, $store = null, $attributes = null, $identifierType = null) + { + $product = $this->_getProduct($productId, $store, $identifierType); + + + $result = array( // Basic product data + 'product_id' => $product->getId(), + 'sku' => $product->getSku(), + 'set' => $product->getAttributeSetId(), + 'type' => $product->getTypeId(), + 'categories' => $product->getCategoryIds(), + 'websites' => $product->getWebsiteIds() + ); + + foreach ($product->getTypeInstance()->getEditableAttributes($product) as $attribute) { + if ($this->_isAllowedAttribute($attribute, $attributes)) { + $result[$attribute->getAttributeCode()] = $product->getData( + $attribute->getAttributeCode()); + } + } + + return $result; + } + + /** + * Create new product. + * + * @param string $type + * @param int $set + * @param string $sku + * @param array $productData + * @param string $store + * @return int + */ + public function create($type, $set, $sku, $productData, $store = null) + { + if (!$type || !$set || !$sku) { + $this->_fault('data_invalid'); + } + + $this->_checkProductTypeExists($type); + $this->_checkProductAttributeSet($set); + + /** @var $product Mage_Catalog_Model_Product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->setStoreId($this->_getStoreId($store)) + ->setAttributeSetId($set) + ->setTypeId($type) + ->setSku($sku); + + if (!isset($productData['stock_data']) || !is_array($productData['stock_data'])) { + //Set default stock_data if not exist in product data + $product->setStockData(array('use_config_manage_stock' => 0)); + } + + foreach ($product->getMediaAttributes() as $mediaAttribute) { + $mediaAttrCode = $mediaAttribute->getAttributeCode(); + $product->setData($mediaAttrCode, 'no_selection'); + } + + $this->_prepareDataForSave($product, $productData); + + try { + /** + * @todo implement full validation process with errors returning which are ignoring now + * @todo see Mage_Catalog_Model_Product::validate() + */ + if (is_array($errors = $product->validate())) { + $strErrors = array(); + foreach($errors as $code => $error) { + if ($error === true) { + $error = Mage::helper('Mage_Catalog_Helper_Data')->__('Attribute "%s" is invalid.', $code); + } + $strErrors[] = $error; + } + $this->_fault('data_invalid', implode("\n", $strErrors)); + } + + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $product->getId(); + } + + /** + * Update product data + * + * @param int|string $productId + * @param array $productData + * @param string|int $store + * @return boolean + */ + public function update($productId, $productData, $store = null, $identifierType = null) + { + $product = $this->_getProduct($productId, $store, $identifierType); + + $this->_prepareDataForSave($product, $productData); + + try { + /** + * @todo implement full validation process with errors returning which are ignoring now + * @todo see Mage_Catalog_Model_Product::validate() + */ + if (is_array($errors = $product->validate())) { + $strErrors = array(); + foreach($errors as $code => $error) { + if ($error === true) { + $error = Mage::helper('Mage_Catalog_Helper_Data')->__('Value for "%s" is invalid.', $code); + } else { + $error = Mage::helper('Mage_Catalog_Helper_Data')->__('Value for "%s" is invalid: %s', $code, $error); + } + $strErrors[] = $error; + } + $this->_fault('data_invalid', implode("\n", $strErrors)); + } + + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Set additional data before product saved + * + * @param Mage_Catalog_Model_Product $product + * @param array $productData + * @return object + */ + protected function _prepareDataForSave($product, $productData) + { + if (isset($productData['website_ids']) && is_array($productData['website_ids'])) { + $product->setWebsiteIds($productData['website_ids']); + } + + foreach ($product->getTypeInstance()->getEditableAttributes($product) as $attribute) { + //Unset data if object attribute has no value in current store + if (Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID !== (int) $product->getStoreId() + && !$product->getExistsStoreValueFlag($attribute->getAttributeCode()) + && !$attribute->isScopeGlobal() + ) { + $product->setData($attribute->getAttributeCode(), false); + } + + if ($this->_isAllowedAttribute($attribute)) { + if (isset($productData[$attribute->getAttributeCode()])) { + $product->setData( + $attribute->getAttributeCode(), + $productData[$attribute->getAttributeCode()] + ); + } elseif (isset($productData['additional_attributes']['single_data'][$attribute->getAttributeCode()])) { + $product->setData( + $attribute->getAttributeCode(), + $productData['additional_attributes']['single_data'][$attribute->getAttributeCode()] + ); + } elseif (isset($productData['additional_attributes']['multi_data'][$attribute->getAttributeCode()])) { + $product->setData( + $attribute->getAttributeCode(), + $productData['additional_attributes']['multi_data'][$attribute->getAttributeCode()] + ); + } + } + } + + if (isset($productData['categories']) && is_array($productData['categories'])) { + $product->setCategoryIds($productData['categories']); + } + + if (isset($productData['websites']) && is_array($productData['websites'])) { + foreach ($productData['websites'] as &$website) { + if (is_string($website)) { + try { + $website = Mage::app()->getWebsite($website)->getId(); + } catch (Exception $e) { } + } + } + $product->setWebsiteIds($productData['websites']); + } + + if (Mage::app()->hasSingleStore()) { + $product->setWebsiteIds(array(Mage::app()->getStore(true)->getWebsite()->getId())); + } + + if (isset($productData['stock_data']) && is_array($productData['stock_data'])) { + $product->setStockData($productData['stock_data']); + } + + if (isset($productData['tier_price']) && is_array($productData['tier_price'])) { + $tierPrices = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Tierprice_Api') + ->prepareTierPrices($product, $productData['tier_price']); + $product->setData(Mage_Catalog_Model_Product_Attribute_Tierprice_Api::ATTRIBUTE_CODE, $tierPrices); + } + $this->_prepareConfigurableAttributes($product, $productData); + } + + /** + * Process configurable attributes + * + * @param Mage_Catalog_Model_Product $product + * @param array $saveData + */ + protected function _prepareConfigurableAttributes(Mage_Catalog_Model_Product $product, array $saveData) + { + if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) { + if ($product->isObjectNew()) { + $this->_prepareConfigurableAttributesForCreate($product, $saveData); + } else { + // TODO: Implement part related to product update + } + } + } + + /** + * Process configurable attributes for product create + * + * @param Mage_Catalog_Model_Product $product + * @param array $saveData + */ + protected function _prepareConfigurableAttributesForCreate(Mage_Catalog_Model_Product $product, array $saveData) + { + $usedConfigurableAttributeIds = array(); + $configurableAttributesData = array(); + if (isset($saveData['configurable_attributes']) && is_array($saveData['configurable_attributes'])) { + foreach ($saveData['configurable_attributes'] as $configurableData) { + if (!isset($configurableData['attribute_code'])) { + continue; + } + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = Mage::getResourceModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + $attribute->load($configurableData['attribute_code'], 'attribute_code'); + if ($attribute->getId()) { + $usedConfigurableAttributeIds[] = $attribute->getId(); + $configurableAttributesData[$attribute->getAttributeCode()] = array( + 'attribute_id' => $attribute->getId(), + 'attribute_code' => $attribute->getAttributeCode(), + 'label' => (isset($configurableData['frontend_label']) && $configurableData['frontend_label']) + ? trim((string) $configurableData['frontend_label']) : null, + 'use_default' => (isset($configurableData['frontend_label_use_default']) + && $configurableData['frontend_label_use_default']) ? 1 : 0, + 'position' => (isset($configurableData['position']) && $configurableData['position']) + ? (int) $configurableData['position'] : 0, + ); + + // save information about configurable options' prices + if (isset($configurableData['prices']) && is_array($configurableData['prices'])) { + $formattedOptions = array(); + foreach ($configurableData['prices'] as $optionPrice) { + if (isset($optionPrice['option_value']) && isset($optionPrice['price']) + && isset($optionPrice['price_type']) + ) { + $formattedOptions[] = array( + 'value_index' => $optionPrice['option_value'], + 'pricing_value' => $optionPrice['price'], + 'is_percent' => ($optionPrice['price_type'] == 'percent') + ); + } + } + $configurableAttributesData[$attribute->getAttributeCode()]['values'] = $formattedOptions; + } + } + } + } + $product->setConfigurableAttributesData($configurableAttributesData); + /** @var $configurableType Mage_Catalog_Model_Product_Type_Configurable */ + $configurableType = $product->getTypeInstance(); + $configurableType->setUsedProductAttributeIds($usedConfigurableAttributeIds, $product); + } + + /** + * Update product special price + * + * @param int|string $productId + * @param float $specialPrice + * @param string $fromDate + * @param string $toDate + * @param string|int $store + * @return boolean + */ + public function setSpecialPrice($productId, $specialPrice = null, $fromDate = null, $toDate = null, $store = null) + { + return $this->update($productId, array( + 'special_price' => $specialPrice, + 'special_from_date' => $fromDate, + 'special_to_date' => $toDate + ), $store); + } + + /** + * Retrieve product special price + * + * @param int|string $productId + * @param string|int $store + * @return array + */ + public function getSpecialPrice($productId, $store = null) + { + return $this->info($productId, $store, array('special_price', 'special_from_date', 'special_to_date')); + } + + /** + * Delete product + * + * @param int|string $productId + * @return boolean + */ + public function delete($productId, $identifierType = null) + { + $product = $this->_getProduct($productId, null, $identifierType); + + try { + $product->delete(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_deleted', $e->getMessage()); + } + + return true; + } + + /** + * Get list of additional attributes which are not in default create/update list + * + * @param $productType + * @param $attributeSetId + * @return array + */ + public function getAdditionalAttributes($productType, $attributeSetId) + { + $this->_checkProductTypeExists($productType); + $this->_checkProductAttributeSet($attributeSetId); + + /** @var $product Mage_Catalog_Model_Product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $productAttributes = $product->setAttributeSetId($attributeSetId) + ->setTypeId($productType) + ->getTypeInstance() + ->getEditableAttributes($product); + + $result = array(); + foreach ($productAttributes as $attribute) { + /* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + if ($attribute->isInSet($attributeSetId) && $this->_isAllowedAttribute($attribute) + && !in_array($attribute->getAttributeCode(), $this->_defaultProductAttributeList)) { + + if ($attribute->isScopeGlobal()) { + $scope = 'global'; + } elseif ($attribute->isScopeWebsite()) { + $scope = 'website'; + } else { + $scope = 'store'; + } + + $result[] = array( + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'type' => $attribute->getFrontendInput(), + 'required' => $attribute->getIsRequired(), + 'scope' => $scope + ); + } + } + + return $result; + } + + /** + * Check if product type exists + * + * @param $productType + * @throw Mage_Api_Exception + * @return void + */ + protected function _checkProductTypeExists($productType) + { + if (!in_array($productType, array_keys(Mage::getModel('Mage_Catalog_Model_Product_Type')->getOptionArray()))) { + $this->_fault('product_type_not_exists'); + } + } + + /** + * Check if attributeSet is exits and in catalog_product entity group type + * + * @param $attributeSetId + * @throw Mage_Api_Exception + * @return void + */ + protected function _checkProductAttributeSet($attributeSetId) + { + $attributeSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set')->load($attributeSetId); + if (is_null($attributeSet->getId())) { + $this->_fault('product_attribute_set_not_exists'); + } + if (Mage::getModel('Mage_Catalog_Model_Product')->getResource()->getTypeId() != $attributeSet->getEntityTypeId()) { + $this->_fault('product_attribute_set_not_valid'); + } + } +} // Class Mage_Catalog_Model_Product_Api End diff --git a/app/code/core/Mage/Catalog/Model/Product/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Api/V2.php new file mode 100644 index 00000000000..d74389daea7 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Api/V2.php @@ -0,0 +1,308 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product api V2 + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Api_V2 extends Mage_Catalog_Model_Product_Api +{ + /** + * Retrieve product info + * + * @param int|string $productId + * @param string|int $store + * @param stdClass $attributes + * @return array + */ + public function info($productId, $store = null, $attributes = null, $identifierType = null) + { + $product = $this->_getProduct($productId, $store, $identifierType); + + $result = array( // Basic product data + 'product_id' => $product->getId(), + 'sku' => $product->getSku(), + 'set' => $product->getAttributeSetId(), + 'type' => $product->getTypeId(), + 'categories' => $product->getCategoryIds(), + 'websites' => $product->getWebsiteIds() + ); + + $allAttributes = array(); + if (!empty($attributes->attributes)) { + $allAttributes = array_merge($allAttributes, $attributes->attributes); + } else { + foreach ($product->getTypeInstance()->getEditableAttributes($product) as $attribute) { + if ($this->_isAllowedAttribute($attribute, $attributes)) { + $allAttributes[] = $attribute->getAttributeCode(); + } + } + } + + $_additionalAttributeCodes = array(); + if (!empty($attributes->additional_attributes)) { + foreach ($attributes->additional_attributes as $k => $_attributeCode) { + $allAttributes[] = $_attributeCode; + $_additionalAttributeCodes[] = $_attributeCode; + } + } + + $_additionalAttribute = 0; + foreach ($product->getTypeInstance()->getEditableAttributes($product) as $attribute) { + if ($this->_isAllowedAttribute($attribute, $allAttributes)) { + if (in_array($attribute->getAttributeCode(), $_additionalAttributeCodes)) { + $result['additional_attributes'][$_additionalAttribute]['key'] = $attribute->getAttributeCode(); + $result['additional_attributes'][$_additionalAttribute]['value'] = $product + ->getData($attribute->getAttributeCode()); + $_additionalAttribute++; + } else { + $result[$attribute->getAttributeCode()] = $product->getData($attribute->getAttributeCode()); + } + } + } + + return $result; + } + + /** + * Create new product. + * + * @param string $type + * @param int $set + * @param string $sku + * @param array $productData + * @param string $store + * @return int + */ + public function create($type, $set, $sku, $productData, $store = null) + { + if (!$type || !$set || !$sku) { + $this->_fault('data_invalid'); + } + + $this->_checkProductTypeExists($type); + $this->_checkProductAttributeSet($set); + + /** @var $product Mage_Catalog_Model_Product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->setStoreId($this->_getStoreId($store)) + ->setAttributeSetId($set) + ->setTypeId($type) + ->setSku($sku); + + if (!property_exists($productData, 'stock_data')) { + //Set default stock_data if not exist in product data + $_stockData = array('use_config_manage_stock' => 0); + $product->setStockData($_stockData); + } + + foreach ($product->getMediaAttributes() as $mediaAttribute) { + $mediaAttrCode = $mediaAttribute->getAttributeCode(); + $product->setData($mediaAttrCode, 'no_selection'); + } + + $this->_prepareDataForSave($product, $productData); + + try { + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $product->getId(); + } + + /** + * Update product data + * + * @param int|string $productId + * @param array $productData + * @param string|int $store + * @return boolean + */ + public function update($productId, $productData, $store = null, $identifierType = null) + { + $product = $this->_getProduct($productId, $store, $identifierType); + + $this->_prepareDataForSave($product, $productData); + + try { + /** + * @todo implement full validation process with errors returning which are ignoring now + * @todo see Mage_Catalog_Model_Product::validate() + */ + if (is_array($errors = $product->validate())) { + $strErrors = array(); + foreach($errors as $code => $error) { + if ($error === true) { + $error = Mage::helper('Mage_Catalog_Helper_Data')->__('Value for "%s" is invalid.', $code); + } else { + $error = Mage::helper('Mage_Catalog_Helper_Data')->__('Value for "%s" is invalid: %s', $code, $error); + } + $strErrors[] = $error; + } + $this->_fault('data_invalid', implode("\n", $strErrors)); + } + + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Set additional data before product saved + * + * @param Mage_Catalog_Model_Product $product + * @param array $productData + * @return object + */ + protected function _prepareDataForSave ($product, $productData) + { + if (property_exists($productData, 'website_ids') && is_array($productData->website_ids)) { + $product->setWebsiteIds($productData->website_ids); + } + + if (property_exists($productData, 'additional_attributes')) { + if (property_exists($productData->additional_attributes, 'single_data')) { + foreach ($productData->additional_attributes->single_data as $_attribute) { + $_attrCode = $_attribute->key; + $productData->$_attrCode = $_attribute->value; + } + } + if (property_exists($productData->additional_attributes, 'multi_data')) { + foreach ($productData->additional_attributes->multi_data as $_attribute) { + $_attrCode = $_attribute->key; + $productData->$_attrCode = $_attribute->value; + } + } + unset($productData->additional_attributes); + } + + foreach ($product->getTypeInstance()->getEditableAttributes($product) as $attribute) { + $_attrCode = $attribute->getAttributeCode(); + + //Unset data if object attribute has no value in current store + if (Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID !== (int) $product->getStoreId() + && !$product->getExistsStoreValueFlag($_attrCode) + && !$attribute->isScopeGlobal() + ) { + $product->setData($_attrCode, false); + } + + if ($this->_isAllowedAttribute($attribute) && (isset($productData->$_attrCode))) { + $product->setData( + $_attrCode, + $productData->$_attrCode + ); + } + } + + if (property_exists($productData, 'categories') && is_array($productData->categories)) { + $product->setCategoryIds($productData->categories); + } + + if (property_exists($productData, 'websites') && is_array($productData->websites)) { + foreach ($productData->websites as &$website) { + if (is_string($website)) { + try { + $website = Mage::app()->getWebsite($website)->getId(); + } catch (Exception $e) { } + } + } + $product->setWebsiteIds($productData->websites); + } + + if (Mage::app()->hasSingleStore()) { + $product->setWebsiteIds(array(Mage::app()->getStore(true)->getWebsite()->getId())); + } + + if (property_exists($productData, 'stock_data')) { + $_stockData = array(); + foreach ($productData->stock_data as $key => $value) { + $_stockData[$key] = $value; + } + $product->setStockData($_stockData); + } + + if (property_exists($productData, 'tier_price')) { + $tierPrices = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2') + ->prepareTierPrices($product, $productData->tier_price); + $product->setData(Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2::ATTRIBUTE_CODE, $tierPrices); + } + + /** @var $helper Mage_Api_Helper_Data */ + $helper = Mage::helper('Mage_Api_Helper_Data'); + $helper->v2AssociativeArrayUnpacker($productData); + $helper->toArray($productData); + $this->_prepareConfigurableAttributes($product, $productData); + } + + /** + * Update product special price + * + * @param int|string $productId + * @param float $specialPrice + * @param string $fromDate + * @param string $toDate + * @param string|int $store + * @param string $identifierType OPTIONAL If 'sku' - search product by SKU, if any except for NULL - search by ID, + * otherwise - try to determine identifier type automatically + * @return boolean + */ + public function setSpecialPrice($productId, $specialPrice = null, $fromDate = null, $toDate = null, $store = null, + $identifierType = null + ) { + $obj = new stdClass(); + $obj->special_price = $specialPrice; + $obj->special_from_date = $fromDate; + $obj->special_to_date = $toDate; + return $this->update($productId, $obj, $store, $identifierType); + } + + /** + * Retrieve product special price + * + * @param int|string $productId + * @param string|int $store + * @return array + */ + public function getSpecialPrice($productId, $store = null) + { + $attributes = new stdClass(); + $attributes->attributes = array( + 'special_price', + 'special_from_date', + 'special_to_date' + ); + return $this->info($productId, $store, $attributes); + } +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Api.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Api.php new file mode 100644 index 00000000000..53ca84511ff --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Api.php @@ -0,0 +1,526 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product attribute api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Api extends Mage_Catalog_Model_Api_Resource +{ + /** + * Product entity type id + * + * @var int + */ + protected $_entityTypeId; + + /** + * Constructor. Initializes default values. + */ + public function __construct() + { + $this->_storeIdSessionField = 'product_store_id'; + $this->_ignoredAttributeCodes[] = 'type_id'; + $this->_ignoredAttributeTypes[] = 'gallery'; + $this->_ignoredAttributeTypes[] = 'media_image'; + $this->_entityTypeId = Mage::getModel('Mage_Eav_Model_Entity')->setType('catalog_product')->getTypeId(); + } + + /** + * Retrieve attributes from specified attribute set + * + * @param int $setId + * @return array + */ + public function items($setId) + { + $attributes = Mage::getModel('Mage_Catalog_Model_Product')->getResource() + ->loadAllAttributes() + ->getSortedAttributes($setId); + $result = array(); + + foreach ($attributes as $attribute) { + /* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + if ((!$attribute->getId() || $attribute->isInSet($setId)) + && $this->_isAllowedAttribute($attribute)) { + + if (!$attribute->getId() || $attribute->isScopeGlobal()) { + $scope = 'global'; + } elseif ($attribute->isScopeWebsite()) { + $scope = 'website'; + } else { + $scope = 'store'; + } + + $result[] = array( + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'type' => $attribute->getFrontendInput(), + 'required' => $attribute->getIsRequired(), + 'scope' => $scope + ); + } + } + + return $result; + } + + /** + * Retrieve attribute options + * + * @param int $attributeId + * @param string|int $store + * @return array + */ + public function options($attributeId, $store = null) + { + $storeId = $this->_getStoreId($store); + $attribute = Mage::getModel('Mage_Catalog_Model_Product') + ->setStoreId($storeId) + ->getResource() + ->getAttribute($attributeId); + + /* @var $attribute Mage_Catalog_Model_Entity_Attribute */ + if (!$attribute) { + $this->_fault('not_exists'); + } + $options = array(); + if ($attribute->usesSource()) { + foreach ($attribute->getSource()->getAllOptions() as $optionId => $optionValue) { + if (is_array($optionValue)) { + $options[] = $optionValue; + } else { + $options[] = array( + 'value' => $optionId, + 'label' => $optionValue + ); + } + } + } + + return $options; + } + + /** + * Retrieve list of possible attribute types + * + * @return array + */ + public function types() + { + return Mage::getModel('Mage_Catalog_Model_Product_Attribute_Source_Inputtype')->toOptionArray(); + } + + /** + * Create new product attribute + * + * @param array $data input data + * @return integer + */ + public function create($data) + { + /** @var $model Mage_Catalog_Model_Resource_Eav_Attribute */ + $model = Mage::getModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + /** @var $helper Mage_Catalog_Helper_Product */ + $helper = Mage::helper('Mage_Catalog_Helper_Product'); + + if (empty($data['attribute_code']) || !is_array($data['frontend_label'])) { + $this->_fault('invalid_parameters'); + } + + //validate attribute_code + if (!preg_match('/^[a-z][a-z_0-9]{0,254}$/', $data['attribute_code'])) { + $this->_fault('invalid_code'); + } + + //validate frontend_input + $allowedTypes = array(); + foreach ($this->types() as $type) { + $allowedTypes[] = $type['value']; + } + if (!in_array($data['frontend_input'], $allowedTypes)) { + $this->_fault('invalid_frontend_input'); + } + + $data['source_model'] = $helper->getAttributeSourceModelByInputType($data['frontend_input']); + $data['backend_model'] = $helper->getAttributeBackendModelByInputType($data['frontend_input']); + if (is_null($model->getIsUserDefined()) || $model->getIsUserDefined() != 0) { + $data['backend_type'] = $model->getBackendTypeByInput($data['frontend_input']); + } + + $this->_prepareDataForSave($data); + + $model->addData($data); + $model->setEntityTypeId($this->_entityTypeId); + $model->setIsUserDefined(1); + + try { + $model->save(); + // clear translation cache because attribute labels are stored in translation + Mage::app()->cleanCache(array(Mage_Core_Model_Translate::CACHE_TAG)); + } catch (Exception $e) { + $this->_fault('unable_to_save', $e->getMessage()); + } + + return (int) $model->getId(); + } + + /** + * Update product attribute + * + * @param string|integer $attribute attribute code or ID + * @param array $data + * @return boolean + */ + public function update($attribute, $data) + { + $model = $this->_getAttribute($attribute); + + if ($model->getEntityTypeId() != $this->_entityTypeId) { + $this->_fault('can_not_edit'); + } + + $data['attribute_code'] = $model->getAttributeCode(); + $data['is_user_defined'] = $model->getIsUserDefined(); + $data['frontend_input'] = $model->getFrontendInput(); + + $this->_prepareDataForSave($data); + + $model->addData($data); + try { + $model->save(); + // clear translation cache because attribute labels are stored in translation + Mage::app()->cleanCache(array(Mage_Core_Model_Translate::CACHE_TAG)); + return true; + } catch (Exception $e) { + $this->_fault('unable_to_save', $e->getMessage()); + } + } + + /** + * Remove attribute + * + * @param integer|string $attribute attribute ID or code + * @return boolean + */ + public function remove($attribute) + { + $model = $this->_getAttribute($attribute); + + if ($model->getEntityTypeId() != $this->_entityTypeId) { + $this->_fault('can_not_delete'); + } + + try { + $model->delete(); + return true; + } catch (Exception $e) { + $this->_fault('can_not_delete', $e->getMessage()); + } + } + + /** + * Get full information about attribute with list of options + * + * @param integer|string $attribute attribute ID or code + * @return array + */ + public function info($attribute) + { + $model = $this->_getAttribute($attribute); + + if ($model->isScopeGlobal()) { + $scope = 'global'; + } elseif ($model->isScopeWebsite()) { + $scope = 'website'; + } else { + $scope = 'store'; + } + + $frontendLabels = array( + array( + 'store_id' => 0, + 'label' => $model->getFrontendLabel() + ) + ); + foreach ($model->getStoreLabels() as $store_id => $label) { + $frontendLabels[] = array( + 'store_id' => $store_id, + 'label' => $label + ); + } + + $result = array( + 'attribute_id' => $model->getId(), + 'attribute_code' => $model->getAttributeCode(), + 'frontend_input' => $model->getFrontendInput(), + 'default_value' => $model->getDefaultValue(), + 'is_unique' => $model->getIsUnique(), + 'is_required' => $model->getIsRequired(), + 'apply_to' => $model->getApplyTo(), + 'is_configurable' => $model->getIsConfigurable(), + 'is_searchable' => $model->getIsSearchable(), + 'is_visible_in_advanced_search' => $model->getIsVisibleInAdvancedSearch(), + 'is_comparable' => $model->getIsComparable(), + 'is_used_for_promo_rules' => $model->getIsUsedForPromoRules(), + 'is_visible_on_front' => $model->getIsVisibleOnFront(), + 'used_in_product_listing' => $model->getUsedInProductListing(), + 'frontend_label' => $frontendLabels + ); + if ($model->getFrontendInput() != 'price') { + $result['scope'] = $scope; + } + + // set additional fields to different types + switch ($model->getFrontendInput()) { + case 'text': + $result['additional_fields'] = array( + 'frontend_class' => $model->getFrontendClass(), + 'is_html_allowed_on_front' => $model->getIsHtmlAllowedOnFront(), + 'used_for_sort_by' => $model->getUsedForSortBy() + ); + break; + case 'textarea': + $result['additional_fields'] = array( + 'is_wysiwyg_enabled' => $model->getIsWysiwygEnabled(), + 'is_html_allowed_on_front' => $model->getIsHtmlAllowedOnFront(), + ); + break; + case 'date': + case 'boolean': + $result['additional_fields'] = array( + 'used_for_sort_by' => $model->getUsedForSortBy() + ); + break; + case 'multiselect': + $result['additional_fields'] = array( + 'is_filterable' => $model->getIsFilterable(), + 'is_filterable_in_search' => $model->getIsFilterableInSearch(), + 'position' => $model->getPosition() + ); + break; + case 'select': + case 'price': + $result['additional_fields'] = array( + 'is_filterable' => $model->getIsFilterable(), + 'is_filterable_in_search' => $model->getIsFilterableInSearch(), + 'position' => $model->getPosition(), + 'used_for_sort_by' => $model->getUsedForSortBy() + ); + break; + default: + $result['additional_fields'] = array(); + break; + } + + // set options + $options = $this->options($model->getId()); + // remove empty first element + if ($model->getFrontendInput() != 'boolean') { + array_shift($options); + } + + if (count($options) > 0) { + $result['options'] = $options; + } + + return $result; + } + + /** + * Add option to select or multiselect attribute + * + * @param integer|string $attribute attribute ID or code + * @param array $data + * @return bool + */ + public function addOption($attribute, $data) + { + $model = $this->_getAttribute($attribute); + + if (!$model->usesSource()) { + $this->_fault('invalid_frontend_input'); + } + + /** @var $helperCatalog Mage_Catalog_Helper_Data */ + $helperCatalog = Mage::helper('Mage_Catalog_Helper_Data'); + + $optionLabels = array(); + foreach ($data['label'] as $label) { + $storeId = $label['store_id']; + $labelText = $helperCatalog->stripTags($label['value']); + if (is_array($storeId)) { + foreach ($storeId as $multiStoreId) { + $optionLabels[$multiStoreId] = $labelText; + } + } else { + $optionLabels[$storeId] = $labelText; + } + } + // data in the following format is accepted by the model + // it simulates parameters of the request made to + // Mage_Adminhtml_Catalog_Product_AttributeController::saveAction() + $modelData = array( + 'option' => array( + 'value' => array( + 'option_1' => $optionLabels + ), + 'order' => array( + 'option_1' => (int) $data['order'] + ) + ) + ); + if ($data['is_default']) { + $modelData['default'][] = 'option_1'; + } + + $model->addData($modelData); + try { + $model->save(); + } catch (Exception $e) { + $this->_fault('unable_to_add_option', $e->getMessage()); + } + + return true; + } + + /** + * Remove option from select or multiselect attribute + * + * @param integer|string $attribute attribute ID or code + * @param integer $optionId option to remove ID + * @return bool + */ + public function removeOption($attribute, $optionId) + { + $model = $this->_getAttribute($attribute); + + if (!$model->usesSource()) { + $this->_fault('invalid_frontend_input'); + } + + // data in the following format is accepted by the model + // it simulates parameters of the request made to + // Mage_Adminhtml_Catalog_Product_AttributeController::saveAction() + $modelData = array( + 'option' => array( + 'value' => array( + $optionId => array() + ), + 'delete' => array( + $optionId => '1' + ) + ) + ); + $model->addData($modelData); + try { + $model->save(); + } catch (Exception $e) { + $this->_fault('unable_to_remove_option', $e->getMessage()); + } + + return true; + } + + /** + * Prepare request input data for saving + * + * @param array $data input data + * @return void + */ + protected function _prepareDataForSave(&$data) + { + /** @var $helperCatalog Mage_Catalog_Helper_Data */ + $helperCatalog = Mage::helper('Mage_Catalog_Helper_Data'); + + if ($data['scope'] == 'global') { + $data['is_global'] = Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL; + } else if ($data['scope'] == 'website') { + $data['is_global'] = Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_WEBSITE; + } else { + $data['is_global'] = Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE; + } + if (!isset($data['is_configurable'])) { + $data['is_configurable'] = 0; + } + if (!isset($data['is_filterable'])) { + $data['is_filterable'] = 0; + } + if (!isset($data['is_filterable_in_search'])) { + $data['is_filterable_in_search'] = 0; + } + if (!isset($data['apply_to'])) { + $data['apply_to'] = array(); + } + // set frontend labels array with store_id as keys + if (isset($data['frontend_label']) && is_array($data['frontend_label'])) { + $labels = array(); + foreach ($data['frontend_label'] as $label) { + $storeId = $label['store_id']; + $labelText = $helperCatalog->stripTags($label['label']); + $labels[$storeId] = $labelText; + } + $data['frontend_label'] = $labels; + } + // set additional fields + if (isset($data['additional_fields']) && is_array($data['additional_fields'])) { + $data = array_merge($data, $data['additional_fields']); + unset($data['additional_fields']); + } + //default value + if (!empty($data['default_value'])) { + $data['default_value'] = $helperCatalog->stripTags($data['default_value']); + } + } + + /** + * Load model by attribute ID or code + * + * @param integer|string $attribute + * @return Mage_Catalog_Model_Resource_Eav_Attribute + */ + protected function _getAttribute($attribute) + { + $model = Mage::getResourceModel('Mage_Catalog_Model_Resource_Eav_Attribute') + ->setEntityTypeId($this->_entityTypeId); + + if (is_numeric($attribute)) { + $model->load(intval($attribute)); + } else { + $model->load($attribute, 'attribute_code'); + } + + if (!$model->getId()) { + $this->_fault('not_exists'); + } + + return $model; + } + +} // Class Mage_Catalog_Model_Product_Attribute_Api End diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Api/V2.php new file mode 100644 index 00000000000..b9098d61408 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Api/V2.php @@ -0,0 +1,99 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product attribute api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Api_V2 extends Mage_Catalog_Model_Product_Attribute_Api +{ + /** + * Create new product attribute + * + * @param array $data input data + * @return integer + */ + public function create($data) + { + $helper = Mage::helper('Mage_Api_Helper_Data'); + $helper->v2AssociativeArrayUnpacker($data); + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::create($data); + } + + /** + * Update product attribute + * + * @param string|integer $attribute attribute code or ID + * @param array $data + * @return boolean + */ + public function update($attribute, $data) + { + $helper = Mage::helper('Mage_Api_Helper_Data'); + $helper->v2AssociativeArrayUnpacker($data); + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::update($attribute, $data); + } + + /** + * Add option to select or multiselect attribute + * + * @param integer|string $attribute attribute ID or code + * @param array $data + * @return bool + */ + public function addOption($attribute, $data) + { + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::addOption($attribute, $data); + } + + /** + * Get full information about attribute with list of options + * + * @param integer|string $attribute attribute ID or code + * @return array + */ + public function info($attribute) + { + $result = parent::info($attribute); + if (!empty($result['additional_fields'])){ + $keys = array_keys($result['additional_fields']); + foreach ($keys as $key ) { + $result['additional_fields'][] = array( + 'key' => $key, + 'value' => $result['additional_fields'][$key] + ); + unset($result['additional_fields'][$key]); + } + } + return $result; + } +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php index e4c946c1779..c04904896e8 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Media.php @@ -42,6 +42,11 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ */ protected $_resourceModel; + /** + * @var Mage_Catalog_Model_Product_Media_Config + */ + protected $_mediaConfig; + /** * @var Magento_Filesystem $filesystem */ @@ -60,19 +65,26 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ /** * Constructor to inject dependencies * + * @param Mage_Catalog_Model_Product_Media_Config $mediaConfig + * @param Mage_Core_Model_Dir $dirs * @param Magento_Filesystem $filesystem * @param array $data */ - public function __construct(Magento_Filesystem $filesystem, $data = array()) - { + public function __construct( + Mage_Catalog_Model_Product_Media_Config $mediaConfig, + Mage_Core_Model_Dir $dirs, + Magento_Filesystem $filesystem, + $data = array() + ) { if (isset($data['resourceModel'])) { $this->_resourceModel = $data['resourceModel']; } + $this->_mediaConfig = $mediaConfig; $this->_filesystem = $filesystem; $this->_filesystem->setIsAllowCreateDirectories(true); - $this->_filesystem->setWorkingDirectory(Mage::getBaseDir('media')); - $this->_baseMediaPath = $this->_getConfig()->getBaseMediaPath(); - $this->_baseTmpMediaPath = $this->_getConfig()->getBaseTmpMediaPath(); + $this->_filesystem->setWorkingDirectory($dirs->getDir(Mage_Core_Model_Dir::MEDIA)); + $this->_baseMediaPath = $this->_mediaConfig->getBaseMediaPath(); + $this->_baseTmpMediaPath = $this->_mediaConfig->getBaseTmpMediaPath(); $this->_filesystem->ensureDirectoryExists($this->_baseMediaPath); $this->_filesystem->ensureDirectoryExists($this->_baseTmpMediaPath); } @@ -329,7 +341,7 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ $fileName = $this->_getNotDuplicatedFilename($fileName, $dispretionPath); - $destinationFile = $this->_getConfig()->getTmpMediaPath($fileName); + $destinationFile = $this->_mediaConfig->getTmpMediaPath($fileName); try { /** @var $storageHelper Mage_Core_Helper_File_Storage_Database */ @@ -338,11 +350,11 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ $this->_filesystem->rename($file, $destinationFile, $this->_baseTmpMediaPath); //If this is used, filesystem should be configured properly - $storageHelper->saveFile($this->_getConfig()->getTmpMediaShortUrl($fileName)); + $storageHelper->saveFile($this->_mediaConfig->getTmpMediaShortUrl($fileName)); } else { $this->_filesystem->copy($file, $destinationFile, $this->_baseTmpMediaPath); - $storageHelper->saveFile($this->_getConfig()->getTmpMediaShortUrl($fileName)); + $storageHelper->saveFile($this->_mediaConfig->getTmpMediaShortUrl($fileName)); $this->_filesystem->changePermissions($destinationFile, 0777, false, $this->_baseTmpMediaPath); } } catch (Exception $e) { @@ -576,16 +588,6 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ return $this->_resourceModel; } - /** - * Retrive media config - * - * @return Mage_Catalog_Model_Product_Media_Config - */ - protected function _getConfig() - { - return Mage::getSingleton('Mage_Catalog_Model_Product_Media_Config'); - } - /** * Move image from temporary directory to normal * @@ -604,16 +606,16 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ if ($storageHelper->checkDbUsage()) { $storageHelper->renameFile( - $this->_getConfig()->getTmpMediaShortUrl($file), - $this->_getConfig()->getMediaShortUrl($destinationFile) + $this->_mediaConfig->getTmpMediaShortUrl($file), + $this->_mediaConfig->getMediaShortUrl($destinationFile) ); - $this->_filesystem->delete($this->_getConfig()->getTmpMediaPath($file), $this->_baseTmpMediaPath); - $this->_filesystem->delete($this->_getConfig()->getMediaPath($destinationFile), $this->_baseMediaPath); + $this->_filesystem->delete($this->_mediaConfig->getTmpMediaPath($file), $this->_baseTmpMediaPath); + $this->_filesystem->delete($this->_mediaConfig->getMediaPath($destinationFile), $this->_baseMediaPath); } else { $this->_filesystem->rename( - $this->_getConfig()->getTmpMediaPath($file), - $this->_getConfig()->getMediaPath($destinationFile), + $this->_mediaConfig->getTmpMediaPath($file), + $this->_mediaConfig->getMediaPath($destinationFile), $this->_baseTmpMediaPath, $this->_baseMediaPath ); @@ -638,7 +640,7 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ ); } else { $destFile = dirname($file) . DS - . Mage_Core_Model_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($file)); + . Mage_Core_Model_File_Uploader::getNewFileName($this->_mediaConfig->getMediaPath($file)); } return $destFile; @@ -655,27 +657,27 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ try { $destinationFile = $this->_getUniqueFileName($file); - if (!$this->_filesystem->isFile($this->_getConfig()->getMediaPath($file), $this->_baseMediaPath)) { + if (!$this->_filesystem->isFile($this->_mediaConfig->getMediaPath($file), $this->_baseMediaPath)) { throw new Exception(); } if (Mage::helper('Mage_Core_Helper_File_Storage_Database')->checkDbUsage()) { Mage::helper('Mage_Core_Helper_File_Storage_Database') - ->copyFile($this->_getConfig()->getMediaShortUrl($file), - $this->_getConfig()->getMediaShortUrl($destinationFile)); + ->copyFile($this->_mediaConfig->getMediaShortUrl($file), + $this->_mediaConfig->getMediaShortUrl($destinationFile)); - $this->_filesystem->delete($this->_getConfig()->getMediaPath($destinationFile), $this->_baseMediaPath); + $this->_filesystem->delete($this->_mediaConfig->getMediaPath($destinationFile), $this->_baseMediaPath); } else { $this->_filesystem->copy( - $this->_getConfig()->getMediaPath($file), - $this->_getConfig()->getMediaPath($destinationFile), + $this->_mediaConfig->getMediaPath($file), + $this->_mediaConfig->getMediaPath($destinationFile), $this->_baseMediaPath ); } return str_replace(DS, '/', $destinationFile); } catch (Exception $e) { - $file = $this->_getConfig()->getMediaPath($file); + $file = $this->_mediaConfig->getMediaPath($file); Mage::throwException( Mage::helper('Mage_Catalog_Helper_Data') ->__('Failed to copy file %s. Please, delete media with non-existing images and try again.', $file) @@ -712,9 +714,9 @@ class Mage_Catalog_Model_Product_Attribute_Backend_Media extends Mage_Eav_Model_ protected function _getNotDuplicatedFilename($fileName, $dispretionPath) { $fileMediaName = $dispretionPath . DS - . Mage_Core_Model_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($fileName)); + . Mage_Core_Model_File_Uploader::getNewFileName($this->_mediaConfig->getMediaPath($fileName)); $fileTmpMediaName = $dispretionPath . DS - . Mage_Core_Model_File_Uploader::getNewFileName($this->_getConfig()->getTmpMediaPath($fileName)); + . Mage_Core_Model_File_Uploader::getNewFileName($this->_mediaConfig->getTmpMediaPath($fileName)); if ($fileMediaName != $fileTmpMediaName) { if ($fileMediaName != $fileName) { diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api.php new file mode 100644 index 00000000000..48665dc4ee0 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api.php @@ -0,0 +1,421 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product media api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Media_Api extends Mage_Catalog_Model_Api_Resource +{ + /** + * Attribute code for media gallery + * + */ + const ATTRIBUTE_CODE = 'media_gallery'; + + /** + * Allowed mime types for image + * + * @var array + */ + protected $_mimeTypes = array( + 'image/jpeg' => 'jpg', + 'image/gif' => 'gif', + 'image/png' => 'png' + ); + + /** @var Mage_Catalog_Model_Product_Media_Config */ + protected $_mediaConfig; + + public function __construct(Mage_Catalog_Model_Product_Media_Config $mediaConfig) + { + $this->_mediaConfig = $mediaConfig; + $this->_storeIdSessionField = 'product_store_id'; + } + + /** + * Retrieve images for product + * + * @param int|string $productId + * @param string|int $store + * @return array + */ + public function items($productId, $store = null, $identifierType = null) + { + $product = $this->_initProduct($productId, $store, $identifierType); + + $gallery = $this->_getGalleryAttribute($product); + + $galleryData = $product->getData(self::ATTRIBUTE_CODE); + + if (!isset($galleryData['images']) || !is_array($galleryData['images'])) { + return array(); + } + + $result = array(); + + foreach ($galleryData['images'] as &$image) { + $result[] = $this->_imageToArray($image, $product); + } + + return $result; + } + + /** + * Retrieve image data + * + * @param int|string $productId + * @param string $file + * @param string|int $store + * @return array + */ + public function info($productId, $file, $store = null, $identifierType = null) + { + $product = $this->_initProduct($productId, $store, $identifierType); + + $gallery = $this->_getGalleryAttribute($product); + + if (!$image = $gallery->getBackend()->getImage($product, $file)) { + $this->_fault('not_exists'); + } + + return $this->_imageToArray($image, $product); + } + + /** + * Create new image for product and return image filename + * + * @throws Mage_Api_Exception + * @param int|string $productId + * @param array $data + * @param string|int $store + * @return string + */ + public function create($productId, $data, $store = null, $identifierType = null) + { + $data = $this->_prepareImageData($data); + + $product = $this->_initProduct($productId, $store, $identifierType); + + $gallery = $this->_getGalleryAttribute($product); + + if (!isset($data['file']) || !isset($data['file']['mime']) || !isset($data['file']['content'])) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('The image is not specified.')); + } + + if (!isset($this->_mimeTypes[$data['file']['mime']])) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid image type.')); + } + + $fileContent = @base64_decode($data['file']['content'], true); + if (!$fileContent) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('The image contents is not valid base64 data.')); + } + + unset($data['file']['content']); + + $tmpDirectory = $this->_mediaConfig->getBaseTmpMediaPath() . DS . microtime(); + + if (isset($data['file']['name']) && $data['file']['name']) { + $fileName = $data['file']['name']; + } else { + $fileName = 'image'; + } + $fileName .= '.' . $this->_mimeTypes[$data['file']['mime']]; + + $ioAdapter = new Varien_Io_File(); + try { + // Create temporary directory for api + $ioAdapter->checkAndCreateFolder($tmpDirectory); + $ioAdapter->open(array('path'=>$tmpDirectory)); + // Write image file + $ioAdapter->write($fileName, $fileContent, 0666); + unset($fileContent); + + // try to create Image object - it fails with Exception if image is not supported + try { + $adapter = Mage::helper('Mage_Core_Helper_Data')->getImageAdapterType(); + new Varien_Image($tmpDirectory . DS . $fileName, $adapter); + } catch (Exception $e) { + // Remove temporary directory + $ioAdapter->rmdir($tmpDirectory, true); + + throw new Mage_Core_Exception($e->getMessage()); + } + + // Adding image to gallery + $file = $gallery->getBackend()->addImage( + $product, + $tmpDirectory . DS . $fileName, + null, + true + ); + + // Remove temporary directory + $ioAdapter->rmdir($tmpDirectory, true); + + $gallery->getBackend()->updateImage($product, $file, $data); + + if (isset($data['types'])) { + $gallery->getBackend()->setMediaAttribute($product, $data['types'], $file); + } + + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_created', $e->getMessage()); + } catch (Exception $e) { + $this->_fault('not_created', Mage::helper('Mage_Catalog_Helper_Data')->__('Cannot create image.')); + } + + return $gallery->getBackend()->getRenamedImage($file); + } + + /** + * Update image data + * + * @param int|string $productId + * @param string $file + * @param array $data + * @param string|int $store + * @return boolean + */ + public function update($productId, $file, $data, $store = null, $identifierType = null) + { + $data = $this->_prepareImageData($data); + + $product = $this->_initProduct($productId, $store, $identifierType); + + $gallery = $this->_getGalleryAttribute($product); + + if (!$gallery->getBackend()->getImage($product, $file)) { + $this->_fault('not_exists'); + } + + if (isset($data['file']['mime']) && isset($data['file']['content'])) { + if (!isset($this->_mimeTypes[$data['file']['mime']])) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid image type.')); + } + + $fileContent = @base64_decode($data['file']['content'], true); + if (!$fileContent) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Image content is not valid base64 data.')); + } + + unset($data['file']['content']); + + $ioAdapter = new Varien_Io_File(); + try { + $fileName = $this->_mediaConfig->getMediaPath($file); + $ioAdapter->open(array('path'=>dirname($fileName))); + $ioAdapter->write(basename($fileName), $fileContent, 0666); + + } catch(Exception $e) { + $this->_fault('not_created', Mage::helper('Mage_Catalog_Helper_Data')->__('Can\'t create image.')); + } + } + + $gallery->getBackend()->updateImage($product, $file, $data); + + if (isset($data['types']) && is_array($data['types'])) { + $oldTypes = array(); + foreach ($product->getMediaAttributes() as $attribute) { + if ($product->getData($attribute->getAttributeCode()) == $file) { + $oldTypes[] = $attribute->getAttributeCode(); + } + } + + $clear = array_diff($oldTypes, $data['types']); + + if (count($clear) > 0) { + $gallery->getBackend()->clearMediaAttribute($product, $clear); + } + + $gallery->getBackend()->setMediaAttribute($product, $data['types'], $file); + } + + try { + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_updated', $e->getMessage()); + } + + return true; + } + + /** + * Remove image from product + * + * @param int|string $productId + * @param string $file + * @return boolean + */ + public function remove($productId, $file, $identifierType = null) + { + $product = $this->_initProduct($productId, null, $identifierType); + + $gallery = $this->_getGalleryAttribute($product); + + if (!$gallery->getBackend()->getImage($product, $file)) { + $this->_fault('not_exists'); + } + + $gallery->getBackend()->removeImage($product, $file); + + try { + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_removed', $e->getMessage()); + } + + return true; + } + + + /** + * Retrieve image types (image, small_image, thumbnail, etc...) + * + * @param int $setId + * @return array + */ + public function types($setId) + { + $attributes = Mage::getModel('Mage_Catalog_Model_Product')->getResource() + ->loadAllAttributes() + ->getSortedAttributes($setId); + + $result = array(); + + foreach ($attributes as $attribute) { + /* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + if ($attribute->isInSet($setId) + && $attribute->getFrontendInput() == 'media_image') { + if ($attribute->isScopeGlobal()) { + $scope = 'global'; + } elseif ($attribute->isScopeWebsite()) { + $scope = 'website'; + } else { + $scope = 'store'; + } + + $result[] = array( + 'code' => $attribute->getAttributeCode(), + 'scope' => $scope + ); + } + } + + return $result; + } + + /** + * Prepare data to create or update image + * + * @param array $data + * @return array + */ + protected function _prepareImageData($data) + { + return $data; + } + + /** + * Retrieve gallery attribute from product + * + * @param Mage_Catalog_Model_Product $product + * @param Mage_Catalog_Model_Resource_Attribute|boolean + */ + protected function _getGalleryAttribute($product) + { + $attributes = $product->getTypeInstance() + ->getSetAttributes($product); + + if (!isset($attributes[self::ATTRIBUTE_CODE])) { + $this->_fault('not_media'); + } + + return $attributes[self::ATTRIBUTE_CODE]; + } + + /** + * Retrie + * ve media config + * + * @return Mage_Catalog_Model_Product_Media_Config + */ + protected function _getMediaConfig() + { + return Mage::getSingleton('Mage_Catalog_Model_Product_Media_Config'); + } + + /** + * Converts image to api array data + * + * @param array $image + * @param Mage_Catalog_Model_Product $product + * @return array + */ + protected function _imageToArray(&$image, $product) + { + $result = array( + 'file' => $image['file'], + 'label' => $image['label'], + 'position' => $image['position'], + 'exclude' => $image['disabled'], + 'url' => $this->_getMediaConfig()->getMediaUrl($image['file']), + 'types' => array() + ); + + + foreach ($product->getMediaAttributes() as $attribute) { + if ($product->getData($attribute->getAttributeCode()) == $image['file']) { + $result['types'][] = $attribute->getAttributeCode(); + } + } + + return $result; + } + + /** + * Retrieve product + * + * @param int|string $productId + * @param string|int $store + * @param string $identifierType + * @return Mage_Catalog_Model_Product + */ + protected function _initProduct($productId, $store = null, $identifierType = null) + { + $product = Mage::helper('Mage_Catalog_Helper_Product')->getProduct($productId, $this->_getStoreId($store), $identifierType); + if (!$product->getId()) { + $this->_fault('product_not_exists'); + } + + return $product; + } +} // Class Mage_Catalog_Model_Product_Attribute_Media_Api End diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api/V2.php new file mode 100644 index 00000000000..35a1abaf46e --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api/V2.php @@ -0,0 +1,53 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product media api V2 + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Media_Api_V2 extends Mage_Catalog_Model_Product_Attribute_Media_Api +{ + /** + * Prepare data to create or update image + * + * @param stdClass $data + * @return array + */ + protected function _prepareImageData($data) + { + if( !is_object($data) ) { + return parent::_prepareImageData($data); + } + $_imageData = get_object_vars($data); + if( isset($data->file) && is_object($data->file) ) { + $_imageData['file'] = get_object_vars($data->file); + } + return parent::_prepareImageData($_imageData); + } +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api.php new file mode 100644 index 00000000000..66489bb9baf --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api.php @@ -0,0 +1,287 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product attribute set api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Set_Api extends Mage_Api_Model_Resource_Abstract +{ + /** + * Retrieve attribute set list + * + * @return array + */ + public function items() + { + $entityType = Mage::getModel('Mage_Catalog_Model_Product')->getResource()->getEntityType(); + $collection = Mage::getResourceModel('Mage_Eav_Model_Resource_Entity_Attribute_Set_Collection') + ->setEntityTypeFilter($entityType->getId()); + + $result = array(); + foreach ($collection as $attributeSet) { + $result[] = array( + 'set_id' => $attributeSet->getId(), + 'name' => $attributeSet->getAttributeSetName() + ); + + } + + return $result; + } + + /** + * Create new attribute set based on another set + * + * @param string $attributeSetName + * @param string $skeletonSetId + * @return integer + */ + public function create($attributeSetName, $skeletonSetId) + { + // check if set with requested $skeletonSetId exists + if (!Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set')->load($skeletonSetId)->getId()){ + $this->_fault('invalid_skeleton_set_id'); + } + // get catalog product entity type id + $entityTypeId = Mage::getModel('Mage_Catalog_Model_Product')->getResource()->getTypeId(); + /** @var $attributeSet Mage_Eav_Model_Entity_Attribute_Set */ + $attributeSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set') + ->setEntityTypeId($entityTypeId) + ->setAttributeSetName($attributeSetName); + try { + // check if name is valid + $attributeSet->validate(); + // copy parameters to new set from skeleton set + $attributeSet->save(); + $attributeSet->initFromSkeleton($skeletonSetId)->save(); + } catch (Mage_Eav_Exception $e) { + $this->_fault('invalid_data', $e->getMessage()); + } catch (Exception $e) { + $this->_fault('create_attribute_set_error', $e->getMessage()); + } + return (int)$attributeSet->getId(); + } + + /** + * Remove attribute set + * + * @param string $attributeSetId + * @param bool $forceProductsRemove + * @return bool + */ + public function remove($attributeSetId, $forceProductsRemove = false) + { + // if attribute set has related goods and $forceProductsRemove is not set throw exception + if (!$forceProductsRemove) { + /** @var $catalogProductsCollection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */ + $catalogProductsCollection = Mage::getModel('Mage_Catalog_Model_Product')->getCollection() + ->addFieldToFilter('attribute_set_id', $attributeSetId); + if (count($catalogProductsCollection)) { + $this->_fault('attribute_set_has_related_products'); + } + } + $attributeSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set')->load($attributeSetId); + // check if set with requested id exists + if (!$attributeSet->getId()){ + $this->_fault('invalid_attribute_set_id'); + } + try { + $attributeSet->delete(); + } catch (Exception $e) { + $this->_fault('remove_attribute_set_error', $e->getMessage()); + } + return true; + } + + /** + * Add attribute to attribute set + * + * @param string $attributeId + * @param string $attributeSetId + * @param string|null $attributeGroupId + * @param string $sortOrder + * @return bool + */ + public function attributeAdd($attributeId, $attributeSetId, $attributeGroupId = null, $sortOrder = '0') + { + // check if attribute with requested id exists + /** @var $attribute Mage_Eav_Model_Entity_Attribute */ + $attribute = Mage::getModel('Mage_Eav_Model_Entity_Attribute')->load($attributeId); + if (!$attribute->getId()) { + $this->_fault('invalid_attribute_id'); + } + // check if attribute set with requested id exists + /** @var $attributeSet Mage_Eav_Model_Entity_Attribute_Set */ + $attributeSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set')->load($attributeSetId); + if (!$attributeSet->getId()) { + $this->_fault('invalid_attribute_set_id'); + } + if (!empty($attributeGroupId)) { + // check if attribute group with requested id exists + if (!Mage::getModel('Mage_Eav_Model_Entity_Attribute_Group')->load($attributeGroupId)->getId()) { + $this->_fault('invalid_attribute_group_id'); + } + } else { + // define default attribute group id for current attribute set + $attributeGroupId = $attributeSet->getDefaultGroupId(); + } + $attribute->setAttributeSetId($attributeSet->getId())->loadEntityAttributeIdBySet(); + if ($attribute->getEntityAttributeId()) { + $this->_fault('attribute_is_already_in_set'); + } + try { + $attribute->setEntityTypeId($attributeSet->getEntityTypeId()) + ->setAttributeSetId($attributeSetId) + ->setAttributeGroupId($attributeGroupId) + ->setSortOrder($sortOrder) + ->save(); + } catch (Exception $e) { + $this->_fault('add_attribute_error', $e->getMessage()); + } + return true; + } + + /** + * Remove attribute from attribute set + * + * @param string $attributeId + * @param string $attributeSetId + * @return bool + */ + public function attributeRemove($attributeId, $attributeSetId) + { + // check if attribute with requested id exists + /** @var $attribute Mage_Eav_Model_Entity_Attribute */ + $attribute = Mage::getModel('Mage_Eav_Model_Entity_Attribute')->load($attributeId); + if (!$attribute->getId()) { + $this->_fault('invalid_attribute_id'); + } + // check if attribute set with requested id exists + /** @var $attributeSet Mage_Eav_Model_Entity_Attribute_Set */ + $attributeSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set')->load($attributeSetId); + if (!$attributeSet->getId()) { + $this->_fault('invalid_attribute_set_id'); + } + // check if attribute is in set + $attribute->setAttributeSetId($attributeSet->getId())->loadEntityAttributeIdBySet(); + if (!$attribute->getEntityAttributeId()) { + $this->_fault('attribute_is_not_in_set'); + } + try { + // delete record from eav_entity_attribute + // using entity_attribute_id loaded by loadEntityAttributeIdBySet() + $attribute->deleteEntity(); + } catch (Exception $e) { + $this->_fault('remove_attribute_error', $e->getMessage()); + } + + return true; + } + + /** + * Create group within existing attribute set + * + * @param string|int $attributeSetId + * @param string $groupName + * @return int + */ + public function groupAdd($attributeSetId, $groupName) + { + /** @var $group Mage_Eav_Model_Entity_Attribute_Group */ + $group = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Group'); + $group->setAttributeSetId($attributeSetId) + ->setAttributeGroupName( + Mage::helper('Mage_Catalog_Helper_Data')->stripTags($groupName) + ); + if ($group->itemExists()) { + $this->_fault('group_already_exists'); + } + try { + $group->save(); + } catch (Exception $e) { + $this->_fault('group_add_error', $e->getMessage()); + } + return (int)$group->getId(); + } + + /** + * Rename existing group + * + * @param string|int $groupId + * @param string $groupName + * @return boolean + */ + public function groupRename($groupId, $groupName) + { + $model = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Group')->load($groupId); + + if (!$model->getAttributeGroupName()) { + $this->_fault('invalid_attribute_group_id'); + } + + $model->setAttributeGroupName( + Mage::helper('Mage_Catalog_Helper_Data')->stripTags($groupName) + ); + try { + $model->save(); + } catch (Exception $e) { + $this->_fault('group_rename_error', $e->getMessage()); + } + return true; + } + + /** + * Remove group from existing attribute set + * + * @param string|int $attributeGroupId + * @return bool + */ + public function groupRemove($attributeGroupId) + { + /** @var $group Mage_Catalog_Model_Product_Attribute_Group */ + $group = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Group')->load($attributeGroupId); + if (!$group->getId()) { + $this->_fault('invalid_attribute_group_id'); + } + if ($group->hasConfigurableAttributes()) { + $this->_fault('group_has_configurable_attributes'); + } + if ($group->hasSystemAttributes()) { + $this->_fault('group_has_system_attributes'); + } + try { + $group->delete(); + } catch (Exception $e) { + $this->_fault('group_remove_error', $e->getMessage()); + } + return true; + } + +} // Class Mage_Catalog_Model_Product_Attribute_Set_Api End diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api/V2.php new file mode 100644 index 00000000000..d3569545110 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Set/Api/V2.php @@ -0,0 +1,36 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product attribute set api V2 + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Set_Api_V2 extends Mage_Catalog_Model_Product_Attribute_Set_Api +{ +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api.php new file mode 100644 index 00000000000..14e4080bbac --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api.php @@ -0,0 +1,185 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog Product tier price api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Tierprice_Api extends Mage_Catalog_Model_Api_Resource +{ + const ATTRIBUTE_CODE = 'tier_price'; + + public function __construct() + { + $this->_storeIdSessionField = 'product_store_id'; + } + + public function info($productId, $identifierType = null) + { + $product = $this->_initProduct($productId, $identifierType); + $tierPrices = $product->getData(self::ATTRIBUTE_CODE); + + if (!is_array($tierPrices)) { + return array(); + } + + $result = array(); + + foreach ($tierPrices as $tierPrice) { + $row = array(); + $row['customer_group_id'] = (empty($tierPrice['all_groups']) ? $tierPrice['cust_group'] : 'all' ); + $row['website'] = ($tierPrice['website_id'] ? + Mage::app()->getWebsite($tierPrice['website_id'])->getCode() : + 'all' + ); + $row['qty'] = $tierPrice['price_qty']; + $row['price'] = $tierPrice['price']; + + $result[] = $row; + } + + return $result; + } + + /** + * Update tier prices of product + * + * @param int|string $productId + * @param array $tierPrices + * @return boolean + */ + public function update($productId, $tierPrices, $identifierType = null) + { + $product = $this->_initProduct($productId, $identifierType); + + $updatedTierPrices = $this->prepareTierPrices($product, $tierPrices); + if (is_null($updatedTierPrices)) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid Tier Prices')); + } + + $product->setData(self::ATTRIBUTE_CODE, $updatedTierPrices); + try { + /** + * @todo implement full validation process with errors returning which are ignoring now + * @todo see Mage_Catalog_Model_Product::validate() + */ + if (is_array($errors = $product->validate())) { + $strErrors = array(); + foreach($errors as $code=>$error) { + $strErrors[] = ($error === true)? Mage::helper('Mage_Catalog_Helper_Data')->__('Value for "%s" is invalid.', $code) : Mage::helper('Mage_Catalog_Helper_Data')->__('Value for "%s" is invalid: %s', $code, $error); + } + $this->_fault('data_invalid', implode("\n", $strErrors)); + } + + $product->save(); + } catch (Mage_Api_Exception $e) { + throw $e; + }catch (Mage_Core_Exception $e) { + $this->_fault('not_updated', $e->getMessage()); + } + + return true; + } + + /** + * Prepare tier prices for save + * + * @param Mage_Catalog_Model_Product $product + * @param array $tierPrices + * @return array + */ + public function prepareTierPrices($product, $tierPrices = null) + { + if (!is_array($tierPrices)) { + return null; + } + + if (!is_array($tierPrices)) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid Tier Prices')); + } + + $updateValue = array(); + + foreach ($tierPrices as $tierPrice) { + if (!is_array($tierPrice) + || !isset($tierPrice['qty']) + || !isset($tierPrice['price'])) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid Tier Prices')); + } + + if (!isset($tierPrice['website']) || $tierPrice['website'] == 'all') { + $tierPrice['website'] = 0; + } else { + try { + $tierPrice['website'] = Mage::app()->getWebsite($tierPrice['website'])->getId(); + } catch (Mage_Core_Exception $e) { + $tierPrice['website'] = 0; + } + } + + if (intval($tierPrice['website']) > 0 && !in_array($tierPrice['website'], $product->getWebsiteIds())) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid tier prices. The product is not associated to the requested website.')); + } + + if (!isset($tierPrice['customer_group_id'])) { + $tierPrice['customer_group_id'] = 'all'; + } + + if ($tierPrice['customer_group_id'] == 'all') { + $tierPrice['customer_group_id'] = Mage_Customer_Model_Group::CUST_GROUP_ALL; + } + + $updateValue[] = array( + 'website_id' => $tierPrice['website'], + 'cust_group' => $tierPrice['customer_group_id'], + 'price_qty' => $tierPrice['qty'], + 'price' => $tierPrice['price'] + ); + } + + return $updateValue; + } + + /** + * Retrieve product + * + * @param int $productId + * @param string $identifierType + * @return Mage_Catalog_Model_Product + */ + protected function _initProduct($productId, $identifierType = null) + { + $product = Mage::helper('Mage_Catalog_Helper_Product')->getProduct($productId, $this->_getStoreId(), $identifierType); + if (!$product->getId()) { + $this->_fault('product_not_exists'); + } + + return $product; + } +} // Class Mage_Catalog_Model_Product_Attribute_Tierprice End diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2.php new file mode 100644 index 00000000000..1ac81133875 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2.php @@ -0,0 +1,91 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog Product tier price api V2 + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2 extends Mage_Catalog_Model_Product_Attribute_Tierprice_Api +{ + /** + * Prepare tier prices for save + * + * @param Mage_Catalog_Model_Product $product + * @param array $tierPrices + * @return array + */ + public function prepareTierPrices($product, $tierPrices = null) + { + if (!is_array($tierPrices)) { + return null; + } + + $updateValue = array(); + + foreach ($tierPrices as $tierPrice) { + if (!is_object($tierPrice) + || !isset($tierPrice->qty) + || !isset($tierPrice->price)) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid Tier Prices')); + } + + if (!isset($tierPrice->website) || $tierPrice->website == 'all') { + $tierPrice->website = 0; + } else { + try { + $tierPrice->website = Mage::app()->getWebsite($tierPrice->website)->getId(); + } catch (Mage_Core_Exception $e) { + $tierPrice->website = 0; + } + } + + if (intval($tierPrice->website) > 0 && !in_array($tierPrice->website, $product->getWebsiteIds())) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Invalid tier prices. The product is not associated to the requested website.')); + } + + if (!isset($tierPrice->customer_group_id)) { + $tierPrice->customer_group_id = 'all'; + } + + if ($tierPrice->customer_group_id == 'all') { + $tierPrice->customer_group_id = Mage_Customer_Model_Group::CUST_GROUP_ALL; + } + + $updateValue[] = array( + 'website_id' => $tierPrice->website, + 'cust_group' => $tierPrice->customer_group_id, + 'price_qty' => $tierPrice->qty, + 'price' => $tierPrice->price + ); + + } + + return $updateValue; + } +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Link/Api.php b/app/code/core/Mage/Catalog/Model/Product/Link/Api.php new file mode 100644 index 00000000000..bee8a8ae908 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Link/Api.php @@ -0,0 +1,349 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product link api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Link_Api extends Mage_Catalog_Model_Api_Resource +{ + /** + * Product link type mapping, used for references and validation + * + * @var array + */ + protected $_typeMap = array( + 'related' => Mage_Catalog_Model_Product_Link::LINK_TYPE_RELATED, + 'up_sell' => Mage_Catalog_Model_Product_Link::LINK_TYPE_UPSELL, + 'cross_sell' => Mage_Catalog_Model_Product_Link::LINK_TYPE_CROSSSELL, + 'grouped' => Mage_Catalog_Model_Product_Link::LINK_TYPE_GROUPED + ); + + public function __construct() + { + $this->_storeIdSessionField = 'product_store_id'; + } + + /** + * Retrieve product link associations + * + * @param string $type + * @param int|sku $productId + * @param string $identifierType + * @return array + */ + public function items($type, $productId, $identifierType = null) + { + $typeId = $this->_getTypeId($type); + + $product = $this->_initProduct($productId, $identifierType); + + $link = $product->getLinkInstance() + ->setLinkTypeId($typeId); + + $collection = $this->_initCollection($link, $product); + + $result = array(); + + foreach ($collection as $linkedProduct) { + $row = array( + 'product_id' => $linkedProduct->getId(), + 'type' => $linkedProduct->getTypeId(), + 'set' => $linkedProduct->getAttributeSetId(), + 'sku' => $linkedProduct->getSku() + ); + + foreach ($link->getAttributes() as $attribute) { + $row[$attribute['code']] = $linkedProduct->getData($attribute['code']); + } + + $result[] = $row; + } + + return $result; + } + + /** + * Add product link association + * + * @param string $type + * @param int|string $productId + * @param int|string $linkedProductId + * @param array $data + * @param string $identifierType + * @return boolean + */ + public function assign($type, $productId, $linkedProductId, $data = array(), $identifierType = null) + { + $typeId = $this->_getTypeId($type); + + $product = $this->_initProduct($productId, $identifierType); + + $link = $product->getLinkInstance() + ->setLinkTypeId($typeId); + + $collection = $this->_initCollection($link, $product); + $idBySku = $product->getIdBySku($linkedProductId); + if ($idBySku) { + $linkedProductId = $idBySku; + } + + $links = $this->_collectionToEditableArray($collection); + + $links[(int)$linkedProductId] = array(); + + foreach ($collection->getLinkModel()->getAttributes() as $attribute) { + if (isset($data[$attribute['code']])) { + $links[(int)$linkedProductId][$attribute['code']] = $data[$attribute['code']]; + } + } + + try { + if ($type == 'grouped') { + $link->getResource()->saveGroupedLinks($product, $links, $typeId); + } else { + $link->getResource()->saveProductLinks($product, $links, $typeId); + } + + $_linkInstance = Mage::getSingleton('Mage_Catalog_Model_Product_Link'); + $_linkInstance->saveProductRelations($product); + + $indexerStock = Mage::getModel('Mage_CatalogInventory_Model_Stock_Status'); + $indexerStock->updateStatus($productId); + + $indexerPrice = Mage::getResourceModel('Mage_Catalog_Model_Resource_Product_Indexer_Price'); + $indexerPrice->reindexProductIds($productId); + } catch (Exception $e) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Link product does not exist.')); + } + + return true; + } + + /** + * Update product link association info + * + * @param string $type + * @param int|string $productId + * @param int|string $linkedProductId + * @param array $data + * @param string $identifierType + * @return boolean + */ + public function update($type, $productId, $linkedProductId, $data = array(), $identifierType = null) + { + $typeId = $this->_getTypeId($type); + + $product = $this->_initProduct($productId, $identifierType); + + $link = $product->getLinkInstance() + ->setLinkTypeId($typeId); + + $collection = $this->_initCollection($link, $product); + + $links = $this->_collectionToEditableArray($collection); + + $idBySku = $product->getIdBySku($linkedProductId); + if ($idBySku) { + $linkedProductId = $idBySku; + } + + foreach ($collection->getLinkModel()->getAttributes() as $attribute) { + if (isset($data[$attribute['code']])) { + $links[(int)$linkedProductId][$attribute['code']] = $data[$attribute['code']]; + } + } + + try { + if ($type == 'grouped') { + $link->getResource()->saveGroupedLinks($product, $links, $typeId); + } else { + $link->getResource()->saveProductLinks($product, $links, $typeId); + } + + $_linkInstance = Mage::getSingleton('Mage_Catalog_Model_Product_Link'); + $_linkInstance->saveProductRelations($product); + + $indexerStock = Mage::getModel('Mage_CatalogInventory_Model_Stock_Status'); + $indexerStock->updateStatus($productId); + + $indexerPrice = Mage::getResourceModel('Mage_Catalog_Model_Resource_Product_Indexer_Price'); + $indexerPrice->reindexProductIds($productId); + } catch (Exception $e) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Link product does not exist.')); + } + + return true; + } + + /** + * Remove product link association + * + * @param string $type + * @param int|string $productId + * @param int|string $linkedProductId + * @param string $identifierType + * @return boolean + */ + public function remove($type, $productId, $linkedProductId, $identifierType = null) + { + $typeId = $this->_getTypeId($type); + + $product = $this->_initProduct($productId, $identifierType); + + $link = $product->getLinkInstance() + ->setLinkTypeId($typeId); + + $collection = $this->_initCollection($link, $product); + + $idBySku = $product->getIdBySku($linkedProductId); + if ($idBySku) { + $linkedProductId = $idBySku; + } + + $links = $this->_collectionToEditableArray($collection); + + if (isset($links[$linkedProductId])) { + unset($links[$linkedProductId]); + } + + try { + $link->getResource()->saveProductLinks($product, $links, $typeId); + } catch (Exception $e) { + $this->_fault('not_removed'); + } + + return true; + } + + /** + * Retrieve attribute list for specified type + * + * @param string $type + * @return array + */ + public function attributes($type) + { + $typeId = $this->_getTypeId($type); + + $attributes = Mage::getModel('Mage_Catalog_Model_Product_Link') + ->getAttributes($typeId); + + $result = array(); + + foreach ($attributes as $attribute) { + $result[] = array( + 'code' => $attribute['code'], + 'type' => $attribute['type'] + ); + } + + return $result; + } + + /** + * Retrieve link types + * + * @return array + */ + public function types() + { + return array_keys($this->_typeMap); + } + + /** + * Retrieve link type id by code + * + * @param string $type + * @return int + */ + protected function _getTypeId($type) + { + if (!isset($this->_typeMap[$type])) { + $this->_fault('type_not_exists'); + } + + return $this->_typeMap[$type]; + } + + /** + * Initialize and return product model + * + * @param int $productId + * @param string $identifierType + * @return Mage_Catalog_Model_Product + */ + protected function _initProduct($productId, $identifierType = null) + { + $product = Mage::helper('Mage_Catalog_Helper_Product')->getProduct($productId, null, $identifierType); + if (!$product->getId()) { + $this->_fault('product_not_exists'); + } + + return $product; + } + + /** + * Initialize and return linked products collection + * + * @param Mage_Catalog_Model_Product_Link $link + * @param Mage_Catalog_Model_Product $product + * @return Mage_Catalog_Model_Resource_Product_Link_Product_Collection + */ + protected function _initCollection($link, $product) + { + $collection = $link + ->getProductCollection() + ->setIsStrongMode() + ->setProduct($product); + + return $collection; + } + + /** + * Export collection to editable array + * + * @param Mage_Catalog_Model_Resource_Product_Link_Product_Collection $collection + * @return array + */ + protected function _collectionToEditableArray($collection) + { + $result = array(); + + foreach ($collection as $linkedProduct) { + $result[$linkedProduct->getId()] = array(); + + foreach ($collection->getLinkModel()->getAttributes() as $attribute) { + $result[$linkedProduct->getId()][$attribute['code']] = $linkedProduct->getData($attribute['code']); + } + } + + return $result; + } +} // Class Mage_Catalog_Model_Product_Link_Api End diff --git a/app/code/core/Mage/Catalog/Model/Product/Link/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Link/Api/V2.php new file mode 100644 index 00000000000..d7a6717c2d6 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Link/Api/V2.php @@ -0,0 +1,119 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product link api V2 + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Link_Api_V2 extends Mage_Catalog_Model_Product_Link_Api +{ + /** + * Add product link association + * + * @param string $type + * @param int|string $productId + * @param int|string $linkedProductId + * @param array $data + * @return boolean + */ + public function assign($type, $productId, $linkedProductId, $data = array(), $identifierType = null) + { + $typeId = $this->_getTypeId($type); + + $product = $this->_initProduct($productId, $identifierType); + + $link = $product->getLinkInstance() + ->setLinkTypeId($typeId); + + $collection = $this->_initCollection($link, $product); + $idBySku = $product->getIdBySku($linkedProductId); + if ($idBySku) { + $linkedProductId = $idBySku; + } + + $links = $this->_collectionToEditableArray($collection); + + $links[(int)$linkedProductId] = array(); + foreach ($collection->getLinkModel()->getAttributes() as $attribute) { + if (isset($data->$attribute['code'])) { + $links[(int)$linkedProductId][$attribute['code']] = $data->$attribute['code']; + } + } + + try { + $link->getResource()->saveProductLinks($product, $links, $typeId); + } catch (Exception $e) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Link product does not exist.')); + } + + return true; + } + + /** + * Update product link association info + * + * @param string $type + * @param int|string $productId + * @param int|string $linkedProductId + * @param array $data + * @return boolean + */ + public function update($type, $productId, $linkedProductId, $data = array(), $identifierType = null) + { + $typeId = $this->_getTypeId($type); + + $product = $this->_initProduct($productId, $identifierType); + + $link = $product->getLinkInstance() + ->setLinkTypeId($typeId); + + $collection = $this->_initCollection($link, $product); + + $links = $this->_collectionToEditableArray($collection); + + $idBySku = $product->getIdBySku($linkedProductId); + if ($idBySku) { + $linkedProductId = $idBySku; + } + + foreach ($collection->getLinkModel()->getAttributes() as $attribute) { + if (isset($data->$attribute['code'])) { + $links[(int)$linkedProductId][$attribute['code']] = $data->$attribute['code']; + } + } + + try { + $link->getResource()->saveProductLinks($product, $links, $typeId); + } catch (Exception $e) { + $this->_fault('data_invalid', Mage::helper('Mage_Catalog_Helper_Data')->__('Link product does not exist.')); + } + + return true; + } +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Option/Api.php b/app/code/core/Mage/Catalog/Model/Product/Option/Api.php new file mode 100644 index 00000000000..836a1273877 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Option/Api.php @@ -0,0 +1,331 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product options api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Option_Api extends Mage_Catalog_Model_Api_Resource +{ + + /** + * Add custom option to product + * + * @param string $productId + * @param array $data + * @param int|string|null $store + * @return bool $isAdded + */ + public function add($productId, $data, $store = null) + { + $product = $this->_getProduct($productId, $store, null); + if (!(is_array($data['additional_fields']) and count($data['additional_fields']))) { + $this->_fault('invalid_data'); + } + if (!$this->_isTypeAllowed($data['type'])) { + $this->_fault('invalid_type'); + } + $this->_prepareAdditionalFields( + $data, + $product->getOptionInstance()->getGroupByType($data['type']) + ); + $this->_saveProductCustomOption($product, $data); + return true; + } + + /** + * Update product custom option data + * + * @param string $optionId + * @param array $data + * @param int|string|null $store + * @return bool + */ + public function update($optionId, $data, $store = null) + { + /** @var $option Mage_Catalog_Model_Product_Option */ + $option = Mage::getModel('Mage_Catalog_Model_Product_Option')->load($optionId); + if (!$option->getId()) { + $this->_fault('option_not_exists'); + } + $product = $this->_getProduct($option->getProductId(), $store, null); + $option = $product->getOptionById($optionId); + if (isset($data['type']) and !$this->_isTypeAllowed($data['type'])) { + $this->_fault('invalid_type'); + } + if (isset($data['additional_fields'])) { + $this->_prepareAdditionalFields( + $data, + $option->getGroupByType() + ); + } + foreach ($option->getValues() as $valueId => $value) { + if(isset($data['values'][$valueId])) { + $data['values'][$valueId] = array_merge($value->getData(), $data['values'][$valueId]); + } + } + $data = array_merge($option->getData(), $data); + $this->_saveProductCustomOption($product, $data); + return true; + } + + /** + * Prepare custom option data for saving by model. Used for custom option add and update + * + * @param array $data + * @param string $groupType + * @return void + */ + protected function _prepareAdditionalFields(&$data, $groupType) + { + if (is_array($data['additional_fields'])) { + if ($groupType != Mage_Catalog_Model_Product_Option::OPTION_GROUP_SELECT) { + // reset can be used as there should be the only + // element in 'additional_fields' for options of all types except those from Select group + $field = reset($data['additional_fields']); + if (!(is_array($field) and count($field))) { + $this->_fault('invalid_data'); + } else { + foreach ($field as $key => $value) { + $data[$key] = $value; + } + } + } else { + // convert Select rows array to appropriate format for saving in the model + foreach ($data['additional_fields'] as $row) { + if (!(is_array($row) and count($row))) { + $this->_fault('invalid_data'); + } else { + foreach ($row as $key => $value) { + $row[$key] = Mage::helper('Mage_Catalog_Helper_Data')->stripTags($value); + } + if (!empty($row['value_id'])) { + // map 'value_id' to 'option_type_id' + $row['option_type_id'] = $row['value_id']; + unset($row['value_id']); + $data['values'][$row['option_type_id']] = $row; + } else { + $data['values'][] = $row; + } + } + } + } + } + unset($data['additional_fields']); + } + + /** + * Save product custom option data. Used for custom option add and update. + * + * @param Mage_Catalog_Model_Product $product + * @param array $data + * @return void + */ + protected function _saveProductCustomOption($product, $data) + { + foreach ($data as $key => $value) { + if (is_string($value)) { + $data[$key] = Mage::helper('Mage_Catalog_Helper_Data')->stripTags($value); + } + } + + try { + if (!$product->getOptionsReadonly()) { + $product + ->getOptionInstance() + ->setOptions(array($data)); + + $product->setHasOptions(true); + + // an empty request can be set as event parameter + // because it is not used for options changing in observers + Mage::dispatchEvent( + 'catalog_product_prepare_save', + array('product' => $product, 'request' => new Mage_Core_Controller_Request_Http()) + ); + + $product->save(); + } + } catch (Exception $e) { + $this->_fault('save_option_error', $e->getMessage()); + } + } + + /** + * Read list of possible custom option types from module config + * + * @return array + */ + public function types() + { + $path = Mage_Catalog_Model_Config_Source_Product_Options_Type::PRODUCT_OPTIONS_GROUPS_PATH; + $types = array(); + foreach (Mage::getConfig()->getNode($path)->children() as $group) { + $groupTypes = Mage::getConfig()->getNode($path . '/' . $group->getName() . '/types')->children(); + /** @var $type Mage_Core_Model_Config_Element */ + foreach($groupTypes as $type){ + $labelPath = $path . '/' . $group->getName() . '/types/' . $type->getName() . '/label'; + $types[] = array( + 'label' => (string) Mage::getConfig()->getNode($labelPath), + 'value' => $type->getName() + ); + } + } + return $types; + } + + /** + * Get full information about custom option in product + * + * @param int|string $optionId + * @param int|string|null $store + * @return array + */ + public function info($optionId, $store = null) + { + /** @var $option Mage_Catalog_Model_Product_Option */ + $option = Mage::getModel('Mage_Catalog_Model_Product_Option')->load($optionId); + if (!$option->getId()) { + $this->_fault('option_not_exists'); + } + /** @var $product Mage_Catalog_Model_Product */ + $product = $this->_getProduct($option->getProductId(), $store, null); + $option = $product->getOptionById($optionId); + $result = array( + 'title' => $option->getTitle(), + 'type' => $option->getType(), + 'is_require' => $option->getIsRequire(), + 'sort_order' => $option->getSortOrder(), + // additional_fields should be two-dimensional array for all option types + 'additional_fields' => array( + array( + 'price' => $option->getPrice(), + 'price_type' => $option->getPriceType(), + 'sku' => $option->getSku() + ) + ) + ); + // Set additional fields to each type group + switch ($option->getGroupByType()) { + case Mage_Catalog_Model_Product_Option::OPTION_GROUP_TEXT: + $result['additional_fields'][0]['max_characters'] = $option->getMaxCharacters(); + break; + case Mage_Catalog_Model_Product_Option::OPTION_GROUP_FILE: + $result['additional_fields'][0]['file_extension'] = $option->getFileExtension(); + $result['additional_fields'][0]['image_size_x'] = $option->getImageSizeX(); + $result['additional_fields'][0]['image_size_y'] = $option->getImageSizeY(); + break; + case Mage_Catalog_Model_Product_Option::OPTION_GROUP_SELECT: + $result['additional_fields'] = array(); + foreach ($option->getValuesCollection() as $value) { + $result['additional_fields'][] = array( + 'value_id' => $value->getId(), + 'title' => $value->getTitle(), + 'price' => $value->getPrice(), + 'price_type' => $value->getPriceType(), + 'sku' => $value->getSku(), + 'sort_order' => $value->getSortOrder() + ); + } + break; + default: + break; + } + + return $result; + } + + /** + * Retrieve list of product custom options + * + * @param string $productId + * @param int|string|null $store + * @return array + */ + public function items($productId, $store = null) + { + $result = array(); + $product = $this->_getProduct($productId, $store, null); + /** @var $option Mage_Catalog_Model_Product_Option */ + foreach ($product->getProductOptionsCollection() as $option) { + $result[] = array( + 'option_id' => $option->getId(), + 'title' => $option->getTitle(), + 'type' => $option->getType(), + 'is_require' => $option->getIsRequire(), + 'sort_order' => $option->getSortOrder() + ); + } + return $result; + } + + /** + * Remove product custom option + * + * @param string $optionId + * @return boolean + */ + public function remove($optionId) + { + /** @var $option Mage_Catalog_Model_Product_Option */ + $option = Mage::getModel('Mage_Catalog_Model_Product_Option')->load($optionId); + if (!$option->getId()) { + $this->_fault('option_not_exists'); + } + try { + $option->getValueInstance()->deleteValue($optionId); + $option->deletePrices($optionId); + $option->deleteTitles($optionId); + $option->delete(); + } catch (Exception $e){ + $this->fault('delete_option_error'); + } + return true; + } + + /** + * Check is type in allowed set + * + * @param string $type + * @return bool + */ + protected function _isTypeAllowed($type) + { + $allowedTypes = array(); + foreach($this->types() as $optionType){ + $allowedTypes[] = $optionType['value']; + } + + if (!in_array($type, $allowedTypes)) { + return false; + } + return true; + } + +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Option/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Option/Api/V2.php new file mode 100644 index 00000000000..7078a21b216 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Option/Api/V2.php @@ -0,0 +1,81 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product options api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Option_Api_V2 extends Mage_Catalog_Model_Product_Option_Api +{ + + /** + * Add custom option to product + * + * @param string $productId + * @param array $data + * @param int|string|null $store + * @return bool + */ + public function add($productId, $data, $store = null) + { + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::add($productId, $data, $store); + } + + /** + * Update product custom option data + * + * @param string $optionId + * @param array $data + * @param int|string|null $store + * @return bool + */ + public function update($optionId, $data, $store = null) + { + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::update($optionId, $data, $store); + } + + /** + * Retrieve list of product custom options + * + * @param string $productId + * @param int|string|null $store + * @return array + */ + public function items($productId, $store = null) + { + $result = parent::items($productId, $store); + foreach ($result as $key => $option) { + $result[$key] = Mage::helper('Mage_Api_Helper_Data')->wsiArrayPacker($option); + } + return $result; + } + +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Option/Value/Api.php b/app/code/core/Mage/Catalog/Model/Product/Option/Value/Api.php new file mode 100644 index 00000000000..5d8d0f4af1a --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Option/Value/Api.php @@ -0,0 +1,226 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product option values api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Option_Value_Api extends Mage_Catalog_Model_Api_Resource +{ + /** + * Retrieve values from specified option + * + * @param string $optionId + * @param int|string|null $store + * @return array + */ + public function items($optionId, $store = null) + { + /** @var $option Mage_Catalog_Model_Product_Option */ + $option = $this->_prepareOption($optionId, $store); + $productOptionValues = $option->getValuesCollection(); + $result = array(); + foreach($productOptionValues as $value){ + $result[] = array( + 'value_id' => $value->getId(), + 'title' => $value->getTitle(), + 'price' => $value->getPrice(), + 'price_type' => $value->getPriceType(), + 'sku' => $value->getSku(), + 'sort_order' => $value->getSortOrder() + ); + } + return $result; + } + + /** + * Retrieve specified option value info + * + * @param string $valueId + * @param int|string|null $store + * @return array + */ + public function info($valueId, $store = null) + { + /** @var $productOptionValue Mage_Catalog_Model_Product_Option_Value */ + $productOptionValue = Mage::getModel('Mage_Catalog_Model_Product_Option_Value')->load($valueId); + if (!$productOptionValue->getId()) { + $this->_fault('value_not_exists'); + } + $storeId = $this->_getStoreId($store); + $productOptionValues = $productOptionValue + ->getValuesByOption( + array($valueId), + $productOptionValue->getOptionId(), + $storeId + ) + ->addTitleToResult($storeId) + ->addPriceToResult($storeId); + + $result = $productOptionValues->toArray(); + // reset can be used as the only item is expected + $result = reset($result['items']); + if (empty($result)) { + $this->_fault('value_not_exists'); + } + // map option_type_id to value_id + $result['value_id'] = $result['option_type_id']; + unset($result['option_type_id']); + return $result; + } + + /** + * Add new values to select option + * + * @param string $optionId + * @param array $data + * @param int|string|null $store + * @return bool + */ + public function add($optionId, $data, $store = null) + { + /** @var $option Mage_Catalog_Model_Product_Option */ + $option = $this->_prepareOption($optionId, $store); + /** @var $optionValueModel Mage_Catalog_Model_Product_Option_Value */ + $optionValueModel = Mage::getModel('Mage_Catalog_Model_Product_Option_Value'); + $optionValueModel->setOption($option); + foreach ($data as &$optionValue) { + foreach ($optionValue as &$value) { + $value = Mage::helper('Mage_Catalog_Helper_Data')->stripTags($value); + } + } + $optionValueModel->setValues($data); + try { + $optionValueModel->saveValues(); + } catch (Exception $e) { + $this->_fault('add_option_value_error', $e->getMessage()); + } + return true; + } + + /** + * Update value to select option + * + * @param string $valueId + * @param array $data + * @param int|string|null $store + * @return bool + */ + public function update($valueId, $data, $store = null) + { + /** @var $productOptionValue Mage_Catalog_Model_Product_Option_Value */ + $productOptionValue = Mage::getModel('Mage_Catalog_Model_Product_Option_Value')->load($valueId); + if (!$productOptionValue->getId()) { + $this->_fault('value_not_exists'); + } + + /** @var $option Mage_Catalog_Model_Product_Option */ + $option = $this->_prepareOption($productOptionValue->getOptionId(), $store); + if (!$option->getId()) { + $this->_fault('option_not_exists'); + } + $productOptionValue->setOption($option); + // Sanitize data + foreach ($data as $key => $value) { + $data[$key] = Mage::helper('Mage_Catalog_Helper_Data')->stripTags($value); + } + if (!isset($data['title']) OR empty($data['title'])) { + $this->_fault('option_value_title_required'); + } + $data['option_type_id'] = $valueId; + $data['store_id'] = $this->_getStoreId($store); + $productOptionValue->addValue($data); + $productOptionValue->setData($data); + + try { + $productOptionValue->save()->saveValues(); + } catch (Exception $e) { + $this->_fault('update_option_value_error', $e->getMessage()); + } + + return true; + } + + /** + * Delete value from select option + * + * @param int $valueId + * @return boolean + */ + public function remove($valueId) + { + /** @var $optionValue Mage_Catalog_Model_Product_Option_Value */ + $optionValue = Mage::getModel('Mage_Catalog_Model_Product_Option_Value')->load($valueId); + if (!$optionValue->getId()) { + $this->_fault('value_not_exists'); + } + + // check values count + if(count($this->items($optionValue->getOptionId())) <= 1){ + $this->_fault('cant_delete_last_value'); + } + + try { + $optionValue->delete(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_deleted', $e->getMessage()); + } + + return true; + } + + /** + * Load option by id and store + * + * @param string $optionId + * @param int|string|null $store + * @return Mage_Catalog_Model_Product_Option + */ + protected function _prepareOption($optionId, $store = null) + { + /** @var $option Mage_Catalog_Model_Product_Option */ + $option = Mage::getModel('Mage_Catalog_Model_Product_Option'); + if (is_string($store) || is_integer($store)) { + $storeId = $this->_getStoreId($store); + $option->setStoreId($storeId); + } + $option->load($optionId); + if (isset($storeId)) { + $option->setData('store_id', $storeId); + } + if (!$option->getId()) { + $this->_fault('option_not_exists'); + } + if ($option->getGroupByType() != Mage_Catalog_Model_Product_Option::OPTION_GROUP_SELECT) { + $this->_fault('invalid_option_type'); + } + return $option; + } + +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Option/Value/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Option/Value/Api/V2.php new file mode 100644 index 00000000000..44bc37a2ce8 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Option/Value/Api/V2.php @@ -0,0 +1,104 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product option values api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Option_Value_Api_V2 extends Mage_Catalog_Model_Product_Option_Value_Api +{ + /** + * Retrieve values from specified option + * + * @param string $optionId + * @param int|string|null $store + * @return array + */ + public function items($optionId, $store = null) + { + $result = parent::items($optionId, $store); + foreach ($result as $key => $optionValue) { + $result[$key] = Mage::helper('Mage_Api_Helper_Data')->wsiArrayPacker($optionValue); + } + return $result; + } + + /** + * Retrieve specified option value info + * + * @param string $valueId + * @param int|string|null $store + * @return array + */ + public function info($valueId, $store = null) + { + return Mage::helper('Mage_Api_Helper_Data')->wsiArrayPacker( + parent::info($valueId, $store) + ); + } + + /** + * Add new values to select option + * + * @param string $optionId + * @param array $data + * @param int|string|null $store + * @return bool + */ + public function add($optionId, $data, $store = null) + { + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::add($optionId, $data, $store); + } + + /** + * Update value to select option + * + * @param string $valueId + * @param array $data + * @param int|string|null $store + * @return bool + */ + public function update($valueId, $data, $store = null) + { + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::update($valueId, $data, $store); + } + + /** + * Delete value from select option + * + * @param int $valueId + * @return boolean + */ + public function remove($valueId) + { + return parent::remove($valueId); + } +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Type/Api.php b/app/code/core/Mage/Catalog/Model/Product/Type/Api.php new file mode 100644 index 00000000000..7413553be01 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Type/Api.php @@ -0,0 +1,54 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product type api + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Type_Api extends Mage_Api_Model_Resource_Abstract +{ + /** + * Retrieve product type list + * + * @return array + */ + public function items() + { + $result = array(); + + foreach (Mage_Catalog_Model_Product_Type::getOptionArray() as $type=>$label) { + $result[] = array( + 'type' => $type, + 'label' => $label + ); + } + + return $result; + } +} // Class Mage_Catalog_Model_Product_Type_Api End diff --git a/app/code/core/Mage/Catalog/Model/Product/Type/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Type/Api/V2.php new file mode 100644 index 00000000000..99f91899ccf --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Product/Type/Api/V2.php @@ -0,0 +1,36 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog product type api V2 + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Product_Type_Api_V2 extends Mage_Catalog_Model_Product_Type_Api +{ +} diff --git a/app/code/core/Mage/Catalog/Model/Product/Type/Configurable.php b/app/code/core/Mage/Catalog/Model/Product/Type/Configurable.php index 0f96e0dbb3e..13091964537 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Type/Configurable.php +++ b/app/code/core/Mage/Catalog/Model/Product/Type/Configurable.php @@ -865,16 +865,6 @@ class Mage_Catalog_Model_Product_Type_Configurable extends Mage_Catalog_Model_Pr ->getConfigurableOptions($product, $this->getUsedProductAttributes($product)); } - /** - * Check that product of this type has weight - * - * @return bool - */ - public function hasWeight() - { - return false; - } - /** * Delete data specific for Configurable product type * diff --git a/app/code/core/Mage/Catalog/Model/Resource/Product/Type/Grouped/AssociatedProductsCollection.php b/app/code/core/Mage/Catalog/Model/Resource/Product/Type/Grouped/AssociatedProductsCollection.php new file mode 100644 index 00000000000..ffd986fc589 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/Resource/Product/Type/Grouped/AssociatedProductsCollection.php @@ -0,0 +1,70 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Associated products collection + * + * @category Mage + * @package Mage_Catalog + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Catalog_Model_Resource_Product_Type_Grouped_AssociatedProductsCollection + extends Mage_Catalog_Model_Resource_Product_Link_Product_Collection +{ + + /** + * Retrieve currently edited product model + * + * @return Mage_Catalog_Model_Product + */ + protected function _getProduct() + { + return Mage::registry('current_product'); + } + + /** + * Prepare select for load + * + * @param Varien_Db_Select $select + * @return string + */ + public function _prepareSelect(Varien_Db_Select $select) + { + $allowProductTypes = array(); + $allowProductTypeNodes = Mage::getConfig() + ->getNode(Mage_Catalog_Model_Config::XML_PATH_GROUPED_ALLOWED_PRODUCT_TYPES)->children(); + foreach ($allowProductTypeNodes as $type) { + $allowProductTypes[] = $type->getName(); + } + + $this->setProduct($this->_getProduct()) + ->addAttributeToSelect('*') + ->addFilterByRequiredOptions() + ->addAttributeToFilter('type_id', $allowProductTypes); + + return parent::_prepareSelect($select); + } +} diff --git a/app/code/core/Mage/Catalog/etc/api.xml b/app/code/core/Mage/Catalog/etc/api.xml new file mode 100644 index 00000000000..4034fb87856 --- /dev/null +++ b/app/code/core/Mage/Catalog/etc/api.xml @@ -0,0 +1,828 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <catalog_category translate="title" module="Mage_Catalog"> + <model>Mage_Catalog_Model_Category_Api</model> + <title>Category API</title> + <acl>catalog/category</acl> + <methods> + <currentStore> + <title>Set/Get current store view</title> + </currentStore> + <tree translate="title" module="Mage_Catalog"> + <title>Retrieve hierarchical tree</title> + <acl>catalog/category/tree</acl> + </tree> + <level translate="title" module="Mage_Catalog"> + <title>Retrieve one level of categories by website/store view/parent category</title> + </level> + <info translate="title" module="Mage_Catalog"> + <title>Retrieve category data</title> + <acl>catalog/category/info</acl> + </info> + <create translate="title" module="Mage_Catalog"> + <title>Create new category</title> + <acl>catalog/category/create</acl> + </create> + <update translate="title" module="Mage_Catalog"> + <title>Update category</title> + <acl>catalog/category/update</acl> + </update> + <move translate="title" module="Mage_Catalog"> + <title>Move category in tree</title> + <acl>catalog/category/move</acl> + </move> + <delete translate="title" module="Mage_Catalog"> + <title>Delete category</title> + <acl>catalog/category/delete</acl> + </delete> + <assignedProducts translate="title" module="Mage_Catalog"> + <title>Retrieve list of assigned products</title> + <acl>catalog/category/product</acl> + </assignedProducts> + <assignProduct translate="title" module="Mage_Catalog"> + <title>Assign product to category</title> + <acl>catalog/category/product/assign</acl> + </assignProduct> + <updateProduct translate="title" module="Mage_Catalog"> + <title>Update assigned product</title> + <acl>catalog/category/product/update</acl> + </updateProduct> + <removeProduct translate="title" module="Mage_Catalog"> + <title>Remove product assignment</title> + <acl>catalog/category/product/remove</acl> + </removeProduct> + </methods> + <faults module="Mage_Catalog"> + <store_not_exists> + <code>100</code> + <message>Requested store view is not found.</message> + </store_not_exists> + <website_not_exists> + <code>101</code> + <message>Requested website is not found.</message> + </website_not_exists> + <not_exists> + <code>102</code> + <message>Category does not exist.</message> + </not_exists> + <data_invalid> + <code>103</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <not_moved> + <code>104</code> + <message>Category is not moved. Details are in error message.</message> + </not_moved> + <not_deleted> + <code>105</code> + <message>Category is not deleted. Details are in error message.</message> + </not_deleted> + <product_not_assigned> + <code>106</code> + <message>Requested product is not assigned to category.</message> + </product_not_assigned> + </faults> + </catalog_category> + <catalog_category_attribute translate="title" module="Mage_Catalog"> + <title>Category attributes API</title> + <model>Mage_Catalog_Model_Category_Attribute_Api</model> + <acl>catalog/category</acl> + <methods> + <currentStore translate="title" module="Mage_Catalog"> + <title>Set/Get current store view</title> + </currentStore> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve category attributes</title> + <method>items</method> + </list> + <options translate="title" module="Mage_Catalog"> + <title>Retrieve attribute options</title> + </options> + </methods> + <faults module="Mage_Catalog"> + <store_not_exists> + <code>100</code> + <message>Requested store view is not found.</message> + </store_not_exists> + <not_exists> + <code>101</code> + <message>Requested attribute is not found.</message> + </not_exists> + </faults> + </catalog_category_attribute> + <catalog_product translate="title" module="Mage_Catalog"> + <title>Product API</title> + <model>Mage_Catalog_Model_Product_Api</model> + <acl>catalog/product</acl> + <methods> + <currentStore translate="title" module="Mage_Catalog"> + <title>Set/Get current store view</title> + </currentStore> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve products list by filters</title> + <method>items</method> + <acl>catalog/product/info</acl> + </list> + <info translate="title" module="Mage_Catalog"> + <title>Retrieve product</title> + <acl>catalog/product/info</acl> + </info> + <create translate="title" module="Mage_Catalog"> + <title>Create new product</title> + <acl>catalog/product/create</acl> + </create> + <update translate="title" module="Mage_Catalog"> + <title>Update product</title> + <acl>catalog/product/update</acl> + </update> + <delete translate="title" module="Mage_Catalog"> + <title>Delete product</title> + <acl>catalog/product/delete</acl> + </delete> + <getSpecialPrice translate="title" module="Mage_Catalog"> + <title>Get special price</title> + </getSpecialPrice> + <setSpecialPrice translate="title" module="Mage_Catalog"> + <title>Set special price</title> + <acl>catalog/product/update</acl> + </setSpecialPrice> + <listOfAdditionalAttributes translate="title" module="Mage_Catalog"> + <title>Get list of additional attributes</title> + <method>getAdditionalAttributes</method> + <acl>catalog/product/info</acl> + </listOfAdditionalAttributes> + </methods> + <faults module="Mage_Catalog"> + <store_not_exists> + <code>100</code> + <message>Requested store view is not found.</message> + </store_not_exists> + <product_not_exists> + <code>101</code> + <message>Product does not exist.</message> + </product_not_exists> + <data_invalid> + <code>102</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <not_deleted> + <code>103</code> + <message>Product is not deleted. Details are in error message.</message> + </not_deleted> + <product_type_not_exists> + <code>104</code> + <message>Product type is not in range of allowed types.</message> + </product_type_not_exists> + <product_attribute_set_not_exists> + <code>105</code> + <message>Product attribute set does not exist.</message> + </product_attribute_set_not_exists> + <product_attribute_set_not_valid> + <code>106</code> + <message>Product attribute set does not belong to catalog product entity type.</message> + </product_attribute_set_not_valid> + </faults> + </catalog_product> + <catalog_product_attribute translate="title" module="Mage_Catalog"> + <title>Product attributes API</title> + <model>Mage_Catalog_Model_Product_Attribute_Api</model> + <acl>catalog/product</acl> + <methods> + <currentStore translate="title" module="Mage_Catalog"> + <title>Set/Get current store view</title> + <acl>catalog/product/attribute/write</acl> + </currentStore> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve attribute list</title> + <method>items</method> + <acl>catalog/product/attribute/read</acl> + </list> + <options translate="title" module="Mage_Catalog"> + <title>Retrieve attribute options</title> + <acl>catalog/product/attribute/read</acl> + </options> + <types translate="title" module="Mage_Catalog"> + <title>Get list of possible attribute types</title> + <acl>catalog/product/attribute/types</acl> + </types> + <create translate="title" module="Mage_Catalog"> + <title>Create new attribute</title> + <acl>catalog/product/attribute/create</acl> + </create> + <update translate="title" module="Mage_Catalog"> + <title>Update attribute</title> + <acl>catalog/product/attribute/update</acl> + </update> + <remove translate="title" module="Mage_Catalog"> + <title>Delete attribute</title> + <acl>catalog/product/attribute/remove</acl> + </remove> + <info translate="title" module="Mage_Catalog"> + <title>Get full information about attribute with list of options</title> + <acl>catalog/product/attribute/info</acl> + </info> + <addOption translate="title" module="Mage_Catalog"> + <title>Add option</title> + <acl>catalog/product/attribute/option/add</acl> + </addOption> + <removeOption translate="title" module="Mage_Catalog"> + <title>Remove option</title> + <acl>catalog/product/attribute/option/remove</acl> + </removeOption> + </methods> + <faults module="Mage_Catalog"> + <store_not_exists> + <code>100</code> + <message>Requested store view is not found.</message> + </store_not_exists> + <not_exists> + <code>101</code> + <message>Requested attribute is not found.</message> + </not_exists> + <invalid_parameters> + <code>102</code> + <message>Provided request parameters are invalid.</message> + </invalid_parameters> + <invalid_code> + <code>103</code> + <message>Attribute code is invalid. Please use only letters (a-z), numbers (0-9), or underscore(_) in this field. First character should be a letter.</message> + </invalid_code> + <invalid_frontend_input> + <code>104</code> + <message>Attribute type is invalid.</message> + </invalid_frontend_input> + <unable_to_save> + <code>105</code> + <message>Unable to save attribute.</message> + </unable_to_save> + <can_not_delete> + <code>106</code> + <message>This attribute cannot be deleted.</message> + </can_not_delete> + <can_not_edit> + <code>107</code> + <message>This attribute cannot be edited.</message> + </can_not_edit> + <unable_to_add_option> + <code>108</code> + <message>Unable to add option.</message> + </unable_to_add_option> + <unable_to_remove_option> + <code>109</code> + <message>Unable to remove option.</message> + </unable_to_remove_option> + </faults> + </catalog_product_attribute> + <catalog_product_attribute_set translate="title" module="Mage_Catalog"> + <title>Product attribute sets API</title> + <model>Mage_Catalog_Model_Product_Attribute_Set_Api</model> + <acl>catalog/product/attribute/set</acl> + <methods> + <create translate="title" module="Mage_Catalog"> + <title>Create attribute set based on another set</title> + <acl>catalog/product/attribute/set/create</acl> + </create> + <remove translate="title" module="Mage_Catalog"> + <title>Remove attribute set</title> + <acl>catalog/product/attribute/set/remove</acl> + </remove> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve product attribute sets</title> + <method>items</method> + <acl>catalog/product/attribute/set/list</acl> + </list> + <attributeAdd translate="title" module="Mage_Catalog"> + <title>Add attribute into attribute set</title> + <acl>catalog/product/attribute/set/attribute_add</acl> + </attributeAdd> + <attributeRemove translate="title" module="Mage_Catalog"> + <title>Remove attribute from attribute set</title> + <acl>catalog/product/attribute/set/attribute_remove</acl> + </attributeRemove> + <groupAdd translate="title" module="Mage_Catalog"> + <title>Add group into attribute set</title> + <acl>catalog/product/attribute/set/group_add</acl> + </groupAdd> + <groupRename translate="title" module="Mage_Catalog"> + <title>Rename existing group</title> + <acl>catalog/product/attribute/set/group_rename</acl> + </groupRename> + <groupRemove translate="title" module="Mage_Catalog"> + <title>Remove group from attribute set</title> + <acl>catalog/product/attribute/set/group_remove</acl> + </groupRemove> + </methods> + <faults module="Mage_Catalog"> + <invalid_skeleton_set_id> + <code>100</code> + <message>Attribute set with requested ID does not exist.</message> + </invalid_skeleton_set_id> + <invalid_data> + <code>101</code> + <message>Provided data is invalid.</message> + </invalid_data> + <create_attribute_set_error> + <code>102</code> + <message>Error occurred while creating attribute set. Details are in error message.</message> + </create_attribute_set_error> + <remove_attribute_set_error> + <code>103</code> + <message>Error occurred while removing attribute set. Details are in error message.</message> + </remove_attribute_set_error> + <invalid_attribute_set_id> + <code>104</code> + <message>Attribute set with requested ID does not exist.</message> + </invalid_attribute_set_id> + <attribute_set_has_related_products> + <code>105</code> + <message>Unable to remove attribute set as it has related items. Use forceProductsRemove parameter to remove attribute set with all items.</message> + </attribute_set_has_related_products> + <invalid_attribute_id> + <code>106</code> + <message>Attribute with requested ID does not exist.</message> + </invalid_attribute_id> + <add_attribute_error> + <code>107</code> + <message>Error occurred while adding attribute to attribute set. Details are in error message.</message> + </add_attribute_error> + <invalid_attribute_group_id> + <code>108</code> + <message>Attribute group with requested ID does not exist.</message> + </invalid_attribute_group_id> + <attribute_is_already_in_set> + <code>109</code> + <message>Requested attribute is already in requested attribute set.</message> + </attribute_is_already_in_set> + <remove_attribute_error> + <code>110</code> + <message>Error occurred while removing attribute from attribute set. Details are in error message.</message> + </remove_attribute_error> + <attribute_is_not_in_set> + <code>111</code> + <message>Requested attribute is not in requested attribute set.</message> + </attribute_is_not_in_set> + <group_already_exists> + <code>112</code> + <message>Requested group is already in requested attribute set.</message> + </group_already_exists> + <group_add_error> + <code>113</code> + <message>Error occurred while adding group to attribute set. Details are in error message.</message> + </group_add_error> + <group_rename_error> + <code>114</code> + <message>Error occurred while renaming group. Details are in error message.</message> + </group_rename_error> + <group_remove_error> + <code>115</code> + <message>Error occurred while removing group from attribute set. Details are in error message.</message> + </group_remove_error> + <group_has_system_attributes> + <code>116</code> + <message>Group cannot be removed as it contains system attributes.</message> + </group_has_system_attributes> + <group_has_configurable_attributes> + <code>117</code> + <message>Group cannot be removed as it contains attributes used in configurable products.</message> + </group_has_configurable_attributes> + </faults> + </catalog_product_attribute_set> + <catalog_product_type translate="title" module="Mage_Catalog"> + <title>Product types API</title> + <model>Mage_Catalog_Model_Product_Type_Api</model> + <acl>catalog/product</acl> + <methods> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve product types</title> + <method>items</method> + </list> + </methods> + <faults module="Mage_Catalog"> + </faults> + </catalog_product_type> + <catalog_product_attribute_media translate="title" module="Mage_Catalog"> + <title>Product Images API</title> + <model>Mage_Catalog_Model_Product_Attribute_Media_Api</model> + <acl>catalog/product/media</acl> + <methods> + <currentStore translate="title" module="Mage_Catalog"> + <title>Set/Get current store view</title> + </currentStore> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve product image list</title> + <method>items</method> + </list> + <info translate="title" module="Mage_Catalog"> + <title>Retrieve product image</title> + </info> + <types translate="title" module="Mage_Catalog"> + <title>Retrieve product image types</title> + </types> + <create translate="title" module="Mage_Catalog"> + <title>Upload new product image </title> + <acl>catalog/product/media/create</acl> + </create> + <update translate="title" module="Mage_Catalog"> + <title>Update product image</title> + <acl>catalog/product/media/update</acl> + </update> + <remove translate="title" module="Mage_Catalog"> + <title>Remove product image</title> + <acl>catalog/product/media/remove</acl> + </remove> + </methods> + <faults module="Mage_Catalog"> + <store_not_exists> + <code>100</code> + <message>Requested store view is not found.</message> + </store_not_exists> + <product_not_exists> + <code>101</code> + <message>Product does not exist.</message> + </product_not_exists> + <data_invalid> + <code>102</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <not_exists> + <code>103</code> + <message>Requested image does not exist in product images' gallery.</message> + </not_exists> + <not_created> + <code>104</code> + <message>Image creation failed. Details are in error message.</message> + </not_created> + <not_updated> + <code>105</code> + <message>Image is not updated. Details are in error message.</message> + </not_updated> + <not_removed> + <code>106</code> + <message>Image is not removed. Details are in error message.</message> + </not_removed> + <not_media> + <code>107</code> + <message>Requested product doesn't support images.</message> + </not_media> + </faults> + </catalog_product_attribute_media> + <catalog_product_attribute_tier_price translate="title" module="Mage_Catalog"> + <title>Product Tier Price API</title> + <model>Mage_Catalog_Model_Product_Attribute_Tierprice_Api</model> + <acl>catalog/product</acl> + <methods> + <info translate="title" module="Mage_Catalog"> + <title>Retrieve product tier prices</title> + </info> + <update translate="title" module="Mage_Catalog"> + <title>Update product tier prices</title> + <acl>catalog/product/update_tier_price</acl> + </update> + </methods> + <faults module="Mage_Catalog"> + <product_not_exists> + <code>100</code> + <message>Product does not exist.</message> + </product_not_exists> + <data_invalid> + <code>101</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <not_updated> + <code>102</code> + <message>Tier prices are not updated. Details are in error message.</message> + </not_updated> + </faults> + </catalog_product_attribute_tier_price> + <catalog_product_link translate="title" module="Mage_Catalog"> + <title>Product links API (related, cross sells, up sells)</title> + <model>Mage_Catalog_Model_Product_Link_Api</model> + <acl>catalog/product/link</acl> + <methods> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve linked products</title> + <method>items</method> + </list> + <assign translate="title" module="Mage_Catalog"> + <title>Assign product link</title> + <acl>catalog/product/link/assign</acl> + </assign> + <update translate="title" module="Mage_Catalog"> + <title>Update product link</title> + <acl>catalog/product/link/update</acl> + </update> + <remove translate="title" module="Mage_Catalog"> + <title>Remove product link</title> + <acl>catalog/product/link/remove</acl> + </remove> + <types translate="title" module="Mage_Catalog"> + <title>Retrieve product link types</title> + </types> + <attributes translate="title" module="Mage_Catalog"> + <title>Retrieve product link type attributes</title> + </attributes> + </methods> + <faults module="Mage_Catalog"> + <type_not_exists> + <code>100</code> + <message>Provided link type is invalid.</message> + </type_not_exists> + <product_not_exists> + <code>101</code> + <message>Product does not exist.</message> + </product_not_exists> + <data_invalid> + <code>102</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <not_removed> + <code>104</code> + <message>Product link is not removed.</message> + </not_removed> + </faults> + </catalog_product_link> + <catalog_product_custom_option translate="title" module="Mage_Catalog"> + <title>Catalog product custom options API</title> + <model>Mage_Catalog_Model_Product_Option_Api</model> + <acl>catalog/product/option</acl> + <methods> + <add translate="title" module="Mage_Catalog"> + <title>Add new custom option into product</title> + <acl>catalog/product/option/add</acl> + </add> + <update translate="title" module="Mage_Catalog"> + <title>Update custom option of product</title> + <acl>catalog/product/option/update</acl> + </update> + <types translate="title" module="Mage_Catalog"> + <title>Get list of available custom option types</title> + <acl>catalog/product/option/types</acl> + </types> + <info translate="title" module="Mage_Catalog"> + <title>Get full information about custom option in product</title> + <acl>catalog/product/option/info</acl> + </info> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve list of product custom options</title> + <acl>catalog/product/option/list</acl> + <method>items</method> + </list> + <remove translate="title" module="Mage_Catalog"> + <title>Remove custom option</title> + <acl>catalog/product/option/remove</acl> + </remove> + </methods> + <faults module="Mage_Catalog"> + <product_not_exists> + <code>101</code> + <message>Product with requested ID does not exist.</message> + </product_not_exists> + <invalid_data> + <code>102</code> + <message>Provided data is invalid.</message> + </invalid_data> + <save_option_error> + <code>103</code> + <message>Error occurred while saving an option. Details are in error message.</message> + </save_option_error> + <store_not_exists> + <code>104</code> + <message>Store with requested code or ID does not exist.</message> + </store_not_exists> + <option_not_exists> + <code>105</code> + <message>Option with requested ID does not exist.</message> + </option_not_exists> + <invalid_type> + <code>106</code> + <message>Provided option type is invalid. Call 'types' to get list of allowed option types.</message> + </invalid_type> + <delete_option_error> + <code>107</code> + <message>Error occurred while deleting an option. Details are in error message.</message> + </delete_option_error> + </faults> + </catalog_product_custom_option> + <catalog_product_custom_option_value translate="title" module="Mage_Catalog"> + <title>Catalog product custom option values API</title> + <model>Mage_Catalog_Model_Product_Option_Value_Api</model> + <acl>catalog/product/option/value</acl> + <methods> + <list translate="title" module="Mage_Catalog"> + <title>Retrieve list of option values</title> + <method>items</method> + <acl>catalog/product/option/value/list</acl> + </list> + <info translate="title" module="Mage_Catalog"> + <title>Retrieve option value info</title> + <acl>catalog/product/option/value/info</acl> + </info> + <add translate="title" module="Mage_Catalog"> + <title>Add new values into custom option</title> + <acl>catalog/product/option/value/add</acl> + </add> + <update translate="title" module="Mage_Catalog"> + <title>Update value of custom option</title> + <acl>catalog/product/option/value/update</acl> + </update> + <remove translate="title" module="Mage_Catalog"> + <title>Remove value from custom option</title> + <acl>catalog/product/option/value/remove</acl> + </remove> + </methods> + <faults module="Mage_Catalog"> + <value_not_exists> + <code>101</code> + <message>Option value with requested ID does not exist.</message> + </value_not_exists> + <add_option_value_error> + <code>102</code> + <message>Error occurred while adding an option value. Details are in error message.</message> + </add_option_value_error> + <option_not_exists> + <code>103</code> + <message>Option with requested ID does not exist.</message> + </option_not_exists> + <invalid_option_type> + <code>104</code> + <message>Provided option type is invalid.</message> + </invalid_option_type> + <store_not_exists> + <code>105</code> + <message>Store with requested code or ID does not exist.</message> + </store_not_exists> + <can_not_delete> + <code>106</code> + <message>Cannot delete option.</message> + </can_not_delete> + <update_option_value_error> + <code>107</code> + <message>Error occurred while updating an option value. Details are in error message.</message> + </update_option_value_error> + <option_value_title_required> + <code>108</code> + <message>Title field is required.</message> + </option_value_title_required> + <cant_delete_last_value> + <code>109</code> + <message>Option should have at least one value. Cannot delete last value.</message> + </cant_delete_last_value> + </faults> + </catalog_product_custom_option_value> + </resources> + <resources_alias> + <category>catalog_category</category> + <category_attribute>catalog_category_attribute</category_attribute> + <product>catalog_product</product> + <product_attribute>catalog_product_attribute</product_attribute> + <product_attribute_set>catalog_product_attribute_set</product_attribute_set> + <product_type>catalog_product_type</product_type> + <product_link>catalog_product_link</product_link> + <product_attribute_media>catalog_product_attribute_media</product_attribute_media> + <product_media>catalog_product_attribute_media</product_media> + <product_attribute_tier_price>catalog_product_attribute_tier_price</product_attribute_tier_price> + <product_tier_price>catalog_product_attribute_tier_price</product_tier_price> + <product_custom_option>catalog_product_custom_option</product_custom_option> + <product_custom_option_value>catalog_product_custom_option_value</product_custom_option_value> + </resources_alias> + <v2> + <resources_function_prefix> + <category>catalogCategory</category> + <category_attribute>catalogCategoryAttribute</category_attribute> + <product>catalogProduct</product> + <product_attribute>catalogProductAttribute</product_attribute> + <product_attribute_set>catalogProductAttributeSet</product_attribute_set> + <product_type>catalogProductType</product_type> + <product_tier_price>catalogProductAttributeTierPrice</product_tier_price> + <product_attribute_media>catalogProductAttributeMedia</product_attribute_media> + <product_link>catalogProductLink</product_link> + <product_custom_option>catalogProductCustomOption</product_custom_option> + <product_custom_option_value>catalogProductCustomOptionValue</product_custom_option_value> + </resources_function_prefix> + </v2> + <acl> + <resources> + <catalog translate="title" module="Mage_Catalog"> + <title>Catalog</title> + <sort_order>1</sort_order> + <category translate="title" module="Mage_Catalog"> + <title>Category</title> + <create translate="title" module="Mage_Catalog"> + <title>Create</title> + </create> + <update translate="title" module="Mage_Catalog"> + <title>Update</title> + </update> + <move translate="title" module="Mage_Catalog"> + <title>Move</title> + </move> + <delete translate="title" module="Mage_Catalog"> + <title>Delete</title> + </delete> + <tree translate="title" module="Mage_Catalog"> + <title>Retrieve categories tree</title> + </tree> + <info translate="title" module="Mage_Catalog"> + <title>Retrieve category data</title> + </info> + <product translate="title" module="Mage_Catalog"> + <title>Assigned Products</title> + <sort_order>100</sort_order> + <assign translate="title" module="Mage_Catalog"> + <title>Assign</title> + </assign> + <update translate="title" module="Mage_Catalog"> + <title>Update</title> + </update> + <remove translate="title" module="Mage_Catalog"> + <title>Remove</title> + </remove> + </product> + </category> + <product translate="title" module="Mage_Catalog"> + <title>Product</title> + <create translate="title" module="Mage_Catalog"> + <title>Create</title> + </create> + <update translate="title" module="Mage_Catalog"> + <title>Update</title> + </update> + <delete translate="title" module="Mage_Catalog"> + <title>Delete</title> + </delete> + <update_tier_price translate="title" module="Mage_Catalog"> + <title>Update Tier Price</title> + </update_tier_price> + <info translate="title" module="Mage_Catalog"> + <title>Retrieve products data</title> + </info> + <attribute translate="title" module="Mage_Catalog"> + <title>Product Attributes</title> + <sort_order>100</sort_order> + <read translate="title" module="Mage_Catalog"> + <title>Retrieve attribute data</title> + </read> + <write translate="title" module="Mage_Catalog"> + <title>Change or Retrieve attribute store view</title> + </write> + </attribute> + <link translate="title" module="Mage_Catalog"> + <title>Link (Related, Up sell, Cross sell)</title> + <sort_order>101</sort_order> + <assign translate="title" module="Mage_Catalog"> + <title>Assign</title> + </assign> + <update translate="title" module="Mage_Catalog"> + <title>Update</title> + </update> + <remove translate="title" module="Mage_Catalog"> + <title>Remove</title> + </remove> + </link> + <media translate="title" module="Mage_Catalog"> + <title>Product Images</title> + <sort_order>102</sort_order> + <create translate="title" module="Mage_Catalog"> + <title>Create (Upload)</title> + </create> + <update translate="title" module="Mage_Catalog"> + <title>Update</title> + </update> + <remove translate="title" module="Mage_Catalog"> + <title>Remove</title> + </remove> + </media> + </product> + </catalog> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/Catalog/etc/wsdl.xml b/app/code/core/Mage/Catalog/etc/wsdl.xml new file mode 100644 index 00000000000..d0bd149e308 --- /dev/null +++ b/app/code/core/Mage/Catalog/etc/wsdl.xml @@ -0,0 +1,2326 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" + schemaLocation="http://schemas.xmlsoap.org/soap/encoding/"/> + <complexType name="catalogProductEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductAdditionalAttributesEntity"> + <all> + <element name="multi_data" type="typens:associativeMultiArray" minOccurs="0" /> + <element name="single_data" type="typens:associativeArray" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogProductConfigurableAttributesEntity"> + <all> + <element name="attribute_code" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="frontend_label" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="frontend_label_use_default" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <element name="position" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <element name="prices" type="typens:catalogProductConfigurableOptionPricesEntityArray" minOccurs="0" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductConfigurableAttributesEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductConfigurableAttributesEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductConfigurableOptionPricesEntity"> + <all> + <element name="option_value" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="use_default_value" type="xsd:int" minOccurs="0" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductConfigurableOptionPricesEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductConfigurableOptionPricesEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductEntity"> + <all> + <element name="product_id" type="xsd:string"/> + <element name="sku" type="xsd:string"/> + <element name="name" type="xsd:string"/> + <element name="set" type="xsd:string"/> + <element name="type" type="xsd:string"/> + <element name="category_ids" type="typens:ArrayOfString"/> + <element name="website_ids" type="typens:ArrayOfString"/> + </all> + </complexType> + <complexType name="catalogProductRequestAttributes"> + <all> + <element name="attributes" type="typens:ArrayOfString" minOccurs="0"/> + <element name="additional_attributes" type="typens:ArrayOfString" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductReturnEntity"> + <all> + <element name="product_id" type="xsd:string" minOccurs="0"/> + <element name="sku" type="xsd:string" minOccurs="0"/> + <element name="set" type="xsd:string" minOccurs="0"/> + <element name="type" type="xsd:string" minOccurs="0"/> + <element name="categories" type="typens:ArrayOfString" minOccurs="0"/> + <element name="websites" type="typens:ArrayOfString" minOccurs="0"/> + <element name="created_at" type="xsd:string" minOccurs="0"/> + <element name="updated_at" type="xsd:string" minOccurs="0"/> + <element name="type_id" type="xsd:string" minOccurs="0"/> + <element name="name" type="xsd:string" minOccurs="0"/> + <element name="description" type="xsd:string" minOccurs="0"/> + <element name="short_description" type="xsd:string" minOccurs="0"/> + <element name="weight" type="xsd:string" minOccurs="0"/> + <element name="status" type="xsd:string" minOccurs="0"/> + <element name="url_key" type="xsd:string" minOccurs="0"/> + <element name="url_path" type="xsd:string" minOccurs="0"/> + <element name="visibility" type="xsd:string" minOccurs="0"/> + <element name="category_ids" type="typens:ArrayOfString" minOccurs="0"/> + <element name="website_ids" type="typens:ArrayOfString" minOccurs="0"/> + <element name="has_options" type="xsd:string" minOccurs="0"/> + <element name="gift_message_available" type="xsd:string" minOccurs="0"/> + <element name="price" type="xsd:string" minOccurs="0"/> + <element name="special_price" type="xsd:string" minOccurs="0"/> + <element name="special_from_date" type="xsd:string" minOccurs="0"/> + <element name="special_to_date" type="xsd:string" minOccurs="0"/> + <element name="tax_class_id" type="xsd:string" minOccurs="0"/> + <element name="tier_price" type="typens:catalogProductTierPriceEntityArray" minOccurs="0"/> + <element name="meta_title" type="xsd:string" minOccurs="0"/> + <element name="meta_keyword" type="xsd:string" minOccurs="0"/> + <element name="meta_description" type="xsd:string" minOccurs="0"/> + <element name="custom_design" type="xsd:string" minOccurs="0"/> + <element name="custom_layout_update" type="xsd:string" minOccurs="0"/> + <element name="options_container" type="xsd:string" minOccurs="0"/> + <element name="additional_attributes" type="typens:associativeArray" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductCreateEntity"> + <all> + <element name="categories" type="typens:ArrayOfString" minOccurs="0"/> + <element name="websites" type="typens:ArrayOfString" minOccurs="0"/> + <element name="name" type="xsd:string" minOccurs="0"/> + <element name="description" type="xsd:string" minOccurs="0"/> + <element name="short_description" type="xsd:string" minOccurs="0"/> + <element name="weight" type="xsd:string" minOccurs="0"/> + <element name="status" type="xsd:string" minOccurs="0"/> + <element name="url_key" type="xsd:string" minOccurs="0"/> + <element name="url_path" type="xsd:string" minOccurs="0"/> + <element name="visibility" type="xsd:string" minOccurs="0"/> + <element name="category_ids" type="typens:ArrayOfString" minOccurs="0"/> + <element name="website_ids" type="typens:ArrayOfString" minOccurs="0"/> + <element name="has_options" type="xsd:string" minOccurs="0"/> + <element name="gift_message_available" type="xsd:string" minOccurs="0"/> + <element name="price" type="xsd:string" minOccurs="0"/> + <element name="special_price" type="xsd:string" minOccurs="0"/> + <element name="special_from_date" type="xsd:string" minOccurs="0"/> + <element name="special_to_date" type="xsd:string" minOccurs="0"/> + <element name="tax_class_id" type="xsd:string" minOccurs="0"/> + <element name="tier_price" type="typens:catalogProductTierPriceEntityArray" minOccurs="0"/> + <element name="meta_title" type="xsd:string" minOccurs="0"/> + <element name="meta_keyword" type="xsd:string" minOccurs="0"/> + <element name="meta_description" type="xsd:string" minOccurs="0"/> + <element name="custom_design" type="xsd:string" minOccurs="0"/> + <element name="custom_layout_update" type="xsd:string" minOccurs="0"/> + <element name="options_container" type="xsd:string" minOccurs="0"/> + <element name="additional_attributes" type="typens:catalogProductAdditionalAttributesEntity" minOccurs="0"/> + <element name="configurable_attributes" type="typens:catalogProductConfigurableAttributesEntityArray" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductAttributeSetEntity"> + <all> + <element name="set_id" type="xsd:int" minOccurs="0"/> + <element name="name" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductAttributeSetEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductAttributeSetEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductTypeEntity"> + <all> + <element name="type" type="xsd:string" minOccurs="0"/> + <element name="label" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductTypeEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductTypeEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductTierPriceEntity"> + <all> + <element name="customer_group_id" type="xsd:string" minOccurs="0"/> + <element name="website" type="xsd:string" minOccurs="0"/> + <element name="qty" type="xsd:int" minOccurs="0"/> + <element name="price" type="xsd:double" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductTierPriceEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductTierPriceEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="ArrayOfCatalogCategoryEntities"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogCategoryEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogCategoryEntity"> + <all> + <element name="category_id" type="xsd:int"/> + <element name="parent_id" type="xsd:int"/> + <element name="name" type="xsd:string"/> + <element name="is_active" type="xsd:int"/> + <element name="position" type="xsd:int"/> + <element name="level" type="xsd:int"/> + <element name="children" type="typens:ArrayOfCatalogCategoryEntities"/> + </all> + </complexType> + <complexType name="catalogCategoryEntityNoChildren"> + <all> + <element name="category_id" type="xsd:int"/> + <element name="parent_id" type="xsd:int"/> + <element name="name" type="xsd:string"/> + <element name="is_active" type="xsd:int"/> + <element name="position" type="xsd:int"/> + <element name="level" type="xsd:int"/> + </all> + </complexType> + <complexType name="ArrayOfCatalogCategoryEntitiesNoChildren"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogCategoryEntityNoChildren[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogCategoryTree"> + <all> + <element name="category_id" type="xsd:int"/> + <element name="parent_id" type="xsd:int"/> + <element name="name" type="xsd:string"/> + <element name="position" type="xsd:int"/> + <element name="level" type="xsd:int"/> + <element name="children" type="typens:ArrayOfCatalogCategoryEntities"/> + </all> + </complexType> + <complexType name="catalogCategoryEntityCreate"> + <all> + <element name="name" type="xsd:string" minOccurs="0"/> + <element name="is_active" type="xsd:int" minOccurs="0"/> + <element name="position" type="xsd:int" minOccurs="0"/> + <!-- position parameter is deprecated, category anyway will be positioned in the end of list + and you can not set position directly, use catalog_category.move instead --> + <element name="available_sort_by" type="typens:ArrayOfString" minOccurs="0"/> + <element name="custom_design" type="xsd:string" minOccurs="0"/> + <element name="custom_design_apply" type="xsd:int" minOccurs="0"/> + <element name="custom_design_from" type="xsd:string" minOccurs="0"/> + <element name="custom_design_to" type="xsd:string" minOccurs="0"/> + <element name="custom_layout_update" type="xsd:string" minOccurs="0"/> + <element name="default_sort_by" type="xsd:string" minOccurs="0"/> + <element name="description" type="xsd:string" minOccurs="0"/> + <element name="display_mode" type="xsd:string" minOccurs="0"/> + <element name="is_anchor" type="xsd:int" minOccurs="0"/> + <element name="landing_page" type="xsd:int" minOccurs="0"/> + <element name="meta_description" type="xsd:string" minOccurs="0"/> + <element name="meta_keywords" type="xsd:string" minOccurs="0"/> + <element name="meta_title" type="xsd:string" minOccurs="0"/> + <element name="page_layout" type="xsd:string" minOccurs="0"/> + <element name="url_key" type="xsd:string" minOccurs="0"/> + <element name="include_in_menu" type="xsd:int" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogCategoryInfo"> + <all> + <element name="category_id" type="xsd:string"/> + <element name="is_active" type="xsd:int"/> + <element name="position" type="xsd:string"/> + <element name="level" type="xsd:string"/> + <element name="parent_id" type="xsd:string"/> + <element name="all_children" type="xsd:string"/> + <element name="children" type="xsd:string"/> + <element name="created_at" type="xsd:string" minOccurs="0"/> + <element name="updated_at" type="xsd:string" minOccurs="0"/> + <element name="name" type="xsd:string" minOccurs="0"/> + <element name="url_key" type="xsd:string" minOccurs="0"/> + <element name="description" type="xsd:string" minOccurs="0"/> + <element name="meta_title" type="xsd:string" minOccurs="0"/> + <element name="meta_keywords" type="xsd:string" minOccurs="0"/> + <element name="meta_description" type="xsd:string" minOccurs="0"/> + <element name="path" type="xsd:string" minOccurs="0"/> + <element name="url_path" type="xsd:string" minOccurs="0"/> + <element name="children_count" type="xsd:int" minOccurs="0"/> + <element name="display_mode" type="xsd:string" minOccurs="0"/> + <element name="is_anchor" type="xsd:int" minOccurs="0"/> + <element name="available_sort_by" type="typens:ArrayOfString" minOccurs="0"/> + <element name="custom_design" type="xsd:string" minOccurs="0"/> + <element name="custom_design_apply" type="xsd:string" minOccurs="0"/> + <element name="custom_design_from" type="xsd:string" minOccurs="0"/> + <element name="custom_design_to" type="xsd:string" minOccurs="0"/> + <element name="page_layout" type="xsd:string" minOccurs="0"/> + <element name="custom_layout_update" type="xsd:string" minOccurs="0"/> + <element name="default_sort_by" type="xsd:string" minOccurs="0"/> + <element name="landing_page" type="xsd:int" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogAssignedProduct"> + <all> + <element name="product_id" type="xsd:int"/> + <element name="type" type="xsd:string"/> + <element name="set" type="xsd:int"/> + <element name="sku" type="xsd:string"/> + <element name="position" type="xsd:int"/> + </all> + </complexType> + <complexType name="catalogAssignedProductArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogAssignedProduct[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogAttributeEntity"> + <all> + <element name="attribute_id" type="xsd:int" minOccurs="0"/> + <element name="code" type="xsd:string" minOccurs="0"/> + <element name="type" type="xsd:string" minOccurs="0"/> + <element name="required" type="xsd:string" minOccurs="0"/> + <element name="scope" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogAttributeEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogAttributeEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogAttributeOptionEntity"> + <all> + <element name="label" type="xsd:string"/> + <element name="value" type="xsd:string"/> + </all> + </complexType> + <complexType name="catalogAttributeOptionEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogAttributeOptionEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductImageEntity"> + <all> + <element name="file" type="xsd:string"/> + <element name="label" type="xsd:string"/> + <element name="position" type="xsd:string"/> + <element name="exclude" type="xsd:string"/> + <element name="url" type="xsd:string"/> + <element name="types" type="typens:ArrayOfString"/> + </all> + </complexType> + <complexType name="catalogProductImageEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductImageEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductAttributeMediaTypeEntity"> + <all> + <element name="code" type="xsd:string"/> + <element name="scope" type="xsd:string"/> + </all> + </complexType> + <complexType name="catalogProductAttributeMediaTypeEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" + wsdl:arrayType="typens:catalogProductAttributeMediaTypeEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductImageFileEntity"> + <all> + <element name="content" type="xsd:string"/> + <element name="mime" type="xsd:string"/> + <element name="name" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductAttributeMediaCreateEntity"> + <all> + <element name="file" type="typens:catalogProductImageFileEntity" minOccurs="0"/> + <element name="label" type="xsd:string" minOccurs="0"/> + <element name="position" type="xsd:string" minOccurs="0"/> + <element name="types" type="typens:ArrayOfString" minOccurs="0"/> + <element name="exclude" type="xsd:string" minOccurs="0"/> + <element name="remove" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductLinkEntity"> + <all> + <element name="product_id" type="xsd:string" minOccurs="0"/> + <element name="type" type="xsd:string" minOccurs="0"/> + <element name="set" type="xsd:string" minOccurs="0"/> + <element name="sku" type="xsd:string" minOccurs="0"/> + <element name="position" type="xsd:string" minOccurs="0"/> + <element name="qty" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductLinkEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductLinkEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductLinkAttributeEntity"> + <all> + <element name="code" type="xsd:string" minOccurs="0"/> + <element name="type" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="catalogProductLinkAttributeEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductLinkAttributeEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductAttributeFrontendLabelEntity"> + <all> + <element name="store_id" type="xsd:string" /> + <element name="label" type="xsd:string" /> + </all> + </complexType> + <complexType name="catalogProductAttributeFrontendLabelArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductAttributeFrontendLabelEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductAttributeEntityToCreate"> + <all> + <element name="attribute_code" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="frontend_input" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="scope" type="xsd:string" minOccurs="0" /> + <element name="default_value" type="xsd:string" minOccurs="0" /> + <element name="is_unique" type="xsd:int" minOccurs="0" /> + <element name="is_required" type="xsd:int" minOccurs="0" /> + <element name="apply_to" type="typens:ArrayOfString" minOccurs="0" /> + <element name="is_configurable" type="xsd:int" minOccurs="0" /> + <element name="is_searchable" type="xsd:int" minOccurs="0" /> + <element name="is_visible_in_advanced_search" type="xsd:int" minOccurs="0" /> + <element name="is_comparable" type="xsd:int" minOccurs="0" /> + <element name="is_used_for_promo_rules" type="xsd:int" minOccurs="0" /> + <element name="is_visible_on_front" type="xsd:int" minOccurs="0" /> + <element name="used_in_product_listing" type="xsd:int" minOccurs="0" /> + <element name="additional_fields" type="typens:associativeArray" minOccurs="0"/> + <element name="frontend_label" type="typens:catalogProductAttributeFrontendLabelArray" minOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductAttributeEntityToUpdate"> + <all> + <element name="scope" type="xsd:string" minOccurs="0" /> + <element name="default_value" type="xsd:string" minOccurs="0" /> + <element name="is_unique" type="xsd:int" minOccurs="0" /> + <element name="is_required" type="xsd:int" minOccurs="0" /> + <element name="apply_to" type="typens:ArrayOfString" minOccurs="0" /> + <element name="is_configurable" type="xsd:int" minOccurs="0" /> + <element name="is_searchable" type="xsd:int" minOccurs="0" /> + <element name="is_visible_in_advanced_search" type="xsd:int" minOccurs="0" /> + <element name="is_comparable" type="xsd:int" minOccurs="0" /> + <element name="is_used_for_promo_rules" type="xsd:int" minOccurs="0" /> + <element name="is_visible_on_front" type="xsd:int" minOccurs="0" /> + <element name="used_in_product_listing" type="xsd:int" minOccurs="0" /> + <element name="additional_fields" type="typens:associativeArray" minOccurs="0"/> + <element name="frontend_label" type="typens:catalogProductAttributeFrontendLabelArray" minOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductAttributeEntity"> + <all> + <element name="attribute_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="attribute_code" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="frontend_input" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="scope" type="xsd:string" minOccurs="0" /> + <element name="default_value" type="xsd:string" minOccurs="0" /> + <element name="is_unique" type="xsd:int" minOccurs="0" /> + <element name="is_required" type="xsd:int" minOccurs="0" /> + <element name="apply_to" type="typens:ArrayOfString" minOccurs="0" /> + <element name="is_configurable" type="xsd:int" minOccurs="0" /> + <element name="is_searchable" type="xsd:int" minOccurs="0" /> + <element name="is_visible_in_advanced_search" type="xsd:int" minOccurs="0" /> + <element name="is_comparable" type="xsd:int" minOccurs="0" /> + <element name="is_used_for_promo_rules" type="xsd:int" minOccurs="0" /> + <element name="is_visible_on_front" type="xsd:int" minOccurs="0" /> + <element name="used_in_product_listing" type="xsd:int" minOccurs="0" /> + <element name="additional_fields" type="typens:associativeArray" minOccurs="0"/> + <element name="options" type="typens:catalogAttributeOptionEntityArray" minOccurs="0"/> + <element name="frontend_label" type="typens:catalogProductAttributeFrontendLabelArray" minOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductAttributeOptionLabelEntity"> + <all> + <element name="store_id" type="typens:ArrayOfString" /> + <element name="value" type="xsd:string" /> + </all> + </complexType> + <complexType name="catalogProductAttributeOptionLabelArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductAttributeOptionLabelEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductAttributeOptionEntityToAdd"> + <all> + <element name="label" type="typens:catalogProductAttributeOptionLabelArray" /> + <element name="order" type="xsd:int" /> + <element name="is_default" type="xsd:int" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionAdditionalFieldsEntity"> + <all> + <element name="title" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="price_type" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="sku" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="max_characters" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="file_extension" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="image_size_x" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="image_size_y" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="value_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionAdditionalFieldsArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductCustomOptionAdditionalFieldsEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductCustomOptionToAdd"> + <all> + <element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="is_require" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <element name="additional_fields" type="typens:catalogProductCustomOptionAdditionalFieldsArray" minOccurs="1" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionToUpdate"> + <all> + <element name="title" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="type" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <element name="is_require" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <element name="additional_fields" type="typens:catalogProductCustomOptionAdditionalFieldsArray" minOccurs="0" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionInfoEntity"> + <all> + <element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="is_require" type="xsd:int" minOccurs="1" maxOccurs="1" /> + <element name="additional_fields" type="typens:catalogProductCustomOptionAdditionalFieldsArray" minOccurs="1" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionListEntity"> + <all> + <element name="option_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="is_require" type="xsd:int" minOccurs="1" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionListArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductCustomOptionListEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductCustomOptionTypesEntity"> + <all> + <element name="label" type="xsd:string"/> + <element name="value" type="xsd:string"/> + </all> + </complexType> + <complexType name="catalogProductCustomOptionTypesArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductCustomOptionTypesEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductCustomOptionValueInfoEntity"> + <all> + <element name="value_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="option_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="default_price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="default_price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="store_price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="store_price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="default_title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="store_title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionValueListEntity"> + <all> + <element name="value_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionValueListArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductCustomOptionValueListEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductCustomOptionValueAddEntity"> + <all> + <element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductCustomOptionValueAddArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductCustomOptionValueAddEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductCustomOptionValueUpdateEntity"> + <all> + <element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + </all> + </complexType> + </schema> + </types> + <message name="catalogProductCurrentStoreRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogProductCurrentStoreResponse"> + <part name="storeView" type="xsd:int"/> + </message> + <message name="catalogProductListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="filters" type="typens:filters"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogProductListResponse"> + <part name="storeView" type="typens:catalogProductEntityArray"/> + </message> + <message name="catalogProductInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + <part name="attributes" type="typens:catalogProductRequestAttributes"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductInfoResponse"> + <part name="info" type="typens:catalogProductReturnEntity"/> + </message> + <message name="catalogProductCreateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="type" type="xsd:string"/> + <part name="set" type="xsd:string"/> + <part name="sku" type="xsd:string"/> + <part name="productData" type="typens:catalogProductCreateEntity"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogProductCreateResponse"> + <part name="result" type="xsd:int"/> + </message> + <message name="catalogProductUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="productData" type="typens:catalogProductCreateEntity"/> + <part name="storeView" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductUpdateResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductSetSpecialPriceRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="specialPrice" type="xsd:string"/> + <part name="fromDate" type="xsd:string"/> + <part name="toDate" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductSetSpecialPriceResponse"> + <part name="result" type="xsd:int"/> + </message> + <message name="catalogProductGetSpecialPriceRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductGetSpecialPriceResponse"> + <part name="result" type="typens:catalogProductReturnEntity"/> + </message> + <message name="catalogProductDeleteRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductDeleteResponse"> + <part name="result" type="xsd:int"/> + </message> + <message name="catalogProductAttributeCurrentStoreRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogProductAttributeCurrentStoreResponse"> + <part name="storeView" type="xsd:int"/> + </message> + <message name="catalogProductListOfAdditionalAttributesRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="productType" type="xsd:string" /> + <part name="attributeSetId" type="xsd:string" /> + </message> + <message name="catalogProductListOfAdditionalAttributesResponse"> + <part name="result" type="typens:catalogAttributeEntityArray" /> + </message> + <message name="catalogProductAttributeListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="setId" type="xsd:int"/> + </message> + <message name="catalogProductAttributeListResponse"> + <part name="result" type="typens:catalogAttributeEntityArray"/> + </message> + <message name="catalogProductAttributeOptionsRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attributeId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogProductAttributeOptionsResponse"> + <part name="result" type="typens:catalogAttributeOptionEntityArray"/> + </message> + <message name="catalogProductAttributeSetCreateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attributeSetName" type="xsd:string"/> + <part name="skeletonSetId" type="xsd:string"/> + </message> + <message name="catalogProductAttributeSetCreateResponse"> + <part name="setId" type="xsd:int"/> + </message> + <message name="catalogProductAttributeSetRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attributeSetId" type="xsd:string"/> + <part name="forceProductsRemove" type="xsd:string"/> + </message> + <message name="catalogProductAttributeSetRemoveResponse"> + <part name="isRemoved" type="xsd:boolean"/> + </message> + <message name="catalogProductAttributeSetListRequest"> + <part name="sessionId" type="xsd:string"/> + </message> + <message name="catalogProductAttributeSetListResponse"> + <part name="result" type="typens:catalogProductAttributeSetEntityArray"/> + </message> + <message name="catalogProductAttributeSetAttributeAddRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="attributeId" type="xsd:string" /> + <part name="attributeSetId" type="xsd:string" /> + <part name="attributeGroupId" type="xsd:string"/> + <part name="sortOrder" type="xsd:string" /> + </message> + <message name="catalogProductAttributeSetAttributeAddResponse"> + <part name="isAdded" type="xsd:boolean" /> + </message> + <message name="catalogProductAttributeSetAttributeRemoveRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="attributeId" type="xsd:string" /> + <part name="attributeSetId" type="xsd:string" /> + </message> + <message name="catalogProductAttributeSetAttributeRemoveResponse"> + <part name="isRemoved" type="xsd:boolean" /> + </message> + <message name="catalogProductAttributeSetGroupAddRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="attributeSetId" type="xsd:string" /> + <part name="groupName" type="xsd:string" /> + </message> + <message name="catalogProductAttributeSetGroupAddResponse"> + <part name="result" type="xsd:int" /> + </message> + <message name="catalogProductAttributeSetGroupRenameRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="groupId" type="xsd:string" /> + <part name="groupName" type="xsd:string" /> + </message> + <message name="catalogProductAttributeSetGroupRenameResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="catalogProductAttributeSetGroupRemoveRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="attributeGroupId" type="xsd:string" /> + </message> + <message name="catalogProductAttributeSetGroupRemoveResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="catalogProductAttributeTypesRequest"> + <part name="sessionId" type="xsd:string"/> + </message> + <message name="catalogProductAttributeTypesResponse"> + <part name="result" type="typens:catalogAttributeOptionEntityArray" /> + </message> + <message name="catalogProductAttributeCreateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="data" type="typens:catalogProductAttributeEntityToCreate"/> + </message> + <message name="catalogProductAttributeCreateResponse"> + <part name="result" type="xsd:int" /> + </message> + <message name="catalogProductAttributeRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attribute" type="xsd:string"/> + </message> + <message name="catalogProductAttributeRemoveResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="catalogProductAttributeInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attribute" type="xsd:string"/> + </message> + <message name="catalogProductAttributeInfoResponse"> + <part name="result" type="typens:catalogProductAttributeEntity" /> + </message> + <message name="catalogProductAttributeUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attribute" type="xsd:string"/> + <part name="data" type="typens:catalogProductAttributeEntityToUpdate"/> + </message> + <message name="catalogProductAttributeUpdateResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="catalogProductAttributeAddOptionRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attribute" type="xsd:string"/> + <part name="data" type="typens:catalogProductAttributeOptionEntityToAdd"/> + </message> + <message name="catalogProductAttributeAddOptionResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="catalogProductAttributeRemoveOptionRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attribute" type="xsd:string"/> + <part name="optionId" type="xsd:string"/> + </message> + <message name="catalogProductAttributeRemoveOptionResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="catalogProductTypeListRequest"> + <part name="sessionId" type="xsd:string"/> + </message> + <message name="catalogProductTypeListResponse"> + <part name="result" type="typens:catalogProductTypeEntityArray"/> + </message> + <message name="catalogProductAttributeTierPriceInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductAttributeTierPriceInfoResponse"> + <part name="result" type="typens:catalogProductTierPriceEntityArray"/> + </message> + <message name="catalogProductAttributeTierPriceUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="tier_price" type="typens:catalogProductTierPriceEntityArray"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductAttributeTierPriceUpdateResponse"> + <part name="result" type="xsd:int"/> + </message> + <message name="catalogProductAttributeMediaCurrentStoreRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaCurrentStoreResponse"> + <part name="storeView" type="xsd:int"/> + </message> + <message name="catalogProductAttributeMediaListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaListResponse"> + <part name="result" type="typens:catalogProductImageEntityArray"/> + </message> + <message name="catalogProductAttributeMediaInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="file" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaInfoResponse"> + <part name="result" type="typens:catalogProductImageEntity"/> + </message> + <message name="catalogProductAttributeMediaTypesRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="setId" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaTypesResponse"> + <part name="result" type="typens:catalogProductAttributeMediaTypeEntityArray"/> + </message> + <message name="catalogProductAttributeMediaCreateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="data" type="typens:catalogProductAttributeMediaCreateEntity"/> + <part name="storeView" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaCreateResponse"> + <part name="result" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="file" type="xsd:string"/> + <part name="data" type="typens:catalogProductAttributeMediaCreateEntity"/> + <part name="storeView" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaUpdateResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductAttributeMediaRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="file" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductAttributeMediaRemoveResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductLinkListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="type" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductLinkListResponse"> + <part name="result" type="typens:catalogProductLinkEntityArray"/> + </message> + <message name="catalogProductLinkAssignRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="type" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="linkedProduct" type="xsd:string"/> + <part name="data" type="typens:catalogProductLinkEntity"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductLinkAssignResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductLinkUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="type" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="linkedProduct" type="xsd:string"/> + <part name="data" type="typens:catalogProductLinkEntity"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductLinkUpdateResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductLinkRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="type" type="xsd:string"/> + <part name="product" type="xsd:string"/> + <part name="linkedProduct" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogProductLinkRemoveResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductLinkTypesRequest"> + <part name="sessionId" type="xsd:string"/> + </message> + <message name="catalogProductLinkTypesResponse"> + <part name="result" type="typens:ArrayOfString"/> + </message> + <message name="catalogProductLinkAttributesRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="type" type="xsd:string"/> + </message> + <message name="catalogProductLinkAttributesResponse"> + <part name="result" type="typens:catalogProductLinkAttributeEntityArray"/> + </message> + <message name="catalogCategoryCurrentStoreRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogCategoryCurrentStoreResponse"> + <part name="storeView" type="xsd:int"/> + </message> + <message name="catalogProductCustomOptionAddRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="productId" type="xsd:string"/> + <part name="data" type="typens:catalogProductCustomOptionToAdd"/> + <part name="store" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionAddResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductCustomOptionUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="optionId" type="xsd:string"/> + <part name="data" type="typens:catalogProductCustomOptionToUpdate"/> + <part name="store" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionUpdateResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductCustomOptionListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="productId" type="xsd:string"/> + <part name="store" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionListResponse"> + <part name="result" type="typens:catalogProductCustomOptionListArray"/> + </message> + <message name="catalogProductCustomOptionTypesRequest"> + <part name="sessionId" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionTypesResponse"> + <part name="result" type="typens:catalogProductCustomOptionTypesArray"/> + </message> + <message name="catalogProductCustomOptionInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="optionId" type="xsd:string"/> + <part name="store" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionInfoResponse"> + <part name="result" type="typens:catalogProductCustomOptionInfoEntity"/> + </message> + <message name="catalogProductCustomOptionRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="optionId" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionRemoveResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductCustomOptionValueListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="optionId" type="xsd:string"/> + <part name="store" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionValueListResponse"> + <part name="result" type="typens:catalogProductCustomOptionValueListArray"/> + </message> + <message name="catalogProductCustomOptionValueInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="valueId" type="xsd:string"/> + <part name="store" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionValueInfoResponse"> + <part name="result" type="typens:catalogProductCustomOptionValueInfoEntity"/> + </message> + <message name="catalogProductCustomOptionValueAddRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="optionId" type="xsd:string"/> + <part name="data" type="typens:catalogProductCustomOptionValueAddArray"/> + <part name="store" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionValueAddResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductCustomOptionValueUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="valueId" type="xsd:string"/> + <part name="data" type="typens:catalogProductCustomOptionValueUpdateEntity"/> + <part name="storeId" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionValueUpdateResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogProductCustomOptionValueRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="valueId" type="xsd:string"/> + </message> + <message name="catalogProductCustomOptionValueRemoveResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogCategoryTreeRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="parentId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogCategoryTreeResponse"> + <part name="tree" type="typens:catalogCategoryTree"/> + </message> + <message name="catalogCategoryLevelRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="website" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + <part name="parentCategory" type="xsd:string"/> + </message> + <message name="catalogCategoryLevelResponse"> + <part name="tree" type="typens:ArrayOfCatalogCategoryEntitiesNoChildren"/> + </message> + <message name="catalogCategoryInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + <part name="storeView" type="xsd:string"/> + <part name="attributes" type="typens:ArrayOfString"/> + </message> + <message name="catalogCategoryInfoResponse"> + <part name="info" type="typens:catalogCategoryInfo"/> + </message> + <message name="catalogCategoryCreateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="parentId" type="xsd:int"/> + <part name="categoryData" type="typens:catalogCategoryEntityCreate"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogCategoryCreateResponse"> + <part name="attribute_id" type="xsd:int"/> + </message> + <message name="catalogCategoryUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + <part name="categoryData" type="typens:catalogCategoryEntityCreate"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogCategoryUpdateResponse"> + <part name="id" type="xsd:boolean"/> + </message> + <message name="catalogCategoryMoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + <part name="parentId" type="xsd:int"/> + <part name="afterId" type="xsd:string"/> + </message> + <message name="catalogCategoryMoveResponse"> + <part name="id" type="xsd:boolean"/> + </message> + <message name="catalogCategoryDeleteRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + </message> + <message name="catalogCategoryDeleteResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogCategoryAssignedProductsRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + </message> + <message name="catalogCategoryAssignedProductsResponse"> + <part name="result" type="typens:catalogAssignedProductArray"/> + </message> + <message name="catalogCategoryAssignProductRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + <part name="product" type="xsd:string"/> + <part name="position" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogCategoryAssignProductResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogCategoryUpdateProductRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + <part name="product" type="xsd:string"/> + <part name="position" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogCategoryUpdateProductResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogCategoryRemoveProductRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="categoryId" type="xsd:int"/> + <part name="product" type="xsd:string"/> + <part name="productIdentifierType" type="xsd:string"/> + </message> + <message name="catalogCategoryRemoveProductResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="catalogCategoryAttributeCurrentStoreRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogCategoryAttributeCurrentStoreResponse"> + <part name="storeView" type="xsd:int"/> + </message> + <message name="catalogCategoryAttributeListRequest"> + <part name="sessionId" type="xsd:string"/> + </message> + <message name="catalogCategoryAttributeListResponse"> + <part name="result" type="typens:catalogAttributeEntityArray"/> + </message> + <message name="catalogCategoryAttributeOptionsRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="attributeId" type="xsd:string"/> + <part name="storeView" type="xsd:string"/> + </message> + <message name="catalogCategoryAttributeOptionsResponse"> + <part name="result" type="typens:catalogAttributeOptionEntityArray"/> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogCategoryCurrentStore"> + <documentation>Set_Get current store view</documentation> + <input message="typens:catalogCategoryCurrentStoreRequest"/> + <output message="typens:catalogCategoryCurrentStoreResponse"/> + </operation> + <operation name="catalogCategoryTree"> + <documentation>Retrieve hierarchical tree of categories.</documentation> + <input message="typens:catalogCategoryTreeRequest"/> + <output message="typens:catalogCategoryTreeResponse"/> + </operation> + <operation name="catalogCategoryLevel"> + <documentation>Retrieve hierarchical tree of categories.</documentation> + <input message="typens:catalogCategoryLevelRequest"/> + <output message="typens:catalogCategoryLevelResponse"/> + </operation> + <operation name="catalogCategoryInfo"> + <documentation>Retrieve hierarchical tree of categories.</documentation> + <input message="typens:catalogCategoryInfoRequest"/> + <output message="typens:catalogCategoryInfoResponse"/> + </operation> + <operation name="catalogCategoryCreate"> + <documentation>Create new category and return its id.</documentation> + <input message="typens:catalogCategoryCreateRequest"/> + <output message="typens:catalogCategoryCreateResponse"/> + </operation> + <operation name="catalogCategoryUpdate"> + <documentation>Update category</documentation> + <input message="typens:catalogCategoryUpdateRequest"/> + <output message="typens:catalogCategoryUpdateResponse"/> + </operation> + <operation name="catalogCategoryMove"> + <documentation>Move category in tree</documentation> + <input message="typens:catalogCategoryMoveRequest"/> + <output message="typens:catalogCategoryMoveResponse"/> + </operation> + <operation name="catalogCategoryDelete"> + <documentation>Delete category</documentation> + <input message="typens:catalogCategoryDeleteRequest"/> + <output message="typens:catalogCategoryDeleteResponse"/> + </operation> + <operation name="catalogCategoryAssignedProducts"> + <documentation>Retrieve list of assigned products</documentation> + <input message="typens:catalogCategoryAssignedProductsRequest"/> + <output message="typens:catalogCategoryAssignedProductsResponse"/> + </operation> + <operation name="catalogCategoryAssignProduct"> + <documentation>Assign product to category</documentation> + <input message="typens:catalogCategoryAssignProductRequest"/> + <output message="typens:catalogCategoryAssignProductResponse"/> + </operation> + <operation name="catalogCategoryUpdateProduct"> + <documentation>Update assigned product</documentation> + <input message="typens:catalogCategoryUpdateProductRequest"/> + <output message="typens:catalogCategoryUpdateProductResponse"/> + </operation> + <operation name="catalogCategoryRemoveProduct"> + <documentation>Remove product assignment from category</documentation> + <input message="typens:catalogCategoryRemoveProductRequest"/> + <output message="typens:catalogCategoryRemoveProductResponse"/> + </operation> + <operation name="catalogCategoryAttributeCurrentStore"> + <documentation>Set/Get current store view</documentation> + <input message="typens:catalogCategoryAttributeCurrentStoreRequest"/> + <output message="typens:catalogCategoryAttributeCurrentStoreResponse"/> + </operation> + <operation name="catalogCategoryAttributeList"> + <documentation>Retrieve category attributes</documentation> + <input message="typens:catalogCategoryAttributeListRequest"/> + <output message="typens:catalogCategoryAttributeListResponse"/> + </operation> + <operation name="catalogCategoryAttributeOptions"> + <documentation>Retrieve attribute options</documentation> + <input message="typens:catalogCategoryAttributeOptionsRequest"/> + <output message="typens:catalogCategoryAttributeOptionsResponse"/> + </operation> + <operation name="catalogProductCurrentStore"> + <documentation>Set/Get current store view</documentation> + <input message="typens:catalogProductCurrentStoreRequest"/> + <output message="typens:catalogProductCurrentStoreResponse"/> + </operation> + <operation name="catalogProductList"> + <documentation>Retrieve products list by filters</documentation> + <input message="typens:catalogProductListRequest"/> + <output message="typens:catalogProductListResponse"/> + </operation> + <operation name="catalogProductInfo"> + <documentation>Retrieve product</documentation> + <input message="typens:catalogProductInfoRequest"/> + <output message="typens:catalogProductInfoResponse"/> + </operation> + <operation name="catalogProductCreate"> + <documentation>Create new product and return product id</documentation> + <input message="typens:catalogProductCreateRequest"/> + <output message="typens:catalogProductCreateResponse"/> + </operation> + <operation name="catalogProductUpdate"> + <documentation>Update product</documentation> + <input message="typens:catalogProductUpdateRequest"/> + <output message="typens:catalogProductUpdateResponse"/> + </operation> + <operation name="catalogProductSetSpecialPrice"> + <documentation>Update product special price</documentation> + <input message="typens:catalogProductSetSpecialPriceRequest"/> + <output message="typens:catalogProductSetSpecialPriceResponse"/> + </operation> + <operation name="catalogProductGetSpecialPrice"> + <documentation>Get product special price data</documentation> + <input message="typens:catalogProductGetSpecialPriceRequest"/> + <output message="typens:catalogProductGetSpecialPriceResponse"/> + </operation> + <operation name="catalogProductDelete"> + <documentation>Delete product</documentation> + <input message="typens:catalogProductDeleteRequest"/> + <output message="typens:catalogProductDeleteResponse"/> + </operation> + <operation name="catalogProductAttributeCurrentStore"> + <documentation>Set/Get current store view</documentation> + <input message="typens:catalogProductAttributeCurrentStoreRequest"/> + <output message="typens:catalogProductAttributeCurrentStoreResponse"/> + </operation> + <operation name="catalogProductListOfAdditionalAttributes"> + <documentation>Get list of additional attributes which are not in default create/update list</documentation> + <input message="typens:catalogProductListOfAdditionalAttributesRequest"/> + <output message="typens:catalogProductListOfAdditionalAttributesResponse"/> + </operation> + <operation name="catalogProductAttributeList"> + <documentation>Retrieve attribute list</documentation> + <input message="typens:catalogProductAttributeListRequest"/> + <output message="typens:catalogProductAttributeListResponse"/> + </operation> + <operation name="catalogProductAttributeOptions"> + <documentation>Retrieve attribute options</documentation> + <input message="typens:catalogProductAttributeOptionsRequest"/> + <output message="typens:catalogProductAttributeOptionsResponse"/> + </operation> + <operation name="catalogProductAttributeSetCreate"> + <documentation>Create product attribute set based on another set</documentation> + <input message="typens:catalogProductAttributeSetCreateRequest"/> + <output message="typens:catalogProductAttributeSetCreateResponse"/> + </operation> + <operation name="catalogProductAttributeSetRemove"> + <documentation>Remove product attribute set</documentation> + <input message="typens:catalogProductAttributeSetRemoveRequest"/> + <output message="typens:catalogProductAttributeSetRemoveResponse"/> + </operation> + <operation name="catalogProductAttributeSetList"> + <documentation>Retrieve product attribute sets</documentation> + <input message="typens:catalogProductAttributeSetListRequest"/> + <output message="typens:catalogProductAttributeSetListResponse"/> + </operation> + <operation name="catalogProductAttributeSetAttributeAdd"> + <documentation>Add attribute into attribute set</documentation> + <input message="typens:catalogProductAttributeSetAttributeAddRequest"/> + <output message="typens:catalogProductAttributeSetAttributeAddResponse"/> + </operation> + <operation name="catalogProductAttributeSetAttributeRemove"> + <documentation>Remove attribute from attribute set</documentation> + <input message="typens:catalogProductAttributeSetAttributeRemoveRequest"/> + <output message="typens:catalogProductAttributeSetAttributeRemoveResponse"/> + </operation> + <operation name="catalogProductAttributeSetGroupAdd"> + <documentation>Create group within existing attribute set</documentation> + <input message="typens:catalogProductAttributeSetGroupAddRequest"/> + <output message="typens:catalogProductAttributeSetGroupAddResponse"/> + </operation> + <operation name="catalogProductAttributeSetGroupRename"> + <documentation>Rename existing group</documentation> + <input message="typens:catalogProductAttributeSetGroupRenameRequest"/> + <output message="typens:catalogProductAttributeSetGroupRenameResponse"/> + </operation> + <operation name="catalogProductAttributeSetGroupRemove"> + <documentation>Remove group from attribute set</documentation> + <input message="typens:catalogProductAttributeSetGroupRemoveRequest"/> + <output message="typens:catalogProductAttributeSetGroupRemoveResponse"/> + </operation> + <operation name="catalogProductAttributeTypes"> + <documentation>Get list of possible attribute types</documentation> + <input message="typens:catalogProductAttributeTypesRequest"/> + <output message="typens:catalogProductAttributeTypesResponse"/> + </operation> + <operation name="catalogProductAttributeCreate"> + <documentation>Create new attribute</documentation> + <input message="typens:catalogProductAttributeCreateRequest"/> + <output message="typens:catalogProductAttributeCreateResponse"/> + </operation> + <operation name="catalogProductAttributeRemove"> + <documentation>Delete attribute</documentation> + <input message="typens:catalogProductAttributeRemoveRequest"/> + <output message="typens:catalogProductAttributeRemoveResponse"/> + </operation> + <operation name="catalogProductAttributeInfo"> + <documentation>Get full information about attribute with list of options</documentation> + <input message="typens:catalogProductAttributeInfoRequest"/> + <output message="typens:catalogProductAttributeInfoResponse"/> + </operation> + <operation name="catalogProductAttributeUpdate"> + <documentation>Update attribute</documentation> + <input message="typens:catalogProductAttributeUpdateRequest"/> + <output message="typens:catalogProductAttributeUpdateResponse"/> + </operation> + <operation name="catalogProductAttributeAddOption"> + <documentation>Add option to attribute</documentation> + <input message="typens:catalogProductAttributeAddOptionRequest"/> + <output message="typens:catalogProductAttributeAddOptionResponse"/> + </operation> + <operation name="catalogProductAttributeRemoveOption"> + <documentation>Remove option from attribute</documentation> + <input message="typens:catalogProductAttributeRemoveOptionRequest"/> + <output message="typens:catalogProductAttributeRemoveOptionResponse"/> + </operation> + <operation name="catalogProductTypeList"> + <documentation>Retrieve product types</documentation> + <input message="typens:catalogProductTypeListRequest"/> + <output message="typens:catalogProductTypeListResponse"/> + </operation> + <operation name="catalogProductAttributeTierPriceInfo"> + <documentation>Retrieve product tier prices</documentation> + <input message="typens:catalogProductAttributeTierPriceInfoRequest"/> + <output message="typens:catalogProductAttributeTierPriceInfoResponse"/> + </operation> + <operation name="catalogProductAttributeTierPriceUpdate"> + <documentation>Update product tier prices</documentation> + <input message="typens:catalogProductAttributeTierPriceUpdateRequest"/> + <output message="typens:catalogProductAttributeTierPriceUpdateResponse"/> + </operation> + <operation name="catalogProductAttributeMediaCurrentStore"> + <documentation>Set/Get current store view</documentation> + <input message="typens:catalogProductAttributeMediaCurrentStoreRequest"/> + <output message="typens:catalogProductAttributeMediaCurrentStoreResponse"/> + </operation> + <operation name="catalogProductAttributeMediaList"> + <documentation>Retrieve product image list</documentation> + <input message="typens:catalogProductAttributeMediaListRequest"/> + <output message="typens:catalogProductAttributeMediaListResponse"/> + </operation> + <operation name="catalogProductAttributeMediaInfo"> + <documentation>Retrieve product image data</documentation> + <input message="typens:catalogProductAttributeMediaInfoRequest"/> + <output message="typens:catalogProductAttributeMediaInfoResponse"/> + </operation> + <operation name="catalogProductAttributeMediaTypes"> + <documentation>Retrieve product image types</documentation> + <input message="typens:catalogProductAttributeMediaTypesRequest"/> + <output message="typens:catalogProductAttributeMediaTypesResponse"/> + </operation> + <operation name="catalogProductAttributeMediaCreate"> + <documentation>Upload new product image</documentation> + <input message="typens:catalogProductAttributeMediaCreateRequest"/> + <output message="typens:catalogProductAttributeMediaCreateResponse"/> + </operation> + <operation name="catalogProductAttributeMediaUpdate"> + <documentation>Update product image</documentation> + <input message="typens:catalogProductAttributeMediaUpdateRequest"/> + <output message="typens:catalogProductAttributeMediaUpdateResponse"/> + </operation> + <operation name="catalogProductAttributeMediaRemove"> + <documentation>Remove product image</documentation> + <input message="typens:catalogProductAttributeMediaRemoveRequest"/> + <output message="typens:catalogProductAttributeMediaRemoveResponse"/> + </operation> + <operation name="catalogProductLinkList"> + <documentation>Retrieve linked products</documentation> + <input message="typens:catalogProductLinkListRequest"/> + <output message="typens:catalogProductLinkListResponse"/> + </operation> + <operation name="catalogProductLinkAssign"> + <documentation>Assign product link</documentation> + <input message="typens:catalogProductLinkAssignRequest"/> + <output message="typens:catalogProductLinkAssignResponse"/> + </operation> + <operation name="catalogProductLinkUpdate"> + <documentation>Update product link</documentation> + <input message="typens:catalogProductLinkUpdateRequest"/> + <output message="typens:catalogProductLinkUpdateResponse"/> + </operation> + <operation name="catalogProductLinkRemove"> + <documentation>Remove product link</documentation> + <input message="typens:catalogProductLinkRemoveRequest"/> + <output message="typens:catalogProductLinkRemoveResponse"/> + </operation> + <operation name="catalogProductLinkTypes"> + <documentation>Retrieve product link types</documentation> + <input message="typens:catalogProductLinkTypesRequest"/> + <output message="typens:catalogProductLinkTypesResponse"/> + </operation> + <operation name="catalogProductLinkAttributes"> + <documentation>Retrieve product link type attributes</documentation> + <input message="typens:catalogProductLinkAttributesRequest"/> + <output message="typens:catalogProductLinkAttributesResponse"/> + </operation> + <operation name="catalogProductCustomOptionAdd"> + <documentation>Add new custom option into product</documentation> + <input message="typens:catalogProductCustomOptionAddRequest"/> + <output message="typens:catalogProductCustomOptionAddResponse"/> + </operation> + <operation name="catalogProductCustomOptionUpdate"> + <documentation>Update product custom option</documentation> + <input message="typens:catalogProductCustomOptionUpdateRequest"/> + <output message="typens:catalogProductCustomOptionUpdateResponse"/> + </operation> + <operation name="catalogProductCustomOptionTypes"> + <documentation>Get list of available custom option types</documentation> + <input message="typens:catalogProductCustomOptionTypesRequest"/> + <output message="typens:catalogProductCustomOptionTypesResponse"/> + </operation> + <operation name="catalogProductCustomOptionInfo"> + <documentation>Get full information about custom option in product</documentation> + <input message="typens:catalogProductCustomOptionInfoRequest"/> + <output message="typens:catalogProductCustomOptionInfoResponse"/> + </operation> + <operation name="catalogProductCustomOptionList"> + <documentation>Retrieve list of product custom options</documentation> + <input message="typens:catalogProductCustomOptionListRequest"/> + <output message="typens:catalogProductCustomOptionListResponse"/> + </operation> + <operation name="catalogProductCustomOptionRemove"> + <documentation>Remove custom option</documentation> + <input message="typens:catalogProductCustomOptionRemoveRequest"/> + <output message="typens:catalogProductCustomOptionRemoveResponse"/> + </operation> + <operation name="catalogProductCustomOptionValueInfo"> + <documentation>Retrieve custom option value info</documentation> + <input message="typens:catalogProductCustomOptionValueInfoRequest"/> + <output message="typens:catalogProductCustomOptionValueInfoResponse"/> + </operation> + <operation name="catalogProductCustomOptionValueList"> + <documentation>Retrieve custom option values list</documentation> + <input message="typens:catalogProductCustomOptionValueListRequest"/> + <output message="typens:catalogProductCustomOptionValueListResponse"/> + </operation> + <operation name="catalogProductCustomOptionValueAdd"> + <documentation>Add new custom option values</documentation> + <input message="typens:catalogProductCustomOptionValueAddRequest"/> + <output message="typens:catalogProductCustomOptionValueAddResponse"/> + </operation> + <operation name="catalogProductCustomOptionValueUpdate"> + <documentation>Update custom option value</documentation> + <input message="typens:catalogProductCustomOptionValueUpdateRequest"/> + <output message="typens:catalogProductCustomOptionValueUpdateResponse"/> + </operation> + <operation name="catalogProductCustomOptionValueRemove"> + <documentation>Remove value from custom option</documentation> + <input message="typens:catalogProductCustomOptionValueRemoveRequest"/> + <output message="typens:catalogProductCustomOptionValueRemoveResponse"/> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + <operation name="catalogCategoryCurrentStore"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryTree"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryLevel"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryMove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryDelete"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryAssignedProducts"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryAssignProduct"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryUpdateProduct"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryRemoveProduct"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCurrentStore"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductListOfAdditionalAttributes"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductSetSpecialPrice"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductGetSpecialPrice"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductDelete"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeCurrentStore"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeOptions"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetAttributeAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetAttributeRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetGroupAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetGroupRename"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeSetGroupRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeTypes"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryAttributeCurrentStore"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeMediaCurrentStore"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeAddOption"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeRemoveOption"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductTypeList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeTierPriceInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeTierPriceUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryAttributeList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogCategoryAttributeOptions"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeMediaList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeMediaInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeMediaTypes"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeMediaCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeMediaUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductAttributeMediaRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductLinkList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductLinkAssign"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductLinkUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductLinkRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductLinkTypes"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductLinkAttributes"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionTypes"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionValueInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionValueList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionValueAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionValueUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionValueRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductCustomOptionRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}"/> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/Catalog/etc/wsi.xml b/app/code/core/Mage/Catalog/etc/wsi.xml new file mode 100644 index 00000000000..22ea67baa3d --- /dev/null +++ b/app/code/core/Mage/Catalog/etc/wsi.xml @@ -0,0 +1,2866 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="catalogProductEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductEntity"> + <xsd:sequence> + <xsd:element name="product_id" type="xsd:string" /> + <xsd:element name="sku" type="xsd:string" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="set" type="xsd:string" /> + <xsd:element name="type" type="xsd:string" /> + <xsd:element name="category_ids" type="typens:ArrayOfString" /> + <xsd:element name="website_ids" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductRequestAttributes"> + <xsd:sequence> + <xsd:element name="attributes" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="additional_attributes" type="typens:ArrayOfString" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductConfigurableAttributesEntity"> + <xsd:sequence> + <xsd:element name="attribute_code" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="frontend_label" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="frontend_label_use_default" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="position" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="prices" type="typens:catalogProductConfigurableOptionPricesEntityArray" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductConfigurableAttributesEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductConfigurableAttributesEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductConfigurableOptionPricesEntity"> + <xsd:sequence> + <xsd:element name="option_value" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="use_default_value" type="xsd:int" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductConfigurableOptionPricesEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductConfigurableOptionPricesEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductReturnEntity"> + <xsd:sequence> + <xsd:element name="product_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" /> + <xsd:element name="set" type="xsd:string" minOccurs="0" /> + <xsd:element name="type" type="xsd:string" minOccurs="0" /> + <xsd:element name="categories" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="websites" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="type_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="description" type="xsd:string" minOccurs="0" /> + <xsd:element name="short_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="weight" type="xsd:string" minOccurs="0" /> + <xsd:element name="status" type="xsd:string" minOccurs="0" /> + <xsd:element name="url_key" type="xsd:string" minOccurs="0" /> + <xsd:element name="url_path" type="xsd:string" minOccurs="0" /> + <xsd:element name="visibility" type="xsd:string" minOccurs="0" /> + <xsd:element name="category_ids" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="website_ids" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="has_options" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message_available" type="xsd:string" minOccurs="0" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" /> + <xsd:element name="special_price" type="xsd:string" minOccurs="0" /> + <xsd:element name="special_from_date" type="xsd:string" minOccurs="0" /> + <xsd:element name="special_to_date" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_class_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="tier_price" type="typens:catalogProductTierPriceEntityArray" minOccurs="0" /> + <xsd:element name="meta_title" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_keyword" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_design" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_layout_update" type="xsd:string" minOccurs="0" /> + <xsd:element name="options_container" type="xsd:string" minOccurs="0" /> + <xsd:element name="additional_attributes" type="typens:associativeArray" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCreateEntity"> + <xsd:sequence> + <xsd:element name="categories" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="websites" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="description" type="xsd:string" minOccurs="0" /> + <xsd:element name="short_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="weight" type="xsd:string" minOccurs="0" /> + <xsd:element name="status" type="xsd:string" minOccurs="0" /> + <xsd:element name="url_key" type="xsd:string" minOccurs="0" /> + <xsd:element name="url_path" type="xsd:string" minOccurs="0" /> + <xsd:element name="visibility" type="xsd:string" minOccurs="0" /> + <xsd:element name="category_ids" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="website_ids" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="has_options" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message_available" type="xsd:string" minOccurs="0" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" /> + <xsd:element name="special_price" type="xsd:string" minOccurs="0" /> + <xsd:element name="special_from_date" type="xsd:string" minOccurs="0" /> + <xsd:element name="special_to_date" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_class_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="tier_price" type="typens:catalogProductTierPriceEntityArray" minOccurs="0" /> + <xsd:element name="meta_title" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_keyword" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_design" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_layout_update" type="xsd:string" minOccurs="0" /> + <xsd:element name="options_container" type="xsd:string" minOccurs="0" /> + <xsd:element name="additional_attributes" type="typens:associativeArray" minOccurs="0" /> + <xsd:element name="configurable_attributes" type="typens:catalogProductConfigurableAttributesEntityArray" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeSetEntity"> + <xsd:sequence> + <xsd:element name="set_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeSetEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductAttributeSetEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTypeEntity"> + <xsd:sequence> + <xsd:element name="type" type="xsd:string" minOccurs="0" /> + <xsd:element name="label" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTypeEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductTypeEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTierPriceEntity"> + <xsd:sequence> + <xsd:element name="customer_group_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="website" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="price" type="xsd:double" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTierPriceEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductTierPriceEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ArrayOfCatalogCategoryEntities"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogCategoryEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogCategoryEntity"> + <xsd:sequence> + <xsd:element name="category_id" type="xsd:int" /> + <xsd:element name="parent_id" type="xsd:int" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="is_active" type="xsd:int" /> + <xsd:element name="position" type="xsd:int" /> + <xsd:element name="level" type="xsd:int" /> + <xsd:element name="children" type="typens:ArrayOfCatalogCategoryEntities" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogCategoryEntityNoChildren"> + <xsd:sequence> + <xsd:element name="category_id" type="xsd:int" /> + <xsd:element name="parent_id" type="xsd:int" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="is_active" type="xsd:int" /> + <xsd:element name="position" type="xsd:int" /> + <xsd:element name="level" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="ArrayOfCatalogCategoryEntitiesNoChildren"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogCategoryEntityNoChildren" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogCategoryTree"> + <xsd:sequence> + <xsd:element name="category_id" type="xsd:int" /> + <xsd:element name="parent_id" type="xsd:int" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="position" type="xsd:int" /> + <xsd:element name="level" type="xsd:int" /> + <xsd:element name="children" type="typens:ArrayOfCatalogCategoryEntities" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogCategoryEntityCreate"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:int" minOccurs="0" /> + <xsd:element name="position" type="xsd:int" minOccurs="0" /> + <xsd:element name="available_sort_by" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="custom_design" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_design_apply" type="xsd:int" minOccurs="0" /> + <xsd:element name="custom_design_from" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_design_to" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_layout_update" type="xsd:string" minOccurs="0" /> + <xsd:element name="default_sort_by" type="xsd:string" minOccurs="0" /> + <xsd:element name="description" type="xsd:string" minOccurs="0" /> + <xsd:element name="display_mode" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_anchor" type="xsd:int" minOccurs="0" /> + <xsd:element name="landing_page" type="xsd:int" minOccurs="0" /> + <xsd:element name="meta_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_keywords" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_title" type="xsd:string" minOccurs="0" /> + <xsd:element name="page_layout" type="xsd:string" minOccurs="0" /> + <xsd:element name="url_key" type="xsd:string" minOccurs="0" /> + <xsd:element name="include_in_menu" type="xsd:int" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogCategoryInfo"> + <xsd:sequence> + <xsd:element name="category_id" type="xsd:string" /> + <xsd:element name="is_active" type="xsd:int" /> + <xsd:element name="position" type="xsd:string" /> + <xsd:element name="level" type="xsd:string" /> + <xsd:element name="parent_id" type="xsd:string" /> + <xsd:element name="all_children" type="xsd:string" /> + <xsd:element name="children" type="xsd:string" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="url_key" type="xsd:string" minOccurs="0" /> + <xsd:element name="description" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_title" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_keywords" type="xsd:string" minOccurs="0" /> + <xsd:element name="meta_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="path" type="xsd:string" minOccurs="0" /> + <xsd:element name="url_path" type="xsd:string" minOccurs="0" /> + <xsd:element name="children_count" type="xsd:int" minOccurs="0" /> + <xsd:element name="display_mode" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_anchor" type="xsd:int" minOccurs="0" /> + <xsd:element name="available_sort_by" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="custom_design" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_design_apply" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_design_from" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_design_to" type="xsd:string" minOccurs="0" /> + <xsd:element name="page_layout" type="xsd:string" minOccurs="0" /> + <xsd:element name="custom_layout_update" type="xsd:string" minOccurs="0" /> + <xsd:element name="default_sort_by" type="xsd:string" minOccurs="0" /> + <xsd:element name="landing_page" type="xsd:int" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogAssignedProduct"> + <xsd:sequence> + <xsd:element name="product_id" type="xsd:int" /> + <xsd:element name="type" type="xsd:string" /> + <xsd:element name="set" type="xsd:int" /> + <xsd:element name="sku" type="xsd:string" /> + <xsd:element name="position" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogAssignedProductArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogAssignedProduct" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogAttributeEntity"> + <xsd:sequence> + <xsd:element name="attribute_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="code" type="xsd:string" minOccurs="0" /> + <xsd:element name="type" type="xsd:string" minOccurs="0" /> + <xsd:element name="required" type="xsd:string" minOccurs="0" /> + <xsd:element name="scope" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogAttributeEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogAttributeEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogAttributeOptionEntity"> + <xsd:sequence> + <xsd:element name="label" type="xsd:string" /> + <xsd:element name="value" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogAttributeOptionEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogAttributeOptionEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductImageEntity"> + <xsd:sequence> + <xsd:element name="file" type="xsd:string" /> + <xsd:element name="label" type="xsd:string" /> + <xsd:element name="position" type="xsd:string" /> + <xsd:element name="exclude" type="xsd:string" /> + <xsd:element name="url" type="xsd:string" /> + <xsd:element name="types" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductImageEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductImageEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeMediaTypeEntity"> + <xsd:sequence> + <xsd:element name="code" type="xsd:string" /> + <xsd:element name="scope" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeMediaTypeEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductAttributeMediaTypeEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductImageFileEntity"> + <xsd:sequence> + <xsd:element name="content" type="xsd:string" /> + <xsd:element name="mime" type="xsd:string" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeMediaCreateEntity"> + <xsd:sequence> + <xsd:element name="file" type="typens:catalogProductImageFileEntity" minOccurs="0" /> + <xsd:element name="label" type="xsd:string" minOccurs="0" /> + <xsd:element name="position" type="xsd:string" minOccurs="0" /> + <xsd:element name="types" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="exclude" type="xsd:string" minOccurs="0" /> + <xsd:element name="remove" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductLinkEntity"> + <xsd:sequence> + <xsd:element name="product_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="type" type="xsd:string" minOccurs="0" /> + <xsd:element name="set" type="xsd:string" minOccurs="0" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" /> + <xsd:element name="position" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductLinkEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductLinkEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductLinkAttributeEntity"> + <xsd:sequence> + <xsd:element name="code" type="xsd:string" minOccurs="0" /> + <xsd:element name="type" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductLinkAttributeEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductLinkAttributeEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeFrontendLabelEntity"> + <xsd:sequence> + <xsd:element name="store_id" type="xsd:string" /> + <xsd:element name="label" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeFrontendLabelArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductAttributeFrontendLabelEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductAttributeEntityToCreate"> + <xsd:sequence> + <xsd:element name="attribute_code" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="frontend_input" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="scope" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="default_value" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_unique" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_required" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="apply_to" type="typens:ArrayOfString" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_configurable" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_searchable" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_visible_in_advanced_search" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_comparable" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_used_for_promo_rules" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_visible_on_front" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="used_in_product_listing" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="additional_fields" type="typens:associativeArray" minOccurs="0" maxOccurs="1" /> + <xsd:element name="frontend_label" type="typens:catalogProductAttributeFrontendLabelArray" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="catalogProductCustomOptionAdditionalFieldsEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="price_type" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="max_characters" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="file_extension" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="image_size_x" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="image_size_y" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="value_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionAdditionalFieldsArray"> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductCustomOptionAdditionalFieldsEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionToAdd"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_require" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="additional_fields" type="typens:catalogProductCustomOptionAdditionalFieldsArray" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionToUpdate"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="type" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_require" type="xsd:int" minOccurs="0" maxOccurs="1" /> + <xsd:element name="additional_fields" type="typens:catalogProductCustomOptionAdditionalFieldsArray" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionInfoEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="is_require" type="xsd:int" minOccurs="1" maxOccurs="1" /> + <xsd:element name="additional_fields" type="typens:catalogProductCustomOptionAdditionalFieldsArray" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionListEntity"> + <xsd:sequence> + <xsd:element name="option_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="is_require" type="xsd:int" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionListArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductCustomOptionListEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionTypesEntity"> + <xsd:sequence> + <xsd:element name="label" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="value" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionTypesArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductCustomOptionTypesEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionValueInfoEntity"> + <xsd:sequence> + <xsd:element name="value_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="option_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="default_price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="default_price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="store_price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="store_price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="default_title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="store_title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionValueListEntity"> + <xsd:sequence> + <xsd:element name="value_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionValueListArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductCustomOptionValueListEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionValueAddEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionValueAddArray"> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductCustomOptionValueAddEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCustomOptionValueUpdateEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="price_type" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sku" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="sort_order" type="xsd:string" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="catalogProductCurrentStoreRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCurrentStoreResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="filters" type="typens:filters" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="attributes" type="typens:catalogProductRequestAttributes" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductReturnEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="type" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="set" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="sku" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productData" type="typens:catalogProductCreateEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productData" type="typens:catalogProductCreateEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductSetSpecialPriceRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="specialPrice" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="fromDate" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="toDate" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductSetSpecialPriceResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductGetSpecialPriceRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductGetSpecialPriceResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductReturnEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductDeleteRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductDeleteResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeCurrentStoreRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeCurrentStoreResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductListOfAdditionalAttributesRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productType" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeSetId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductListOfAdditionalAttributesResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogAttributeEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="setId" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogAttributeEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeOptionsRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeOptionsResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogAttributeOptionEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogProductCustomOptionToAdd" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="optionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogProductCustomOptionToUpdate" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionTypesRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionTypesResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductCustomOptionTypesArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductCustomOptionListArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="optionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductCustomOptionInfoEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="optionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="optionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductCustomOptionValueListArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="valueId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductCustomOptionValueInfoEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="optionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogProductCustomOptionValueAddArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="valueId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogProductCustomOptionValueUpdateEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="valueId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductCustomOptionValueRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeSetName" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="skeletonSetId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeSetId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="forceProductsRemove" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductAttributeSetEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetAttributeAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeSetId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="attributeGroupId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="sortOrder" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetAttributeAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetAttributeRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeSetId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetAttributeRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetGroupAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeSetId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="groupName" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetGroupAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetGroupRenameRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="groupId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="groupName" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetGroupRenameResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetGroupRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeGroupId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeSetGroupRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTypeListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTypeListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductTypeEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeTierPriceInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeTierPriceInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductTierPriceEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeTierPriceUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="tierPrices" type="typens:catalogProductTierPriceEntityArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeTierPriceUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaCurrentStoreRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaCurrentStoreResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductImageEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="file" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductImageEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaTypesRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="setId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaTypesResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductAttributeMediaTypeEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogProductAttributeMediaCreateEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="file" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogProductAttributeMediaCreateEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="file" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeMediaRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="type" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductLinkEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkAssignRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="type" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="linkedProductId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="data" type="typens:catalogProductLinkEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkAssignResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="type" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="linkedProductId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="data" type="typens:catalogProductLinkEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="type" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="linkedProductId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkTypesRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkTypesResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkAttributesRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="type" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductLinkAttributesResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductLinkAttributeEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryCurrentStoreRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryCurrentStoreResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryTreeRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="parentId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryTreeResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogCategoryTree" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryLevelRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="website" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="categoryId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryLevelResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:ArrayOfCatalogCategoryEntitiesNoChildren" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="attributes" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogCategoryInfo" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="parentId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryData" type="typens:catalogCategoryEntityCreate" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryData" type="typens:catalogCategoryEntityCreate" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryMoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="parentId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="afterId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryMoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryDeleteRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryDeleteResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAssignedProductsRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAssignedProductsResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogAssignedProductArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAssignProductRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="position" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAssignProductResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryUpdateProductRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="position" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryUpdateProductResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryRemoveProductRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="categoryId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryRemoveProductResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAttributeListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAttributeListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogAttributeEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAttributeOptionsRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attributeId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAttributeOptionsResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogAttributeOptionEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAttributeCurrentStoreRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogCategoryAttributeCurrentStoreResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogProductAttributeEntityToCreate" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="attribute" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductAttributeRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="catalogProductCurrentStoreRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCurrentStoreRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCurrentStoreResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCurrentStoreResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductInfoRequest"> + <wsdl:part name="parameters" element="typens:catalogProductInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductInfoResponse"> + <wsdl:part name="parameters" element="typens:catalogProductInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCreateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCreateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductSetSpecialPriceRequest"> + <wsdl:part name="parameters" element="typens:catalogProductSetSpecialPriceRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductSetSpecialPriceResponse"> + <wsdl:part name="parameters" element="typens:catalogProductSetSpecialPriceResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductGetSpecialPriceRequest"> + <wsdl:part name="parameters" element="typens:catalogProductGetSpecialPriceRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductGetSpecialPriceResponse"> + <wsdl:part name="parameters" element="typens:catalogProductGetSpecialPriceResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductDeleteRequest"> + <wsdl:part name="parameters" element="typens:catalogProductDeleteRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductDeleteResponse"> + <wsdl:part name="parameters" element="typens:catalogProductDeleteResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeCurrentStoreRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeCurrentStoreRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeCurrentStoreResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeCurrentStoreResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductListOfAdditionalAttributesRequest"> + <wsdl:part name="parameters" element="typens:catalogProductListOfAdditionalAttributesRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductListOfAdditionalAttributesResponse"> + <wsdl:part name="parameters" element="typens:catalogProductListOfAdditionalAttributesResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeOptionsRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeOptionsRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeOptionsResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeOptionsResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionAddRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionAddRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionAddResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionAddResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionTypesRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionTypesRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionTypesResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionTypesResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionInfoRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionInfoResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueAddRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueAddRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueAddResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueAddResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueInfoRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueInfoResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductCustomOptionValueRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductCustomOptionValueRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetCreateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetCreateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetAttributeAddRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetAttributeAddRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetAttributeAddResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetAttributeAddResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetAttributeRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetAttributeRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetAttributeRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetAttributeRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetGroupAddRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetGroupAddRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetGroupAddResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetGroupAddResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetGroupRenameRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetGroupRenameRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetGroupRenameResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetGroupRenameResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetGroupRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetGroupRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeSetGroupRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeSetGroupRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTypeListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductTypeListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTypeListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductTypeListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeTierPriceInfoRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeTierPriceInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeTierPriceInfoResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeTierPriceInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeTierPriceUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeTierPriceUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeTierPriceUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeTierPriceUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaCurrentStoreRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaCurrentStoreRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaCurrentStoreResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaCurrentStoreResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaInfoRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaInfoResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaTypesRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaTypesRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaTypesResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaTypesResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaCreateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaCreateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeMediaRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeMediaRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductLinkListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductLinkListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkAssignRequest"> + <wsdl:part name="parameters" element="typens:catalogProductLinkAssignRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkAssignResponse"> + <wsdl:part name="parameters" element="typens:catalogProductLinkAssignResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductLinkUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductLinkUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductLinkRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductLinkRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkTypesRequest"> + <wsdl:part name="parameters" element="typens:catalogProductLinkTypesRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkTypesResponse"> + <wsdl:part name="parameters" element="typens:catalogProductLinkTypesResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkAttributesRequest"> + <wsdl:part name="parameters" element="typens:catalogProductLinkAttributesRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductLinkAttributesResponse"> + <wsdl:part name="parameters" element="typens:catalogProductLinkAttributesResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryCurrentStoreRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryCurrentStoreRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryCurrentStoreResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryCurrentStoreResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryTreeRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryTreeRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryTreeResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryTreeResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryLevelRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryLevelRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryLevelResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryLevelResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryInfoRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryInfoResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryCreateRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryCreateResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryMoveRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryMoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryMoveResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryMoveResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryDeleteRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryDeleteRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryDeleteResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryDeleteResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAssignedProductsRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryAssignedProductsRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAssignedProductsResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryAssignedProductsResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAssignProductRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryAssignProductRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAssignProductResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryAssignProductResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryUpdateProductRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryUpdateProductRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryUpdateProductResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryUpdateProductResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryRemoveProductRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryRemoveProductRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryRemoveProductResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryRemoveProductResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAttributeCurrentStoreRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryAttributeCurrentStoreRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAttributeCurrentStoreResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryAttributeCurrentStoreResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAttributeListRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryAttributeListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAttributeListResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryAttributeListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAttributeOptionsRequest"> + <wsdl:part name="parameters" element="typens:catalogCategoryAttributeOptionsRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogCategoryAttributeOptionsResponse"> + <wsdl:part name="parameters" element="typens:catalogCategoryAttributeOptionsResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeCreateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeCreateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductAttributeRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductAttributeRemoveResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogCategoryCurrentStore"> + <wsdl:documentation>Set_Get current store view</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryCurrentStoreRequest" /> + <wsdl:output message="typens:catalogCategoryCurrentStoreResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryTree"> + <wsdl:documentation>Retrieve hierarchical tree of categories.</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryTreeRequest" /> + <wsdl:output message="typens:catalogCategoryTreeResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryLevel"> + <wsdl:documentation>Retrieve hierarchical tree of categories.</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryLevelRequest" /> + <wsdl:output message="typens:catalogCategoryLevelResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryInfo"> + <wsdl:documentation>Retrieve hierarchical tree of categories.</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryInfoRequest" /> + <wsdl:output message="typens:catalogCategoryInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryCreate"> + <wsdl:documentation>Create new category and return its id.</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryCreateRequest" /> + <wsdl:output message="typens:catalogCategoryCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryUpdate"> + <wsdl:documentation>Update category</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryUpdateRequest" /> + <wsdl:output message="typens:catalogCategoryUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryMove"> + <wsdl:documentation>Move category in tree</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryMoveRequest" /> + <wsdl:output message="typens:catalogCategoryMoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryDelete"> + <wsdl:documentation>Delete category</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryDeleteRequest" /> + <wsdl:output message="typens:catalogCategoryDeleteResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAssignedProducts"> + <wsdl:documentation>Retrieve list of assigned products</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryAssignedProductsRequest" /> + <wsdl:output message="typens:catalogCategoryAssignedProductsResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAssignProduct"> + <wsdl:documentation>Assign product to category</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryAssignProductRequest" /> + <wsdl:output message="typens:catalogCategoryAssignProductResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryUpdateProduct"> + <wsdl:documentation>Update assigned product</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryUpdateProductRequest" /> + <wsdl:output message="typens:catalogCategoryUpdateProductResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryRemoveProduct"> + <wsdl:documentation>Remove product assignment from category</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryRemoveProductRequest" /> + <wsdl:output message="typens:catalogCategoryRemoveProductResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAttributeCurrentStore"> + <wsdl:documentation>Set/Get current store view</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryAttributeCurrentStoreRequest" /> + <wsdl:output message="typens:catalogCategoryAttributeCurrentStoreResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAttributeList"> + <wsdl:documentation>Retrieve category attributes</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryAttributeListRequest" /> + <wsdl:output message="typens:catalogCategoryAttributeListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAttributeOptions"> + <wsdl:documentation>Retrieve attribute options</wsdl:documentation> + <wsdl:input message="typens:catalogCategoryAttributeOptionsRequest" /> + <wsdl:output message="typens:catalogCategoryAttributeOptionsResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCurrentStore"> + <wsdl:documentation>Set/Get current store view</wsdl:documentation> + <wsdl:input message="typens:catalogProductCurrentStoreRequest" /> + <wsdl:output message="typens:catalogProductCurrentStoreResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductList"> + <wsdl:documentation>Retrieve products list by filters</wsdl:documentation> + <wsdl:input message="typens:catalogProductListRequest" /> + <wsdl:output message="typens:catalogProductListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductInfo"> + <wsdl:documentation>Retrieve product</wsdl:documentation> + <wsdl:input message="typens:catalogProductInfoRequest" /> + <wsdl:output message="typens:catalogProductInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCreate"> + <wsdl:documentation>Create new product and return product id</wsdl:documentation> + <wsdl:input message="typens:catalogProductCreateRequest" /> + <wsdl:output message="typens:catalogProductCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductUpdate"> + <wsdl:documentation>Update product</wsdl:documentation> + <wsdl:input message="typens:catalogProductUpdateRequest" /> + <wsdl:output message="typens:catalogProductUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductSetSpecialPrice"> + <wsdl:documentation>Update product special price</wsdl:documentation> + <wsdl:input message="typens:catalogProductSetSpecialPriceRequest" /> + <wsdl:output message="typens:catalogProductSetSpecialPriceResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductGetSpecialPrice"> + <wsdl:documentation>Get product special price data</wsdl:documentation> + <wsdl:input message="typens:catalogProductGetSpecialPriceRequest" /> + <wsdl:output message="typens:catalogProductGetSpecialPriceResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductDelete"> + <wsdl:documentation>Delete product</wsdl:documentation> + <wsdl:input message="typens:catalogProductDeleteRequest" /> + <wsdl:output message="typens:catalogProductDeleteResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeCurrentStore"> + <wsdl:documentation>Set/Get current store view</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeCurrentStoreRequest" /> + <wsdl:output message="typens:catalogProductAttributeCurrentStoreResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductListOfAdditionalAttributes"> + <wsdl:documentation>Get list of additional attributes which are not in default create/update list</wsdl:documentation> + <wsdl:input message="typens:catalogProductListOfAdditionalAttributesRequest" /> + <wsdl:output message="typens:catalogProductListOfAdditionalAttributesResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeList"> + <wsdl:documentation>Retrieve attribute list</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeListRequest" /> + <wsdl:output message="typens:catalogProductAttributeListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeOptions"> + <wsdl:documentation>Retrieve attribute options</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeOptionsRequest" /> + <wsdl:output message="typens:catalogProductAttributeOptionsResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionAdd"> + <wsdl:documentation>Add new custom option into product</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionAddRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionAddResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionUpdate"> + <wsdl:documentation>Update product custom option</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionUpdateRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionTypes"> + <wsdl:documentation>Get list of available custom option types </wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionTypesRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionTypesResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionList"> + <wsdl:documentation>Retrieve list of product custom options</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionListRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionInfo"> + <wsdl:documentation>Get full information about custom option in product</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionInfoRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionRemove"> + <wsdl:documentation>Remove custom option</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionRemoveRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionRemoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueList"> + <wsdl:documentation>Retrieve custom option values list</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionValueListRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionValueListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueAdd"> + <wsdl:documentation>Add new custom option values</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionValueAddRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionValueAddResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueInfo"> + <wsdl:documentation>Retrieve custom option value info</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionValueInfoRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionValueInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueUpdate"> + <wsdl:documentation>Update custom option value</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionValueUpdateRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionValueUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueRemove"> + <wsdl:documentation>Remove value from custom option</wsdl:documentation> + <wsdl:input message="typens:catalogProductCustomOptionValueRemoveRequest" /> + <wsdl:output message="typens:catalogProductCustomOptionValueRemoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetCreate"> + <wsdl:documentation>Create product attribute set based on another set</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetCreateRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetRemove"> + <wsdl:documentation>Remove product attribute set</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetRemoveRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetRemoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetList"> + <wsdl:documentation>Retrieve product attribute sets</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetListRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetAttributeAdd"> + <wsdl:documentation>Add attribute into attribute set</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetAttributeAddRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetAttributeAddResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetAttributeRemove"> + <wsdl:documentation>Remove attribute from attribute set</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetAttributeRemoveRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetAttributeRemoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetGroupAdd"> + <wsdl:documentation>Create group within existing attribute set</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetGroupAddRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetGroupAddResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetGroupRename"> + <wsdl:documentation>Rename existing group</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetGroupRenameRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetGroupRenameResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetGroupRemove"> + <wsdl:documentation>Remove group from attribute set</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeSetGroupRemoveRequest" /> + <wsdl:output message="typens:catalogProductAttributeSetGroupRemoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductTypeList"> + <wsdl:documentation>Retrieve product types</wsdl:documentation> + <wsdl:input message="typens:catalogProductTypeListRequest" /> + <wsdl:output message="typens:catalogProductTypeListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeTierPriceInfo"> + <wsdl:documentation>Retrieve product tier prices</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeTierPriceInfoRequest" /> + <wsdl:output message="typens:catalogProductAttributeTierPriceInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeTierPriceUpdate"> + <wsdl:documentation>Update product tier prices</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeTierPriceUpdateRequest" /> + <wsdl:output message="typens:catalogProductAttributeTierPriceUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaCurrentStore"> + <wsdl:documentation>Set/Get current store view</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeMediaCurrentStoreRequest" /> + <wsdl:output message="typens:catalogProductAttributeMediaCurrentStoreResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaList"> + <wsdl:documentation>Retrieve product image list</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeMediaListRequest" /> + <wsdl:output message="typens:catalogProductAttributeMediaListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaInfo"> + <wsdl:documentation>Retrieve product image data</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeMediaInfoRequest" /> + <wsdl:output message="typens:catalogProductAttributeMediaInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaTypes"> + <wsdl:documentation>Retrieve product image types</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeMediaTypesRequest" /> + <wsdl:output message="typens:catalogProductAttributeMediaTypesResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaCreate"> + <wsdl:documentation>Upload new product image</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeMediaCreateRequest" /> + <wsdl:output message="typens:catalogProductAttributeMediaCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaUpdate"> + <wsdl:documentation>Update product image</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeMediaUpdateRequest" /> + <wsdl:output message="typens:catalogProductAttributeMediaUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaRemove"> + <wsdl:documentation>Remove product image</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeMediaRemoveRequest" /> + <wsdl:output message="typens:catalogProductAttributeMediaRemoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkList"> + <wsdl:documentation>Retrieve linked products</wsdl:documentation> + <wsdl:input message="typens:catalogProductLinkListRequest" /> + <wsdl:output message="typens:catalogProductLinkListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkAssign"> + <wsdl:documentation>Assign product link</wsdl:documentation> + <wsdl:input message="typens:catalogProductLinkAssignRequest" /> + <wsdl:output message="typens:catalogProductLinkAssignResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkUpdate"> + <wsdl:documentation>Update product link</wsdl:documentation> + <wsdl:input message="typens:catalogProductLinkUpdateRequest" /> + <wsdl:output message="typens:catalogProductLinkUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkRemove"> + <wsdl:documentation>Remove product link</wsdl:documentation> + <wsdl:input message="typens:catalogProductLinkRemoveRequest" /> + <wsdl:output message="typens:catalogProductLinkRemoveResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkTypes"> + <wsdl:documentation>Retrieve product link types</wsdl:documentation> + <wsdl:input message="typens:catalogProductLinkTypesRequest" /> + <wsdl:output message="typens:catalogProductLinkTypesResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkAttributes"> + <wsdl:documentation>Retrieve product link type attributes</wsdl:documentation> + <wsdl:input message="typens:catalogProductLinkAttributesRequest" /> + <wsdl:output message="typens:catalogProductLinkAttributesResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeCreate"> + <wsdl:documentation>Create new attribute</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeCreateRequest" /> + <wsdl:output message="typens:catalogProductAttributeCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeRemove"> + <wsdl:documentation>Delete attribute</wsdl:documentation> + <wsdl:input message="typens:catalogProductAttributeRemoveRequest" /> + <wsdl:output message="typens:catalogProductAttributeRemoveResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogCategoryCurrentStore"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryTree"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryLevel"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryMove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryDelete"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAssignedProducts"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAssignProduct"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryUpdateProduct"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryRemoveProduct"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCurrentStore"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductSetSpecialPrice"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductGetSpecialPrice"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductDelete"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeCurrentStore"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductListOfAdditionalAttributes"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeOptions"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionAdd"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionTypes"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueAdd"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductCustomOptionValueRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetAttributeAdd"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetAttributeRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetGroupAdd"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetGroupRename"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeSetGroupRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductTypeList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeTierPriceInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeTierPriceUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAttributeCurrentStore"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAttributeList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogCategoryAttributeOptions"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaCurrentStore"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaTypes"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeMediaRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkAssign"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkTypes"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductLinkAttributes"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductAttributeRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="{{var wsdl.name}}Service"> + <wsdl:port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/app/code/core/Mage/Catalog/view/adminhtml/js/grouped-product.js b/app/code/core/Mage/Catalog/view/adminhtml/js/grouped-product.js new file mode 100644 index 00000000000..950855a5f0a --- /dev/null +++ b/app/code/core/Mage/Catalog/view/adminhtml/js/grouped-product.js @@ -0,0 +1,182 @@ +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Catalog + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +/*jshint browser:true jquery:true*/ +(function($) { + $.widget('mage.groupedProduct', { + _create: function () { + this.$grid = this.element.find('#grouped_grid'); + this.$popup = this.element.find('#grouped_grid_popup'); + + this._bindDialog(); + this._bindEventHandlers(); + if (!$.isArray(this.options.gridData) || this.options.gridData.length) { + this._initGridWithData(this.options.gridData); + } + this._displayGridRow(this.options.associatedProductIds); + this._updatePopupGrid(); + this._updateHiddenField(this.options.associatedProductIds); + this._sortGridByPosition(); + }, + + _bindDialog: function () { + var widget = this; + $('#grouped-product-popup').dialog({ + title: 'Add Products to Group', + autoOpen: false, + minWidth: 980, + modal: true, + resizable: true, + buttons: [{ + id: 'grouped-product-dialog-cancel-button', + text: 'Cancel', + click: function () { + widget._updatePopupGrid(); + $(this).dialog('close'); + } + }, { + id: 'grouped-product-dialog-apply-button', + text: 'Apply Changes', + 'class': 'add', + click: function () { + var ids = widget._getSelectedIds(); + widget._displayGridRow(ids); + widget._updateHiddenField(ids); + $(this).dialog('close'); + } + }] + }); + }, + + _bindEventHandlers: function () { + var widget = this; + $('#grouped-add-products').on('click', function () { + $('#grouped-product-popup').dialog('open'); + return false; + }); + this.$grid.on('click', '.product-delete button', function (event) { + $(this).closest('tr').hide().addClass('ignore-validate'); + widget._updatePopupGrid(); + widget._updateHiddenField(widget._getSelectedIds()); + widget._updateGridVisibility(); + }); + this.$grid.on('change keyup', 'input[type="text"]', function (event) { + widget._updateHiddenField(widget._getSelectedIds()); + }); + this.options.grid.rowClickCallback = function () {}; + this.options.gridPopup.rowClickCallback = function (grid, event) { + event.stopPropagation(); + if (!this.rows || !this.rows.length) { + return; + } + $(event.target).parent().find('td.selected-products input[type="checkbox"]').click(); + return false; + }; + }, + + updateRowsPositions: function () { + $.each(this.$grid.find('input[name="position"]'), function (index) { + $(this).val(index); + }); + this._updateHiddenField(this._getSelectedIds()); + }, + + _updateHiddenField: function (ids) { + var gridData = {}, widget = this; + $.each(this.$grid.find('input[name="entity_id"]'), function () { + var $idContainer = $(this), + inArray = $.inArray($idContainer.val(), ids) !== -1; + if (inArray) { + var data = {}; + $.each(widget.options.fieldsToSave, function (k, v) { + data[v] = $idContainer.closest('tr').find('input[name="' + v + '"]').val(); + }); + gridData[$idContainer.val()] = data; + } + }); + widget.options.$hiddenInput.val(JSON.stringify(gridData)); + }, + + _displayGridRow: function (ids) { + var displayedRows = 0; + $.each(this.$grid.find('input[name="entity_id"]'), function () { + var $idContainer = $(this), + inArray = $.inArray($idContainer.val(), ids) !== -1; + $idContainer.closest('tr').toggle(inArray).toggleClass('ignore-validate', !inArray); + if (inArray) { + displayedRows++; + } + }); + this._updateGridVisibility(displayedRows); + }, + + _initGridWithData: function (gridData) { + $.each(this.$grid.find('input[name="entity_id"]'), function () { + var $idContainer = $(this), + id = $idContainer.val(); + if (!gridData[id]) { + return true; + } + $.each(gridData[id], function (fieldName, data) { + $idContainer.closest('tr').find('input[name="' + fieldName + '"]').val(data); + }); + }); + }, + + _getSelectedIds: function () { + var ids = []; + $.each(this.$popup.find('.selected-products input[type="checkbox"]:checked'), + function () { + ids.push($(this).val()); + } + ); + return ids; + }, + + _updatePopupGrid: function () { + var $popup = this.$popup; + $.each(this.$grid.find('input[name="entity_id"]'), function () { + var id = $(this).val(); + $popup.find('input[type=checkbox][value="' + id + '"]') + .prop({checked: !$(this).closest('tr').hasClass('ignore-validate')}); + }); + }, + + _sortGridByPosition: function () { + var rows = this.$grid.find('tbody tr'); + rows.sort(function (a, b) { + var valueA = $(a).find('input[name="position"]').val(), + valueB = $(b).find('input[name="position"]').val(); + return (valueA < valueB) ? -1 : (valueA > valueB) ? 1 : 0; + }); + this.$grid.find('tbody').html(rows); + }, + + _updateGridVisibility: function (showGrid) { + showGrid = showGrid || this.element.find('#grouped_grid_table tbody tr:visible').length > 0; + this.element.find('.grid-wrapper').toggle(showGrid); + this.element.find('.no-products-message').toggle(!showGrid); + } + }); +})(jQuery); diff --git a/dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/theme.xml b/app/code/core/Mage/Catalog/view/adminhtml/product/grouped/container.phtml similarity index 66% rename from dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/theme.xml rename to app/code/core/Mage/Catalog/view/adminhtml/product/grouped/container.phtml index 5707aed823d..63f6c4426ba 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Block/_files/adminhtml/default/basic/theme.xml +++ b/app/code/core/Mage/Catalog/view/adminhtml/product/grouped/container.phtml @@ -1,4 +1,4 @@ -<!-- +<?php /** * Magento * @@ -18,21 +18,21 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Magento - * @package Design - * @subpackage integration_tests + * @category design + * @package default_default * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ---> -<design> - <package code="default"> - <title>Default</title> - <theme version="2.0.0.0" code="basic"> - <title>Default</title> - <requirements> - <magento_version from="2.0.0.0-dev1" to="*"/> - </requirements> - </theme> - </package> -</design> + ?> + +<?php /* @var $this Mage_Catalog_Block_Product_Grouped_AssociatedProducts */ ?> +<div class="entry-edit" id="<?php echo $this->getId() ?>"> + <div class="entry-edit-head"> + <h4 class="icon-head head-edit-form fieldset-legend"> + <?php echo $this->getTabLabel() ?> + </h4> + </div> + <fieldset> + <?php echo $this->getChildHtml()?> + </fieldset> +</div> diff --git a/app/code/core/Mage/Catalog/view/adminhtml/product/grouped/grouped.phtml b/app/code/core/Mage/Catalog/view/adminhtml/product/grouped/grouped.phtml new file mode 100644 index 00000000000..65b13e5e548 --- /dev/null +++ b/app/code/core/Mage/Catalog/view/adminhtml/product/grouped/grouped.phtml @@ -0,0 +1,64 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category design + * @package default_default + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +?> +<div id="grouped-product-container"> + <div class="no-products-message" style="display:block"> + <?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('There are no grouped products.')?> + </div> + <div class="grid-wrapper" style="display:none"> +<?php + /** @var $this Mage_Core_Block_Template */ + /** @var $_gridBlock Mage_Catalog_Block_Product_Grouped_AssociatedProducts_Grid */ + $_gridBlock = $this->getChildBlock('catalog.product.group.grid.container') + ->getChildBlock('catalog.product.group.grid'); + $_gridPopupBlock = $this->getChildBlock('catalog.product.group.grid.popup.container') + ->getChildBlock('catalog.product.group.grid.popup'); + $_gridPopupBlock->setRowClickCallback('function(){}'); + /** @var $_helper Mage_Core_Helper_Data */ + $_helper = $this->helper('Mage_Core_Helper_Data'); + echo $this->getChildBlock('catalog.product.group.grid.container')->getChildHtml('catalog.product.group.grid'); +?> + </div> + <input type="hidden" name="<?php echo $_gridBlock->getHiddenInputName();?>"/> + <div id="grouped-product-popup" style="display:none"> + <?php echo $this->getChildBlock('catalog.product.group.grid.popup.container')->getChildHtml('catalog.product.group.grid.popup');?> + </div> +</div> +<button id="grouped-add-products">Add Products to Group</button> +<script type="text/javascript"> +jQuery(function($) { + head.js("<?php echo $this->getViewFileUrl('Mage_Catalog::js/grouped-product.js') ?>", function () { + $('#grouped-product-container').mage('groupedProduct', { + grid: window.<?php echo $_gridBlock->getJsObjectName() ?>, + gridData: <?php echo $_gridBlock->getAssociatedProducts()?>, + gridPopup: window.<?php echo $_gridPopupBlock->getJsObjectName() ?>, + $hiddenInput: $('#grouped-product-container input[name="<?php echo $_gridBlock->getHiddenInputName()?>"]'), + associatedProductIds: <?php echo $_gridBlock->getAssociatedProductIds()?>, + fieldsToSave: <?php echo $_helper->jsonEncode($_gridBlock->getFieldsToSave())?> + }); + }); +}); +</script> diff --git a/app/code/core/Mage/Catalog/view/adminhtml/product/product.css b/app/code/core/Mage/Catalog/view/adminhtml/product/product.css index 7e2c060b86f..80613497138 100644 --- a/app/code/core/Mage/Catalog/view/adminhtml/product/product.css +++ b/app/code/core/Mage/Catalog/view/adminhtml/product/product.css @@ -853,6 +853,7 @@ .ui-icon-grip-dotted-vertical { background-position: 0 -224px; + cursor: n-resize; } .ui-icon-grip-dotted-horizontal { @@ -1053,3 +1054,11 @@ filter: none; text-shadow: none; } +#grouped-product-container .no-products-message { + border: #dadfe0 1px solid; + background: #fff; + margin: 0 30px 10px; + padding: 20px 40px; + text-align: center; + vertical-align: middle; +} diff --git a/app/code/core/Mage/CatalogInventory/Block/Adminhtml/Form/Field/Stock.php b/app/code/core/Mage/CatalogInventory/Block/Adminhtml/Form/Field/Stock.php index 053a895321b..574a19efc85 100644 --- a/app/code/core/Mage/CatalogInventory/Block/Adminhtml/Form/Field/Stock.php +++ b/app/code/core/Mage/CatalogInventory/Block/Adminhtml/Form/Field/Stock.php @@ -162,20 +162,34 @@ class Mage_CatalogInventory_Block_Adminhtml_Form_Field_Stock extends Varien_Data { return " <script> - //<![CDATA[ jQuery(function($) { - var qty = $('#$quantityFieldId'), - isInStock = $('#$inStockFieldId'), - manageStock = $('#inventory_manage_stock').removeClass('disabled').removeAttr('disabled'), - useConfigManageStock = $('#inventory_use_config_manage_stock'); + var qty = $('#{$quantityFieldId}'), + productType = $('#type_id').val(), + stockAvailabilityField = $('#{$inStockFieldId}'), + manageStockField = $('#inventory_manage_stock'), + useConfigManageStockField = $('#inventory_use_config_manage_stock'); var disabler = function() { - if ('' === qty.val()) { - isInStock.attr('disabled', 'disabled'); - manageStock.val(0); + var hasVariation = $('#config_super_product-checkbox').is(':checked'); + if ((productType == 'configurable' && hasVariation) + || productType == 'grouped' + || productType == 'bundle'//@TODO move this check to Mage_Bundle after refactoring as widget + || hasVariation + ) { + return; + } + var manageStockValue = (qty.val() === '') ? 0 : 1; + if (manageStockValue) { + stockAvailabilityField.prop('disabled', false); } else { - isInStock.removeAttr('disabled'); - manageStock.val(1); + stockAvailabilityField.prop('disabled', true).val(0); + } + if (manageStockField.val() != manageStockValue) { + if (useConfigManageStockField.val() == 1) { + useConfigManageStockField.removeAttr('checked').val(0); + } + manageStockField.toggleClass('disabled', false).prop('disabled', false); + manageStockField.val(manageStockValue); } }; @@ -212,7 +226,6 @@ class Mage_CatalogInventory_Block_Adminhtml_Form_Field_Stock extends Varien_Data }); disabler(); }); - //]]> </script> "; } diff --git a/app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api.php b/app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api.php new file mode 100644 index 00000000000..b43852cb546 --- /dev/null +++ b/app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api.php @@ -0,0 +1,75 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_CatalogInventory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog inventory api + * + * @category Mage + * @package Mage_CatalogInventory + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_CatalogInventory_Model_Stock_Item_Api extends Mage_Catalog_Model_Api_Resource +{ + public function __construct() + { + $this->_storeIdSessionField = 'product_store_id'; + } + + public function items($productIds) + { + if (!is_array($productIds)) { + $productIds = array($productIds); + } + + $product = Mage::getModel('Mage_Catalog_Model_Product'); + + foreach ($productIds as &$productId) { + if ($newId = $product->getIdBySku($productId)) { + $productId = $newId; + } + } + + $collection = Mage::getModel('Mage_Catalog_Model_Product') + ->getCollection() + ->setFlag('require_stock_items', true) + ->addFieldToFilter('entity_id', array('in'=>$productIds)); + + $result = array(); + + foreach ($collection as $product) { + if ($product->getStockItem()) { + $result[] = array( + 'product_id' => $product->getId(), + 'sku' => $product->getSku(), + 'qty' => $product->getStockItem()->getQty(), + 'is_in_stock' => $product->getStockItem()->getIsInStock() + ); + } + } + + return $result; + } +} // Class Mage_CatalogInventory_Model_Stock_Item_Api End diff --git a/app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api/V2.php b/app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api/V2.php new file mode 100644 index 00000000000..54bc68c1b32 --- /dev/null +++ b/app/code/core/Mage/CatalogInventory/Model/Stock/Item/Api/V2.php @@ -0,0 +1,89 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_CatalogInventory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Catalog inventory api V2 + * + * @category Mage + * @package Mage_CatalogInventory + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_CatalogInventory_Model_Stock_Item_Api_V2 extends Mage_CatalogInventory_Model_Stock_Item_Api +{ + public function update($productId, $data) + { + $product = Mage::getModel('Mage_Catalog_Model_Product'); + + if ($newId = $product->getIdBySku($productId)) { + $productId = $newId; + } + + $product->setStoreId($this->_getStoreId()) + ->load($productId); + + if (!$product->getId()) { + $this->_fault('not_exists'); + } + + if (!$stockData = $product->getStockData()) { + $stockData = array(); + } + + if (isset($data->qty)) { + $stockData['qty'] = $data->qty; + } + + if (isset($data->is_in_stock)) { + $stockData['is_in_stock'] = $data->is_in_stock; + } + + if (isset($data->manage_stock)) { + $stockData['manage_stock'] = $data->manage_stock; + } + + if (isset($data->use_config_manage_stock)) { + $stockData['use_config_manage_stock'] = $data->use_config_manage_stock; + } + + if (isset($data->use_config_backorders)) { + $stockData['use_config_backorders'] = $data->use_config_backorders; + } + + if (isset($data->backorders)) { + $stockData['backorders'] = $data->backorders; + } + + $product->setStockData($stockData); + + try { + $product->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_updated', $e->getMessage()); + } + + return true; + } +} diff --git a/app/code/core/Mage/CatalogInventory/etc/api.xml b/app/code/core/Mage/CatalogInventory/etc/api.xml new file mode 100644 index 00000000000..282d8192d20 --- /dev/null +++ b/app/code/core/Mage/CatalogInventory/etc/api.xml @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_CatalogInventory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <cataloginventory_stock_item translate="title" module="Mage_CatalogInventory"> + <model>Mage_CatalogInventory_Model_Stock_Item_Api</model> + <title>Inventory API</title> + <acl>cataloginventory</acl> + <methods> + <list translate="title" module="Mage_CatalogInventory"> + <title>Retrieve stock data by product ids</title> + <method>items</method> + <acl>cataloginventory/info</acl> + </list> + <update translate="title" module="Mage_CatalogInventory"> + <title>Update product stock data</title> + <acl>cataloginventory/update</acl> + </update> + </methods> + <faults module="Mage_CatalogInventory"> + <not_exists> + <code>101</code> + <message>Product does not exist.</message> + </not_exists> + <not_updated> + <code>102</code> + <message>Product inventory is not updated. Details are in error message.</message> + </not_updated> + </faults> + </cataloginventory_stock_item> + </resources> + <resources_alias> + <product_stock>cataloginventory_stock_item</product_stock> + </resources_alias> + <v2> + <resources_function_prefix> + <product_stock>catalogInventoryStockItem</product_stock> + </resources_function_prefix> + </v2> + <acl> + <resources> + <cataloginventory translate="title" module="Mage_CatalogInventory"> + <title>Catalog Inventory</title> + <sort_order>4</sort_order> + <update translate="title" module="Mage_CatalogInventory"> + <title>Update</title> + </update> + <info translate="title" module="Mage_CatalogInventory"> + <title>Retrieve stock data</title> + </info> + </cataloginventory> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/CatalogInventory/etc/wsdl.xml b/app/code/core/Mage/CatalogInventory/etc/wsdl.xml new file mode 100644 index 00000000000..6291e9cc039 --- /dev/null +++ b/app/code/core/Mage/CatalogInventory/etc/wsdl.xml @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="catalogInventoryStockItemEntity"> + <all> + <element name="product_id" type="xsd:string" minOccurs="0" /> + <element name="sku" type="xsd:string" minOccurs="0" /> + <element name="qty" type="xsd:string" minOccurs="0" /> + <element name="is_in_stock" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogInventoryStockItemEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogInventoryStockItemEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogInventoryStockItemUpdateEntity"> + <all> + <element name="qty" type="xsd:string" minOccurs="0" /> + <element name="is_in_stock" type="xsd:int" minOccurs="0" /> + <element name="manage_stock" type="xsd:int" minOccurs="0" /> + <element name="use_config_manage_stock" type="xsd:int" minOccurs="0" /> + <element name="min_qty" type="xsd:int" minOccurs="0" /> + <element name="use_config_min_qty" type="xsd:int" minOccurs="0" /> + <element name="min_sale_qty" type="xsd:int" minOccurs="0" /> + <element name="use_config_min_sale_qty" type="xsd:int" minOccurs="0" /> + <element name="max_sale_qty" type="xsd:int" minOccurs="0" /> + <element name="use_config_max_sale_qty" type="xsd:int" minOccurs="0" /> + <element name="is_qty_decimal" type="xsd:int" minOccurs="0" /> + <element name="backorders" type="xsd:int" minOccurs="0" /> + <element name="use_config_backorders" type="xsd:int" minOccurs="0" /> + <element name="notify_stock_qty" type="xsd:int" minOccurs="0" /> + <element name="use_config_notify_stock_qty" type="xsd:int" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogProductCreateEntity"> + <all> + <element name="stock_data" type="typens:catalogInventoryStockItemUpdateEntity" minOccurs="0" /> + </all> + </complexType> + </schema> + </types> + <message name="catalogInventoryStockItemListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="products" type="typens:ArrayOfString" /> + </message> + <message name="catalogInventoryStockItemListResponse"> + <part name="result" type="typens:catalogInventoryStockItemEntityArray" /> + </message> + <message name="catalogInventoryStockItemUpdateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="product" type="xsd:string" /> + <part name="data" type="typens:catalogInventoryStockItemUpdateEntity" /> + </message> + <message name="catalogInventoryStockItemUpdateResponse"> + <part name="result" type="xsd:int" /> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogInventoryStockItemList"> + <documentation>Retrieve stock data by product ids</documentation> + <input message="typens:catalogInventoryStockItemListRequest" /> + <output message="typens:catalogInventoryStockItemListResponse" /> + </operation> + <operation name="catalogInventoryStockItemUpdate"> + <documentation>Update product stock data</documentation> + <input message="typens:catalogInventoryStockItemUpdateRequest" /> + <output message="typens:catalogInventoryStockItemUpdateResponse" /> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="catalogInventoryStockItemList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="catalogInventoryStockItemUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/CatalogInventory/etc/wsi.xml b/app/code/core/Mage/CatalogInventory/etc/wsi.xml new file mode 100644 index 00000000000..6812d85cb05 --- /dev/null +++ b/app/code/core/Mage/CatalogInventory/etc/wsi.xml @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="catalogInventoryStockItemEntity"> + <xsd:sequence> + <xsd:element name="product_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_in_stock" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogInventoryStockItemEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogInventoryStockItemEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogInventoryStockItemUpdateEntity"> + <xsd:sequence> + <xsd:element name="qty" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_in_stock" type="xsd:int" minOccurs="0" /> + <xsd:element name="manage_stock" type="xsd:int" minOccurs="0" /> + <xsd:element name="use_config_manage_stock" type="xsd:int" minOccurs="0" /> + <xsd:element name="min_qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="use_config_min_qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="min_sale_qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="use_config_min_sale_qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="max_sale_qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="use_config_max_sale_qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="is_qty_decimal" type="xsd:int" minOccurs="0" /> + <xsd:element name="backorders" type="xsd:int" minOccurs="0" /> + <xsd:element name="use_config_backorders" type="xsd:int" minOccurs="0" /> + <xsd:element name="notify_stock_qty" type="xsd:int" minOccurs="0" /> + <xsd:element name="use_config_notify_stock_qty" type="xsd:int" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductCreateEntity"> + <xsd:sequence> + <xsd:element name="stock_data" type="typens:catalogInventoryStockItemUpdateEntity" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + + <xsd:element name="catalogInventoryStockItemListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productIds" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogInventoryStockItemListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogInventoryStockItemEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogInventoryStockItemUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="data" type="typens:catalogInventoryStockItemUpdateEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogInventoryStockItemUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="catalogInventoryStockItemListRequest"> + <wsdl:part name="parameters" element="typens:catalogInventoryStockItemListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogInventoryStockItemListResponse"> + <wsdl:part name="parameters" element="typens:catalogInventoryStockItemListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogInventoryStockItemUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogInventoryStockItemUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogInventoryStockItemUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogInventoryStockItemUpdateResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogInventoryStockItemList"> + <wsdl:documentation>Retrieve stock data by product ids</wsdl:documentation> + <wsdl:input message="typens:catalogInventoryStockItemListRequest" /> + <wsdl:output message="typens:catalogInventoryStockItemListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogInventoryStockItemUpdate"> + <wsdl:documentation>Update product stock data</wsdl:documentation> + <wsdl:input message="typens:catalogInventoryStockItemUpdateRequest" /> + <wsdl:output message="typens:catalogInventoryStockItemUpdateResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogInventoryStockItemList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogInventoryStockItemUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="{{var wsdl.name}}Service"> + <wsdl:port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/app/code/core/Mage/CatalogSearch/view/frontend/form.mini.phtml b/app/code/core/Mage/CatalogSearch/view/frontend/form.mini.phtml index 19d2cc05b88..e5de26bf743 100644 --- a/app/code/core/Mage/CatalogSearch/view/frontend/form.mini.phtml +++ b/app/code/core/Mage/CatalogSearch/view/frontend/form.mini.phtml @@ -25,6 +25,7 @@ */ ?> <?php +/** @var $this Mage_Core_Block_Template */ /** @var $helper Mage_CatalogSearch_Helper_Data */ $helper = $this->helper('Mage_CatalogSearch_Helper_Data'); ?> diff --git a/app/code/core/Mage/Checkout/Model/Api/Resource.php b/app/code/core/Mage/Checkout/Model/Api/Resource.php new file mode 100644 index 00000000000..48c9b3784a3 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Api/Resource.php @@ -0,0 +1,218 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Checkout api resource + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Checkout_Model_Api_Resource extends Mage_Api_Model_Resource_Abstract +{ + /** + * Attributes map array per entity type + * + * @var array + */ + protected $_attributesMap = array( + 'global' => array(), + ); + + /** + * Default ignored attribute codes per entity type + * + * @var array + */ + protected $_ignoredAttributeCodes = array( + 'global' => array('entity_id', 'attribute_set_id', 'entity_type_id') + ); + + /** + * Field name in session for saving store id + * + * @var string + */ + protected $_storeIdSessionField = 'store_id'; + + /** @var Mage_Api_Helper_Data */ + protected $_apiHelper; + + /** + * Initialize dependencies. + * + * @param Mage_Api_Helper_Data $apiHelper + */ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + $this->_apiHelper = $apiHelper; + } + + /** + * Check if quote already exist with provided quoteId for creating + * + * @param int $quoteId + * @return bool + */ + protected function _isQuoteExist($quoteId) + { + if (empty($quoteId)) { + return false; + } + + try { + $quote = $this->_getQuote($quoteId); + } catch (Mage_Api_Exception $e) { + return false; + } + + if (!is_null($quote->getId())) { + $this->_fault('quote_already_exist'); + } + + return false; + } + + /** + * Retrieves store id from store code, if no store id specified, + * it use set session or admin store + * + * @param string|int $store + * @return int + */ + protected function _getStoreId($store = null) + { + if (is_null($store)) { + $store = ($this->_getSession()->hasData($this->_storeIdSessionField) + ? $this->_getSession()->getData($this->_storeIdSessionField) : 0); + } + + try { + $storeId = Mage::app()->getStore($store)->getId(); + + } catch (Mage_Core_Model_Store_Exception $e) { + $this->_fault('store_not_exists'); + } + + return $storeId; + } + + /** + * Retrieves quote by quote identifier and store code or by quote identifier + * + * @param int $quoteId + * @param string|int $store + * @return Mage_Sales_Model_Quote + */ + protected function _getQuote($quoteId, $store = null) + { + /** @var $quote Mage_Sales_Model_Quote */ + $quote = Mage::getModel('Mage_Sales_Model_Quote'); + + if (!(is_string($store) || is_integer($store))) { + $quote->loadByIdWithoutStore($quoteId); + } else { + $storeId = $this->_getStoreId($store); + + $quote->setStoreId($storeId) + ->load($quoteId); + } + if (is_null($quote->getId())) { + $this->_fault('quote_not_exists'); + } + + return $quote; + } + + /** + * Get store identifier by quote identifier + * + * @param int $quoteId + * @return int + */ + protected function _getStoreIdFromQuote($quoteId) + { + /** @var $quote Mage_Sales_Model_Quote */ + $quote = Mage::getModel('Mage_Sales_Model_Quote') + ->loadByIdWithoutStore($quoteId); + + return $quote->getStoreId(); + } + + /** + * Update attributes for entity + * + * @param array $data + * @param Mage_Core_Model_Abstract $object + * @param string $type + * @param array|null $attributes + * @return Mage_Checkout_Model_Api_Resource + */ + protected function _updateAttributes($data, $object, $type, array $attributes = null) + { + foreach ($data as $attribute => $value) { + if ($this->_apiHelper->isAttributeAllowed($attribute, $type, $this->_ignoredAttributeCodes, $attributes)) { + $object->setData($attribute, $value); + } + } + + return $this; + } + + /** + * Retrieve entity attributes values + * + * @param Mage_Core_Model_Abstract $object + * @param string $type + * @param array $attributes + * @return Mage_Checkout_Model_Api_Resource + */ + protected function _getAttributes($object, $type, array $attributes = null) + { + $result = array(); + if (!is_object($object)) { + return $result; + } + foreach ($object->getData() as $attribute => $value) { + if (is_object($value)) { + continue; + } + + if ($this->_apiHelper->isAttributeAllowed($attribute, $type, $this->_ignoredAttributeCodes, $attributes)) { + $result[$attribute] = $value; + } + } + if (isset($this->_attributesMap[$type])) { + foreach ($this->_attributesMap[$type] as $alias => $attributeCode) { + $result[$alias] = $object->getData($attributeCode); + } + } + foreach ($this->_attributesMap['global'] as $alias => $attributeCode) { + $result[$alias] = $object->getData($attributeCode); + } + return $result; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php b/app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php new file mode 100644 index 00000000000..34a314d3f6f --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Api/Resource/Customer.php @@ -0,0 +1,213 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Checkout api resource for Customer + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Checkout_Model_Api_Resource_Customer extends Mage_Checkout_Model_Api_Resource +{ + /** + * Customer address types + */ + const ADDRESS_BILLING = Mage_Sales_Model_Quote_Address::TYPE_BILLING; + const ADDRESS_SHIPPING = Mage_Sales_Model_Quote_Address::TYPE_SHIPPING; + + /** + * Customer checkout types + */ + const MODE_CUSTOMER = Mage_Checkout_Model_Type_Onepage::METHOD_CUSTOMER; + const MODE_REGISTER = Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER; + const MODE_GUEST = Mage_Checkout_Model_Type_Onepage::METHOD_GUEST; + + + /** + * + */ + protected function _getCustomer($customerId) + { + /** @var $customer Mage_Customer_Model_Customer */ + $customer = Mage::getModel('Mage_Customer_Model_Customer') + ->load($customerId); + if (!$customer->getId()) { + $this->_fault('customer_not_exists'); + } + + return $customer; + } + + /** + * Get customer address by identifier + * + * @param int $addressId + * @return Mage_Customer_Model_Address + */ + protected function _getCustomerAddress($addressId) + { + $address = Mage::getModel('Mage_Customer_Model_Address')->load((int)$addressId); + if (is_null($address->getId())) { + $this->_fault('invalid_address_id'); + } + + $address->explodeStreetAddress(); + if ($address->getRegionId()) { + $address->setRegion($address->getRegionId()); + } + return $address; + } + + /** + * @param Mage_Sales_Model_Quote $quote + * @return bool + */ + public function prepareCustomerForQuote(Mage_Sales_Model_Quote $quote) + { + $isNewCustomer = false; + switch ($quote->getCheckoutMethod()) { + case self::MODE_GUEST: + $this->_prepareGuestQuote($quote); + break; + case self::MODE_REGISTER: + $this->_prepareNewCustomerQuote($quote); + $isNewCustomer = true; + break; + default: + $this->_prepareCustomerQuote($quote); + break; + } + + return $isNewCustomer; + } + + /** + * Prepare quote for guest checkout order submit + * + * @param Mage_Sales_Model_Quote $quote + * @return Mage_Checkout_Model_Api_Resource_Customer + */ + protected function _prepareGuestQuote(Mage_Sales_Model_Quote $quote) + { + $quote->setCustomerId(null) + ->setCustomerEmail($quote->getBillingAddress()->getEmail()) + ->setCustomerIsGuest(true) + ->setCustomerGroupId(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID); + return $this; + } + + /** + * Prepare quote for customer registration and customer order submit + * + * @param Mage_Sales_Model_Quote $quote + * @return Mage_Checkout_Model_Api_Resource_Customer + */ + protected function _prepareNewCustomerQuote(Mage_Sales_Model_Quote $quote) + { + $billing = $quote->getBillingAddress(); + $shipping = $quote->isVirtual() ? null : $quote->getShippingAddress(); + + //$customer = Mage::getModel('Mage_Customer_Model_Customer'); + $customer = $quote->getCustomer(); + /* @var $customer Mage_Customer_Model_Customer */ + $customerBilling = $billing->exportCustomerAddress(); + $customer->addAddress($customerBilling); + $billing->setCustomerAddress($customerBilling); + $customerBilling->setIsDefaultBilling(true); + if ($shipping && !$shipping->getSameAsBilling()) { + $customerShipping = $shipping->exportCustomerAddress(); + $customer->addAddress($customerShipping); + $shipping->setCustomerAddress($customerShipping); + $customerShipping->setIsDefaultShipping(true); + } else { + $customerBilling->setIsDefaultShipping(true); + } + + Mage::helper('Mage_Core_Helper_Data')->copyFieldset('checkout_onepage_quote', 'to_customer', $quote, $customer); + $customer->setPassword($customer->decryptPassword($quote->getPasswordHash())); + $customer->setPasswordHash($customer->hashPassword($customer->getPassword())); + $quote->setCustomer($customer) + ->setCustomerId(true); + + return $this; + } + + /** + * Prepare quote for customer order submit + * + * @param Mage_Sales_Model_Quote $quote + * @return Mage_Checkout_Model_Api_Resource_Customer + */ + protected function _prepareCustomerQuote(Mage_Sales_Model_Quote $quote) + { + $billing = $quote->getBillingAddress(); + $shipping = $quote->isVirtual() ? null : $quote->getShippingAddress(); + + $customer = $quote->getCustomer(); + if (!$billing->getCustomerId() || $billing->getSaveInAddressBook()) { + $customerBilling = $billing->exportCustomerAddress(); + $customer->addAddress($customerBilling); + $billing->setCustomerAddress($customerBilling); + } + if ($shipping && ((!$shipping->getCustomerId() && !$shipping->getSameAsBilling()) + || (!$shipping->getSameAsBilling() && $shipping->getSaveInAddressBook()))) { + $customerShipping = $shipping->exportCustomerAddress(); + $customer->addAddress($customerShipping); + $shipping->setCustomerAddress($customerShipping); + } + + if (isset($customerBilling) && !$customer->getDefaultBilling()) { + $customerBilling->setIsDefaultBilling(true); + } + if ($shipping && isset($customerShipping) && !$customer->getDefaultShipping()) { + $customerShipping->setIsDefaultShipping(true); + } else if (isset($customerBilling) && !$customer->getDefaultShipping()) { + $customerBilling->setIsDefaultShipping(true); + } + $quote->setCustomer($customer); + + return $this; + } + + /** + * Involve new customer to system + * + * @param Mage_Sales_Model_Quote $quote + * @return Mage_Checkout_Model_Api_Resource_Customer + */ + public function involveNewCustomer(Mage_Sales_Model_Quote $quote) + { + $customer = $quote->getCustomer(); + if ($customer->isConfirmationRequired()) { + $customer->sendNewAccountEmail('confirmation'); + } else { + $customer->sendNewAccountEmail(); + } + + return $this; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Api/Resource/Product.php b/app/code/core/Mage/Checkout/Model/Api/Resource/Product.php new file mode 100644 index 00000000000..c46cc692935 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Api/Resource/Product.php @@ -0,0 +1,128 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * API Resource class for product + */ +class Mage_Checkout_Model_Api_Resource_Product extends Mage_Checkout_Model_Api_Resource +{ + /** + * Default ignored attribute codes + * + * @var array + */ + protected $_ignoredAttributeCodes = array('entity_id', 'attribute_set_id', 'entity_type_id'); + + /** + * Return loaded product instance + * + * @param int|string $productId (SKU or ID) + * @param int|string $store + * @param string $identifierType + * @return Mage_Catalog_Model_Product + */ + protected function _getProduct($productId, $store = null, $identifierType = null) + { + $product = Mage::helper('Mage_Catalog_Helper_Product')->getProduct($productId, + $this->_getStoreId($store), + $identifierType + ); + return $product; + } + + /** + * Get request for product add to cart procedure + * + * @param mixed $requestInfo + * @return Varien_Object + */ + protected function _getProductRequest($requestInfo) + { + if ($requestInfo instanceof Varien_Object) { + $request = $requestInfo; + } elseif (is_numeric($requestInfo)) { + $request = new Varien_Object(); + $request->setQty($requestInfo); + } else { + $request = new Varien_Object($requestInfo); + } + + if (!$request->hasQty()) { + $request->setQty(1); + } + return $request; + } + + /** + * Get QuoteItem by Product and request info + * + * @param Mage_Sales_Model_Quote $quote + * @param Mage_Catalog_Model_Product $product + * @param Varien_Object $requestInfo + * @return Mage_Sales_Model_Quote_Item + * @throw Mage_Core_Exception + */ + protected function _getQuoteItemByProduct(Mage_Sales_Model_Quote $quote, + Mage_Catalog_Model_Product $product, + Varien_Object $requestInfo) + { + $cartCandidates = $product->getTypeInstance() + ->prepareForCartAdvanced($requestInfo, + $product, + Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_FULL + ); + + /** + * Error message + */ + if (is_string($cartCandidates)) { + throw Mage::throwException($cartCandidates); + } + + /** + * If prepare process return one object + */ + if (!is_array($cartCandidates)) { + $cartCandidates = array($cartCandidates); + } + + /** @var $item Mage_Sales_Model_Quote_Item */ + $item = null; + foreach ($cartCandidates as $candidate) { + if ($candidate->getParentProductId()) { + continue; + } + + $item = $quote->getItemByProduct($candidate); + } + + if (is_null($item)) { + $item = Mage::getModel('Mage_Sales_Model_Quote_Item'); + } + + return $item; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Api.php b/app/code/core/Mage/Checkout/Model/Cart/Api.php new file mode 100644 index 00000000000..7eb79c58f64 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Api.php @@ -0,0 +1,366 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Api extends Mage_Checkout_Model_Api_Resource +{ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + parent::__construct($apiHelper); + $this->_storeIdSessionField = "cart_store_id"; + $this->_attributesMap['quote'] = array('quote_id' => 'entity_id'); + $this->_attributesMap['quote_customer'] = array('customer_id' => 'entity_id'); + $this->_attributesMap['quote_address'] = array('address_id' => 'entity_id'); + $this->_attributesMap['quote_payment'] = array('payment_id' => 'entity_id'); + } + + /** + * Prepare payment data for futher usage + * + * @param array $data + * @return array + */ + protected function _preparePaymentData($data) + { + if (!(is_array($data) && is_null($data[0]))) { + return array(); + } + + return $data; + } + + /** + * Create new quote for shopping cart + * + * @param int|string $store + * @return int + */ + public function create($store = null) + { + $storeId = $this->_getStoreId($store); + + try { + /*@var $quote Mage_Sales_Model_Quote*/ + $quote = Mage::getModel('Mage_Sales_Model_Quote'); + $quote->setStoreId($storeId) + ->setIsActive(false) + ->setIsMultiShipping(false) + ->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('create_quote_fault', $e->getMessage()); + } + return (int) $quote->getId(); + } + + /** + * Retrieve full information about quote + * + * @param $quoteId + * @param $store + * @return array + */ + public function info($quoteId, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + + if ($quote->getGiftMessageId() > 0) { + $quote->setGiftMessage( + Mage::getSingleton('Mage_GiftMessage_Model_Message')->load($quote->getGiftMessageId())->getMessage() + ); + } + + $result = $this->_getAttributes($quote, 'quote'); + $result['shipping_address'] = $this->_getAttributes($quote->getShippingAddress(), 'quote_address'); + $result['billing_address'] = $this->_getAttributes($quote->getBillingAddress(), 'quote_address'); + $result['items'] = array(); + + foreach ($quote->getAllItems() as $item) { + if ($item->getGiftMessageId() > 0) { + $item->setGiftMessage( + Mage::getSingleton('Mage_GiftMessage_Model_Message')->load($item->getGiftMessageId())->getMessage() + ); + } + + $result['items'][] = $this->_getAttributes($item, 'quote_item'); + } + + $result['payment'] = $this->_getAttributes($quote->getPayment(), 'quote_payment'); + + return $result; + } + + /** + * @param $quoteId + * @param $store + * @return void + */ + public function totals($quoteId, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + + $totals = $quote->getTotals(); + + $totalsResult = array(); + foreach ($totals as $total) { + $totalsResult[] = array( + "title" => $total->getTitle(), + "amount" => $total->getValue() + ); + } + return $totalsResult; + } + + /** + * Check wether we can use this payment method with current quote + * + * @param Mage_Payment_Model_Method_Abstract $method + * @param Mage_Sales_Model_Quote $quote + * @return bool + */ + protected function _canUsePaymentMethod($method, $quote) + { + if (!($method->isGateway() || $method->canUseInternal())) { + return false; + } + + if (!$method->canUseForCountry($quote->getBillingAddress()->getCountry())) { + return false; + } + + if (!$method->canUseForCurrency(Mage::app()->getStore($quote->getStoreId())->getBaseCurrencyCode())) { + return false; + } + + /** + * Checking for min/max order total for assigned payment method + */ + $total = $quote->getBaseGrandTotal(); + $minTotal = $method->getConfigData('min_order_total'); + $maxTotal = $method->getConfigData('max_order_total'); + + if ((!empty($minTotal) && ($total < $minTotal)) || (!empty($maxTotal) && ($total > $maxTotal))) { + return false; + } + + return true; + } + + /** + * Create an order from the shopping cart (quote) + * + * @param int $quoteId + * @param string|int $store + * @param array $agreements + * @return string + */ + public function createOrder($quoteId, $store = null, $agreements = null) + { + $this->_checkAgreement($agreements); + $quote = $this->_getQuote($quoteId, $store); + $orderId = $this->_placeOrder($quote); + return $orderId; + } + + /** + * Create an order from the shopping cart (quote) with ability to set payment method + * + * @param int $quoteId + * @param string|int $store + * @param array $agreements + * @param array $paymentData + * @return string + */ + public function createOrderWithPayment($quoteId, $store = null, $agreements = null, $paymentData = null) + { + $this->_checkAgreement($agreements); + $quote = $this->_getQuote($quoteId, $store); + $this->_setPayment($quote, $store, $paymentData); + $orderId = $this->_placeOrder($quote); + return $orderId; + } + + /** + * Convert quote to order and return order increment id + * + * @param Mage_Sales_Model_Quote $quote + * @return string + */ + protected function _placeOrder($quote) + { + if ($quote->getIsMultiShipping()) { + $this->_fault('invalid_checkout_type'); + } + if ($quote->getCheckoutMethod() == Mage_Checkout_Model_Api_Resource_Customer::MODE_GUEST + && !Mage::helper('Mage_Checkout_Helper_Data')->isAllowedGuestCheckout($quote, $quote->getStoreId()) + ) { + $this->_fault('guest_checkout_is_not_enabled'); + } + + Mage::getConfig()->setCurrentAreaCode('adminhtml'); + /** @var $customerResource Mage_Checkout_Model_Api_Resource_Customer */ + $customerResource = Mage::getModel("Mage_Checkout_Model_Api_Resource_Customer"); + $isNewCustomer = $customerResource->prepareCustomerForQuote($quote); + + try { + $quote->collectTotals(); + /** @var $service Mage_Sales_Model_Service_Quote */ + $service = Mage::getModel('Mage_Sales_Model_Service_Quote', array('quote' => $quote)); + $service->submitAll(); + + if ($isNewCustomer) { + try { + $customerResource->involveNewCustomer($quote); + } catch (Exception $e) { + Mage::logException($e); + } + } + + $order = $service->getOrder(); + if ($order) { + Mage::dispatchEvent( + 'checkout_type_onepage_save_order_after', + array('order' => $order, 'quote' => $quote) + ); + + try { + $order->sendNewOrderEmail(); + } catch (Exception $e) { + Mage::logException($e); + } + } + + Mage::dispatchEvent('checkout_submit_all_after', array('order' => $order, 'quote' => $quote)); + } catch (Mage_Core_Exception $e) { + $this->_fault('create_order_fault', $e->getMessage()); + } + + return $order->getIncrementId(); + } + + /** + * Set payment data + * + * @param Mage_Sales_Model_Quote $quote + * @param string|int $store + * @param array $paymentData + */ + protected function _setPayment($quote, $store = null, $paymentData = null) + { + if ($paymentData !== null) { + $paymentData = $this->_preparePaymentData($paymentData); + if (empty($paymentData)) { + $this->_fault('payment_method_empty'); + } + + if ($quote->isVirtual()) { + // check if billing address is set + if (is_null($quote->getBillingAddress()->getId())) { + $this->_fault('billing_address_is_not_set'); + } + $quote->getBillingAddress() + ->setPaymentMethod(isset($paymentData['method']) ? $paymentData['method'] : null); + } else { + // check if shipping address is set + if (is_null($quote->getShippingAddress()->getId()) ) { + $this->_fault('shipping_address_is_not_set'); + } + $quote->getShippingAddress() + ->setPaymentMethod(isset($paymentData['method']) ? $paymentData['method'] : null); + } + + if (!$quote->isVirtual() && $quote->getShippingAddress()) { + $quote->getShippingAddress()->setCollectShippingRates(true); + } + + $total = $quote->getBaseSubtotal(); + $methods = Mage::helper('Mage_Payment_Helper_Data')->getStoreMethods($store, $quote); + foreach ($methods as $key => $method) { + if ($method->getCode() == $paymentData['method']) { + /** @var $method Mage_Payment_Model_Method_Abstract */ + if (!($this->_canUsePaymentMethod($method, $quote) && ($total != 0 || $method->getCode() == 'free' + || ($quote->hasRecurringItems() && $method->canManageRecurringProfiles()))) + ) { + $this->_fault('method_not_allowed'); + } + } + } + try { + $quote->getPayment()->importData($paymentData); + $quote->setTotalsCollectedFlag(false)->collectTotals(); + } catch (Mage_Core_Exception $e) { + $this->_fault('payment_method_is_not_set', $e->getMessage()); + } + } + } + + /** + * Check required billing agreements + * + * @param array $agreements + */ + protected function _checkAgreement($agreements = null) + { + $requiredAgreements = Mage::helper('Mage_Checkout_Helper_Data')->getRequiredAgreementIds(); + if (!empty($requiredAgreements)) { + $diff = array_diff($agreements, $requiredAgreements); + if (!empty($diff)) { + $this->_fault('required_agreements_are_not_all'); + } + } + } + + /** + * @param $quoteId + * @param $store + * @return array + */ + public function licenseAgreement($quoteId, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + $storeId = $quote->getStoreId(); + + $agreements = array(); + if (Mage::getStoreConfigFlag('checkout/options/enable_agreements')) { + $agreementsCollection = Mage::getModel('Mage_Checkout_Model_Agreement')->getCollection() + ->addStoreFilter($storeId) + ->addFieldToFilter('is_active', 1); + + foreach ($agreementsCollection as $_a) { + /** @var $_a Mage_Checkout_Model_Agreement */ + $agreements[] = $this->_getAttributes($_a, "quote_agreement"); + } + } + + return $agreements; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Api/V2.php b/app/code/core/Mage/Checkout/Model/Cart/Api/V2.php new file mode 100644 index 00000000000..0b964922b2c --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Api/V2.php @@ -0,0 +1,47 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart model + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Checkout_Model_Cart_Api_V2 extends Mage_Checkout_Model_Cart_Api +{ + /** + * Prepare payment data for further usage + * + * @param array $data + * @return array + */ + protected function _preparePaymentData($data) + { + $data = get_object_vars($data); + return parent::_preparePaymentData($data); + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Coupon/Api.php b/app/code/core/Mage/Checkout/Model/Cart/Coupon/Api.php new file mode 100644 index 00000000000..32d7ad1981c --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Coupon/Api.php @@ -0,0 +1,97 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Coupon_Api extends Mage_Checkout_Model_Api_Resource +{ + /** + * @param $quoteId + * @param $couponCode + * @param $store + * @return bool + */ + public function add($quoteId, $couponCode, $store = null) + { + return $this->_applyCoupon($quoteId, $couponCode, $store = null); + } + + /** + * @param $quoteId + * @param $store + * @return bool + */ + public function remove($quoteId, $store = null) + { + $couponCode = ''; + return $this->_applyCoupon($quoteId, $couponCode, $store); + } + + /** + * @param $quoteId + * @param $couponCode + * @param $store + * @return bool + */ + protected function _applyCoupon($quoteId, $couponCode, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + + if (!$quote->getItemsCount()) { + $this->_fault('quote_is_empty'); + } + + $oldCouponCode = $quote->getCouponCode(); + if (!strlen($couponCode) && !strlen($oldCouponCode)) { + return false; + } + + try { + $quote->getShippingAddress()->setCollectShippingRates(true); + $quote->setCouponCode(strlen($couponCode) ? $couponCode : '') + ->collectTotals() + ->save(); + } catch (Exception $e) { + $this->_fault("cannot_apply_coupon_code", $e->getMessage()); + } + + if ($couponCode) { + if (!$couponCode == $quote->getCouponCode()) { + $this->_fault('coupon_code_is_not_valid'); + } + } + + return true; + } + + +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Coupon/Api/V2.php b/app/code/core/Mage/Checkout/Model/Cart/Coupon/Api/V2.php new file mode 100644 index 00000000000..2867f6ec043 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Coupon/Api/V2.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Coupon_Api_V2 extends Mage_Checkout_Model_Cart_Coupon_Api +{ + +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Customer/Api.php b/app/code/core/Mage/Checkout/Model/Cart/Customer/Api.php new file mode 100644 index 00000000000..e5248395e02 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Customer/Api.php @@ -0,0 +1,232 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api for customer data + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Checkout_Model_Cart_Customer_Api extends Mage_Checkout_Model_Api_Resource_Customer +{ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + parent::__construct($apiHelper); + $this->_storeIdSessionField = "cart_store_id"; + + $this->_attributesMap['quote'] = array('quote_id' => 'entity_id'); + $this->_attributesMap['quote_customer'] = array('customer_id' => 'entity_id'); + $this->_attributesMap['quote_address'] = array('address_id' => 'entity_id'); + } + + /** + * Set customer for shopping cart + * + * @param int $quoteId + * @param array|object $customerData + * @param int | string $store + * @return int + */ + public function set($quoteId, $customerData, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + + $customerData = $this->_prepareCustomerData($customerData); + if (!isset($customerData['mode'])) { + $this->_fault('customer_mode_is_unknown'); + } + + switch ($customerData['mode']) { + case self::MODE_CUSTOMER: + /** @var Mage_Customer_Model_Customer $customer */ + $customer = $this->_getCustomer($customerData['entity_id']); + $customer->setMode(self::MODE_CUSTOMER); + break; + case self::MODE_REGISTER: + case self::MODE_GUEST: + /** @var Mage_Customer_Model_Customer $customer */ + $customer = Mage::getModel('Mage_Customer_Model_Customer')->setData($customerData); + + if ($customer->getMode() == self::MODE_GUEST) { + $password = $customer->generatePassword(); + $customer->setPassword($password) + ->setConfirmation($password); + } + + $isCustomerValid = $customer->validate(); + if ($isCustomerValid !== true && is_array($isCustomerValid)) { + $this->_fault('customer_data_invalid', implode(PHP_EOL, $isCustomerValid)); + } + break; + } + + try { + $quote->setCustomer($customer) + ->setCheckoutMethod($customer->getMode()) + ->setPasswordHash($customer->encryptPassword($customer->getPassword())) + ->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('customer_not_set', $e->getMessage()); + } + + return true; + } + + /** + * @param int $quoteId + * @param array of array|object $customerAddressData + * @param int|string $store + * @return int + */ + public function setAddresses($quoteId, $customerAddressData, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + + $customerAddressData = $this->_prepareCustomerAddressData($customerAddressData); + if (is_null($customerAddressData)) { + $this->_fault('customer_address_data_empty'); + } + + foreach ($customerAddressData as $addressItem) { +// switch($addressItem['mode']) { +// case self::ADDRESS_BILLING: + /** @var $address Mage_Sales_Model_Quote_Address */ + $address = Mage::getModel('Mage_Sales_Model_Quote_Address'); +// break; +// case self::ADDRESS_SHIPPING: +// /** @var $address Mage_Sales_Model_Quote_Address */ +// $address = Mage::getModel('Mage_Sales_Model_Quote_Address'); +// break; +// } + $addressMode = $addressItem['mode']; + unset($addressItem['mode']); + + if (!empty($addressItem['entity_id'])) { + $customerAddress = $this->_getCustomerAddress($addressItem['entity_id']); + if ($customerAddress->getCustomerId() != $quote->getCustomerId()) { + $this->_fault('address_not_belong_customer'); + } + $address->importCustomerAddress($customerAddress); + + } else { + $address->setData($addressItem); + } + + $address->implodeStreetAddress(); + + if (($validateRes = $address->validate())!==true) { + $this->_fault('customer_address_invalid', implode(PHP_EOL, $validateRes)); + } + + switch ($addressMode) { + case self::ADDRESS_BILLING: + $address->setEmail($quote->getCustomer()->getEmail()); + + if (!$quote->isVirtual()) { + $useCase = isset($addressItem['use_for_shipping']) ? (int)$addressItem['use_for_shipping'] : 0; + switch ($useCase) { + case 0: + $shippingAddress = $quote->getShippingAddress(); + $shippingAddress->setSameAsBilling(0); + break; + case 1: + $billingAddress = clone $address; + $billingAddress->unsAddressId()->unsAddressType(); + + $shippingAddress = $quote->getShippingAddress(); + $shippingMethod = $shippingAddress->getShippingMethod(); + $shippingAddress->addData($billingAddress->getData()) + ->setSameAsBilling(1) + ->setShippingMethod($shippingMethod) + ->setCollectShippingRates(true); + break; + } + } + $quote->setBillingAddress($address); + break; + + case self::ADDRESS_SHIPPING: + $address->setCollectShippingRates(true) + ->setSameAsBilling(0); + $quote->setShippingAddress($address); + break; + } + + } + + try { + $quote->collectTotals() + ->save(); + } catch (Exception $e) { + $this->_fault('address_is_not_set', $e->getMessage()); + } + + return true; + } + + /** + * Prepare customer entered data for implementing + * + * @param array $data + * @return array + */ + protected function _prepareCustomerData($data) + { + foreach ($this->_attributesMap['quote_customer'] as $attributeAlias => $attributeCode) { + if (isset($data[$attributeAlias])) { + $data[$attributeCode] = $data[$attributeAlias]; + unset($data[$attributeAlias]); + } + } + return $data; + } + + /** + * Prepare customer entered data for implementing + * + * @param array $data + * @return array + */ + protected function _prepareCustomerAddressData($data) + { + if (!is_array($data) || !is_array($data[0])) { + return null; + } + + $dataAddresses = array(); + foreach ($data as $addressItem) { + foreach ($this->_attributesMap['quote_address'] as $attributeAlias => $attributeCode) { + if (isset($addressItem[$attributeAlias])) { + $addressItem[$attributeCode] = $addressItem[$attributeAlias]; + unset($addressItem[$attributeAlias]); + } + } + $dataAddresses[] = $addressItem; + } + return $dataAddresses; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Customer/Api/V2.php b/app/code/core/Mage/Checkout/Model/Cart/Customer/Api/V2.php new file mode 100644 index 00000000000..1069273cd3c --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Customer/Api/V2.php @@ -0,0 +1,70 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shoping cart api for customer data + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Checkout_Model_Cart_Customer_Api_V2 extends Mage_Checkout_Model_Cart_Customer_Api +{ + /** + * Prepare customer entered data for implementing + * + * @param object $data + * @return array + */ + protected function _prepareCustomerData($data) + { + if (null !== ($_data = get_object_vars($data))) { + return parent::_prepareCustomerData($_data); + } + return array(); + } + + /** + * Prepare customer entered data for implementing + * + * @param object $data + * @return array + */ + protected function _prepareCustomerAddressData($data) + { + if (is_array($data)) { + $dataAddresses = array(); + foreach($data as $addressItem) { + if (null !== ($_addressItem = get_object_vars($addressItem))) { + $dataAddresses[] = $_addressItem; + } + } + return parent::_prepareCustomerAddressData($dataAddresses); + } + + return null; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Payment/Api.php b/app/code/core/Mage/Checkout/Model/Cart/Payment/Api.php new file mode 100644 index 00000000000..b26d0164dd6 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Payment/Api.php @@ -0,0 +1,200 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Payment_Api extends Mage_Checkout_Model_Api_Resource +{ + + /** + * Returns payment data or empty array in case it is not valid + * + * @param array $data + * @return array + */ + protected function _preparePaymentData($data) + { + if (!is_array($data)) { + return array(); + } + + return $data; + } + + /** + * @param $method + * @param $quote + * @return bool + */ + protected function _canUsePaymentMethod($method, $quote) + { + if ( !($method->isGateway() || $method->canUseInternal()) ) { + return false; + } + + if (!$method->canUseForCountry($quote->getBillingAddress()->getCountry())) { + return false; + } + + if (!$method->canUseForCurrency(Mage::app()->getStore($quote->getStoreId())->getBaseCurrencyCode())) { + return false; + } + + /** + * Checking for min/max order total for assigned payment method + */ + $total = $quote->getBaseGrandTotal(); + $minTotal = $method->getConfigData('min_order_total'); + $maxTotal = $method->getConfigData('max_order_total'); + + if ((!empty($minTotal) && ($total < $minTotal)) || (!empty($maxTotal) && ($total > $maxTotal))) { + return false; + } + + return true; + } + + protected function _getPaymentMethodAvailableCcTypes($method) + { + $ccTypes = Mage::getSingleton('Mage_Payment_Model_Config')->getCcTypes(); + $methodCcTypes = explode(',',$method->getConfigData('cctypes')); + foreach ($ccTypes as $code=>$title) { + if (!in_array($code, $methodCcTypes)) { + unset($ccTypes[$code]); + } + } + if (empty($ccTypes)) { + return null; + } + + return $ccTypes; + } + + /** + * Retrieve available payment methods for a quote + * + * @param int $quoteId + * @param int $store + * @return array + */ + public function getPaymentMethodsList($quoteId, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + $store = $quote->getStoreId(); + + $total = $quote->getBaseSubtotal(); + + $methodsResult = array(); + $methods = Mage::helper('Mage_Payment_Helper_Data')->getStoreMethods($store, $quote); + + foreach ($methods as $method) { + /** @var $method Mage_Payment_Model_Method_Abstract */ + if ($this->_canUsePaymentMethod($method, $quote)) { + $isRecurring = $quote->hasRecurringItems() && $method->canManageRecurringProfiles(); + + if ($total != 0 || $method->getCode() == 'free' || $isRecurring) { + $methodsResult[] = array( + 'code' => $method->getCode(), + 'title' => $method->getTitle(), + 'cc_types' => $this->_getPaymentMethodAvailableCcTypes($method), + ); + } + } + } + + return $methodsResult; + } + + /** + * @param $quoteId + * @param $paymentData + * @param $store + * @return bool + */ + public function setPaymentMethod($quoteId, $paymentData, $store=null) + { + $quote = $this->_getQuote($quoteId, $store); + $store = $quote->getStoreId(); + + $paymentData = $this->_preparePaymentData($paymentData); + + if (empty($paymentData)) { + $this->_fault("payment_method_empty"); + } + + if ($quote->isVirtual()) { + // check if billing address is set + if (is_null($quote->getBillingAddress()->getId()) ) { + $this->_fault('billing_address_is_not_set'); + } + $quote->getBillingAddress()->setPaymentMethod(isset($paymentData['method']) ? $paymentData['method'] : null); + } else { + // check if shipping address is set + if (is_null($quote->getShippingAddress()->getId()) ) { + $this->_fault('shipping_address_is_not_set'); + } + $quote->getShippingAddress()->setPaymentMethod(isset($paymentData['method']) ? $paymentData['method'] : null); + } + + if (!$quote->isVirtual() && $quote->getShippingAddress()) { + $quote->getShippingAddress()->setCollectShippingRates(true); + } + + $total = $quote->getBaseSubtotal(); + $methods = Mage::helper('Mage_Payment_Helper_Data')->getStoreMethods($store, $quote); + + foreach ($methods as $method) { + /** @var $method Mage_Payment_Model_Method_Abstract */ + if ($method->getCode() == $paymentData['method']) { + $isRecurring = $quote->hasRecurringItems() && $method->canManageRecurringProfiles(); + $isAllowedMethod = $total != 0 || $method->getCode() == 'free' || $isRecurring; + if (!$this->_canUsePaymentMethod($method, $quote) || !$isAllowedMethod) { + $this->_fault("method_not_allowed"); + } + } + } + + try { + $payment = $quote->getPayment(); + $payment->importData($paymentData); + + + $quote->setTotalsCollectedFlag(false) + ->collectTotals() + ->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('payment_method_is_not_set', $e->getMessage()); + } + return true; + } + +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Payment/Api/V2.php b/app/code/core/Mage/Checkout/Model/Cart/Payment/Api/V2.php new file mode 100644 index 00000000000..b3be46c0cbc --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Payment/Api/V2.php @@ -0,0 +1,45 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + + class Mage_Checkout_Model_Cart_Payment_Api_V2 extends Mage_Checkout_Model_Cart_Payment_Api +{ + protected function _preparePaymentData($data) + { + if (null !== ($_data = get_object_vars($data))) { + return parent::_preparePaymentData($_data); + } + + return array(); + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Product/Api.php b/app/code/core/Mage/Checkout/Model/Cart/Product/Api.php new file mode 100644 index 00000000000..077c8c69e18 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Product/Api.php @@ -0,0 +1,330 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api for product + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Product_Api extends Mage_Checkout_Model_Api_Resource_Product +{ + /** + * Base preparation of product data + * + * @param mixed $data + * @return null|array + */ + protected function _prepareProductsData($data) + { + return is_array($data) ? $data : null; + } + + /** + * @param $quoteId + * @param $productsData + * @param $store + * @return bool + */ + public function add($quoteId, $productsData, $store=null) + { + $quote = $this->_getQuote($quoteId, $store); + if (empty($store)) { + $store = $quote->getStoreId(); + } + + $productsData = $this->_prepareProductsData($productsData); + if (empty($productsData)) { + $this->_fault('invalid_product_data'); + } + + $errors = array(); + foreach ($productsData as $productItem) { + if (isset($productItem['product_id'])) { + $productByItem = $this->_getProduct($productItem['product_id'], $store, "id"); + } else if (isset($productItem['sku'])) { + $productByItem = $this->_getProduct($productItem['sku'], $store, "sku"); + } else { + $errors[] = Mage::helper('Mage_Checkout_Helper_Data')->__("One item of products do not have identifier or sku"); + continue; + } + + $productRequest = $this->_getProductRequest($productItem); + try { + $result = $quote->addProduct($productByItem, $productRequest); + if (is_string($result)) { + Mage::throwException($result); + } + } catch (Mage_Core_Exception $e) { + $errors[] = $e->getMessage(); + } + } + + if (!empty($errors)) { + $this->_fault("add_product_fault", implode(PHP_EOL, $errors)); + } + + try { + $quote->collectTotals()->save(); + } catch(Exception $e) { + $this->_fault("add_product_quote_save_fault", $e->getMessage()); + } + + return true; + } + + /** + * @param $quoteId + * @param $productsData + * @param $store + * @return bool + */ + public function update($quoteId, $productsData, $store=null) + { + $quote = $this->_getQuote($quoteId, $store); + if (empty($store)) { + $store = $quote->getStoreId(); + } + + $productsData = $this->_prepareProductsData($productsData); + if (empty($productsData)) { + $this->_fault('invalid_product_data'); + } + + $errors = array(); + foreach ($productsData as $productItem) { + if (isset($productItem['product_id'])) { + $productByItem = $this->_getProduct($productItem['product_id'], $store, "id"); + } else if (isset($productItem['sku'])) { + $productByItem = $this->_getProduct($productItem['sku'], $store, "sku"); + } else { + $errors[] = Mage::helper('Mage_Checkout_Helper_Data')->__("One item of products do not have identifier or sku"); + continue; + } + + /** @var $quoteItem Mage_Sales_Model_Quote_Item */ + $quoteItem = $this->_getQuoteItemByProduct($quote, $productByItem, + $this->_getProductRequest($productItem)); + if (is_null($quoteItem->getId())) { + $errors[] = Mage::helper('Mage_Checkout_Helper_Data')->__("One item of products is not belong any of quote item"); + continue; + } + + if ($productItem['qty'] > 0) { + $quoteItem->setQty($productItem['qty']); + } + } + + if (!empty($errors)) { + $this->_fault("update_product_fault", implode(PHP_EOL, $errors)); + } + + try { + $quote->save(); + } catch(Exception $e) { + $this->_fault("update_product_quote_save_fault", $e->getMessage()); + } + + return true; + } + + /** + * @param $quoteId + * @param $productsData + * @param $store + * @return bool + */ + public function remove($quoteId, $productsData, $store=null) + { + $quote = $this->_getQuote($quoteId, $store); + if (empty($store)) { + $store = $quote->getStoreId(); + } + + $productsData = $this->_prepareProductsData($productsData); + if (empty($productsData)) { + $this->_fault('invalid_product_data'); + } + + $errors = array(); + foreach ($productsData as $productItem) { + if (isset($productItem['product_id'])) { + $productByItem = $this->_getProduct($productItem['product_id'], $store, "id"); + } else if (isset($productItem['sku'])) { + $productByItem = $this->_getProduct($productItem['sku'], $store, "sku"); + } else { + $errors[] = Mage::helper('Mage_Checkout_Helper_Data')->__("One item of products do not have identifier or sku"); + continue; + } + + try { + /** @var $quoteItem Mage_Sales_Model_Quote_Item */ + $quoteItem = $this->_getQuoteItemByProduct($quote, $productByItem, + $this->_getProductRequest($productItem)); + if (is_null($quoteItem->getId())) { + $errors[] = Mage::helper('Mage_Checkout_Helper_Data')->__("One item of products is not belong any of quote item"); + continue; + } + $quote->removeItem($quoteItem->getId()); + } catch (Mage_Core_Exception $e) { + $errors[] = $e->getMessage(); + } + } + + if (!empty($errors)) { + $this->_fault("remove_product_fault", implode(PHP_EOL, $errors)); + } + + try { + $quote->save(); + } catch(Exception $e) { + $this->_fault("remove_product_quote_save_fault", $e->getMessage()); + } + + return true; + } + + /** + * @param $quoteId + * @param $store + * @return array + */ + public function items($quoteId, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + if (empty($store)) { + $store = $quote->getStoreId(); + } + + if (!$quote->getItemsCount()) { + return array(); + } + + $productsResult = array(); + foreach ($quote->getAllItems() as $item) { + /** @var $item Mage_Sales_Model_Quote_Item */ + $product = $item->getProduct(); + $productsResult[] = array( // Basic product data + 'product_id' => $product->getId(), + 'sku' => $product->getSku(), + 'name' => $product->getName(), + 'set' => $product->getAttributeSetId(), + 'type' => $product->getTypeId(), + 'category_ids' => $product->getCategoryIds(), + 'website_ids' => $product->getWebsiteIds() + ); + } + + return $productsResult; + } + + /** + * @param $quoteId + * @param $productsData + * @param $store + * @return bool + */ + public function moveToCustomerQuote($quoteId, $productsData, $store=null) + { + $quote = $this->_getQuote($quoteId, $store); + + if (empty($store)) { + $store = $quote->getStoreId(); + } + + $customer = $quote->getCustomer(); + if (is_null($customer->getId())) { + $this->_fault('customer_not_set_for_quote'); + } + + /** @var $customerQuote Mage_Sales_Model_Quote */ + $customerQuote = Mage::getModel('Mage_Sales_Model_Quote') + ->setStoreId($store) + ->loadByCustomer($customer); + + if (is_null($customerQuote->getId())) { + $this->_fault('customer_quote_not_exist'); + } + + if ($customerQuote->getId() == $quote->getId()) { + $this->_fault('quotes_are_similar'); + } + + $productsData = $this->_prepareProductsData($productsData); + if (empty($productsData)) { + $this->_fault('invalid_product_data'); + } + + $errors = array(); + foreach($productsData as $key => $productItem){ + if (isset($productItem['product_id'])) { + $productByItem = $this->_getProduct($productItem['product_id'], $store, "id"); + } else if (isset($productItem['sku'])) { + $productByItem = $this->_getProduct($productItem['sku'], $store, "sku"); + } else { + $errors[] = Mage::helper('Mage_Checkout_Helper_Data')->__("One item of products do not have identifier or sku"); + continue; + } + + try { + /** @var $quoteItem Mage_Sales_Model_Quote_Item */ + $quoteItem = $this->_getQuoteItemByProduct($quote, $productByItem, + $this->_getProductRequest($productItem)); + if($quoteItem && $quoteItem->getId()){ + $newQuoteItem = clone $quoteItem; + $newQuoteItem->setId(null); + $customerQuote->addItem($newQuoteItem); + $quote->removeItem($quoteItem->getId()); + unset($productsData[$key]); + } else { + $errors[] = Mage::helper('Mage_Checkout_Helper_Data')->__("One item of products is not belong any of quote item"); + } + } catch (Mage_Core_Exception $e) { + $errors[] = $e->getMessage(); + } + } + + if (count($productsData) || !empty($errors)) { + $this->_fault('unable_to_move_all_products', implode(PHP_EOL, $errors)); + } + + try { + $customerQuote + ->collectTotals() + ->save(); + + $quote + ->collectTotals() + ->save(); + } catch (Exception $e) { + $this->_fault("product_move_quote_save_fault", $e->getMessage()); + } + + return true; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Product/Api/V2.php b/app/code/core/Mage/Checkout/Model/Cart/Product/Api/V2.php new file mode 100644 index 00000000000..2994c9f5238 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Product/Api/V2.php @@ -0,0 +1,76 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api for product + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Product_Api_V2 extends Mage_Checkout_Model_Cart_Product_Api +{ + + /** + * Return an Array of Object attributes. + * + * @param Mixed $data + * @return Array + */ + protected function _prepareProductsData($data){ + if (is_object($data)) { + $arr = get_object_vars($data); + foreach ($arr as $key => $value) { + $assocArr = array(); + if (is_array($value)) { + foreach ($value as $v) { + if (is_object($v) && count(get_object_vars($v))==2 + && isset($v->key) && isset($v->value)) { + $assocArr[$v->key] = $v->value; + } + } + } + if (!empty($assocArr)) { + $arr[$key] = $assocArr; + } + } + $arr = $this->_prepareProductsData($arr); + return parent::_prepareProductsData($arr); + } + if (is_array($data)) { + foreach ($data as $key => $value) { + if (is_object($value) || is_array($value)) { + $data[$key] = $this->_prepareProductsData($value); + } else { + $data[$key] = $value; + } + } + return parent::_prepareProductsData($data); + } + return $data; + } +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Shipping/Api.php b/app/code/core/Mage/Checkout/Model/Cart/Shipping/Api.php new file mode 100644 index 00000000000..cf31b878945 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Shipping/Api.php @@ -0,0 +1,117 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Shipping_Api extends Mage_Checkout_Model_Api_Resource +{ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + parent::__construct($apiHelper); + $this->_ignoredAttributeCodes['quote_shipping_rate'] = array('address_id', 'created_at', 'updated_at', 'rate_id', 'carrier_sort_order'); + } + + /** + * Set an Shipping Method for Shopping Cart + * + * @param $quoteId + * @param $shippingMethod + * @param $store + * @return bool + */ + public function setShippingMethod($quoteId, $shippingMethod, $store = null) + { + $quote = $this->_getQuote($quoteId, $store); + + $quoteShippingAddress = $quote->getShippingAddress(); + if(is_null($quoteShippingAddress->getId()) ) { + $this->_fault("shipping_address_is_not_set"); + } + + $rate = $quote->getShippingAddress()->collectShippingRates()->getShippingRateByCode($shippingMethod); + if (!$rate) { + $this->_fault('shipping_method_is_not_available'); + } + + try { + $quote->getShippingAddress()->setShippingMethod($shippingMethod); + $quote->collectTotals()->save(); + } catch(Mage_Core_Exception $e) { + $this->_fault('shipping_method_is_not_set', $e->getMessage()); + } + + return true; + } + + /** + * Get list of available shipping methods + * + * @param $quoteId + * @param $store + * @return array + */ + public function getShippingMethodsList($quoteId, $store=null) + { + $quote = $this->_getQuote($quoteId, $store); + + $quoteShippingAddress = $quote->getShippingAddress(); + if (is_null($quoteShippingAddress->getId())) { + $this->_fault("shipping_address_is_not_set"); + } + + try { + $quoteShippingAddress->collectShippingRates()->save(); + $groupedRates = $quoteShippingAddress->getGroupedAllShippingRates(); + + $ratesResult = array(); + foreach ($groupedRates as $carrierCode => $rates ) { + $carrierName = $carrierCode; + if (!is_null(Mage::getStoreConfig('carriers/'.$carrierCode.'/title'))) { + $carrierName = Mage::getStoreConfig('carriers/'.$carrierCode.'/title'); + } + + foreach ($rates as $rate) { + $rateItem = $this->_getAttributes($rate, "quote_shipping_rate"); + $rateItem['carrierName'] = $carrierName; + $ratesResult[] = $rateItem; + unset($rateItem); + } + } + } catch (Mage_Core_Exception $e) { + $this->_fault('shipping_methods_list_could_not_be_retrived', $e->getMessage()); + } + + return $ratesResult; + } + + +} diff --git a/app/code/core/Mage/Checkout/Model/Cart/Shipping/Api/V2.php b/app/code/core/Mage/Checkout/Model/Cart/Shipping/Api/V2.php new file mode 100644 index 00000000000..5d7058852f6 --- /dev/null +++ b/app/code/core/Mage/Checkout/Model/Cart/Shipping/Api/V2.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Shopping cart api + * + * @category Mage + * @package Mage_Checkout + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Checkout_Model_Cart_Shipping_Api_V2 extends Mage_Checkout_Model_Cart_Shipping_Api +{ + +} diff --git a/app/code/core/Mage/Checkout/etc/api.xml b/app/code/core/Mage/Checkout/etc/api.xml new file mode 100644 index 00000000000..d3e73dab15a --- /dev/null +++ b/app/code/core/Mage/Checkout/etc/api.xml @@ -0,0 +1,536 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Checkout + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <cart translate="title" module="Mage_Checkout"> + <model>Mage_Checkout_Model_Cart_Api</model> + <title>Shopping Cart</title> + <acl>cart</acl> + <methods> + <create translate="title" module="Mage_Checkout"> + <title>Create shopping cart</title> + <method>create</method> + <acl>cart/create</acl> + </create> + <order translate="title" module="Mage_Checkout"> + <title>Create an order from shopping cart</title> + <method>createOrder</method> + <acl>cart/order</acl> + </order> + <orderWithPayment translate="title" module="Mage_Checkout"> + <title>Create an order from shopping cart with payment method</title> + <method>createOrderWithPayment</method> + <acl>cart/order</acl> + </orderWithPayment> + <info translate="title" module="Mage_Checkout"> + <title>Retrieve information about shopping cart</title> + <method>info</method> + <acl>cart/info</acl> + </info> + <totals translate="title" module="Mage_Checkout"> + <title>Get total prices for shopping cart</title> + <method>totals</method> + <acl>cart/totals</acl> + </totals> + <license translate="title" module="Mage_Checkout"> + <title>Get terms and conditions</title> + <method>licenseAgreement</method> + <acl>cart/license</acl> + </license> + </methods> + <faults module="Mage_Checkout"> + <store_not_exists> + <code>1001</code> + <message>Cannot perform operation because store does not exist.</message> + </store_not_exists> + <quote_not_exists> + <code>1002</code> + <message>Cannot perform operation because quote does not exist.</message> + </quote_not_exists> + <quote_create_fault> + <code>1003</code> + <message>Cannot create a quote. </message> + </quote_create_fault> + <quote_already_exists> + <code>1004</code> + <message>Cannot create a quote because quote with such ID already exists.</message> + </quote_already_exists> + <required_agreements_are_not_all> + <code>1005</code> + <message>Not all required agreements are set.</message> + </required_agreements_are_not_all> + <invalid_checkout_type> + <code>1006</code> + <message>The checkout type is not valid. Select single checkout type.</message> + </invalid_checkout_type> + <guest_checkout_is_not_enabled> + <code>1007</code> + <message>Checkout is not available for guest.</message> + </guest_checkout_is_not_enabled> + <create_order_fault> + <code>1008</code> + <message>Cannot create an order. </message> + </create_order_fault> + <payment_method_empty> + <code>1071</code> + <message>Payment method data is empty.</message> + </payment_method_empty> + <billing_address_is_not_set> + <code>1072</code> + <message>Customer billing address is not set and is required for payment method data.</message> + </billing_address_is_not_set> + <shipping_address_is_not_set> + <code>1073</code> + <message>Customer shipping address is not set and is required for payment method data.</message> + </shipping_address_is_not_set> + <method_not_allowed> + <code>1074</code> + <message>Payment method is not allowed.</message> + </method_not_allowed> + <payment_method_is_not_set> + <code>1075</code> + <message>Payment method is not set.</message> + </payment_method_is_not_set> + </faults> + </cart> + <cart_product translate="title" module="Mage_Checkout"> + <model>Mage_Checkout_Model_Cart_Product_Api</model> + <title>Cart Product API</title> + <acl>cart/product</acl> + <methods> + <add translate="title" module="Mage_Checkout"> + <title>Add product to shopping cart</title> + <method>add</method> + <acl>cart/product/add</acl> + </add> + <update translate="title" module="Mage_Checkout"> + <title>Update product quantities in shopping cart</title> + <method>update</method> + <acl>cart/product/update</acl> + </update> + <remove translate="title" module="Mage_Checkout"> + <title>Remove product from shopping cart</title> + <method>remove</method> + <acl>cart/product/remove</acl> + </remove> + <list translate="title" module="Mage_Checkout"> + <title>Get list of products in shopping cart</title> + <method>items</method> + <acl>cart/product/list</acl> + </list> + <moveToCustomerQuote> + <title>Move product(s) to customer quote</title> + <method>moveToCustomerQuote</method> + <acl>cart/product/moveToCustomerQuote</acl> + </moveToCustomerQuote> + </methods> + <faults module="Mage_Checkout"> + <store_not_exists> + <code>1001</code> + <message>Cannot perform operation because store does not exist.</message> + </store_not_exists> + <quote_not_exists> + <code>1002</code> + <message>Cannot perform operation because quote does not exist.</message> + </quote_not_exists> + <invalid_product_data> + <code>1021</code> + <message>Product data is not valid.</message> + </invalid_product_data> + <add_product_fault> + <code>1022</code> + <message>Product(s) could not be added. </message> + </add_product_fault> + <add_product_quote_save_fault> + <code>1023</code> + <message>Quote could not be saved during adding product(s) operation.</message> + </add_product_quote_save_fault> + <update_product_fault> + <code>1024</code> + <message>Product(s) could not be updated. </message> + </update_product_fault> + <update_product_quote_save_fault> + <code>1025</code> + <message>Quote could not be saved during updating product(s) operation.</message> + </update_product_quote_save_fault> + <remove_product_fault> + <code>1026</code> + <message>Product(s) could not be removed. </message> + </remove_product_fault> + <remove_product_quote_save_fault> + <code>1027</code> + <message>Quote could not be saved during removing product(s) operation.</message> + </remove_product_quote_save_fault> + <customer_not_set_for_quote> + <code>1028</code> + <message>Customer is not set for quote.</message> + </customer_not_set_for_quote> + <customer_quote_not_exist> + <code>1029</code> + <message>Customer quote does not exist.</message> + </customer_quote_not_exist> + <quotes_are_similar> + <code>1030</code> + <message>Quotes are identical.</message> + </quotes_are_similar> + <unable_to_move_all_products> + <code>1031</code> + <message>Product(s) could not be moved. </message> + </unable_to_move_all_products> + <product_move_quote_save_fault> + <code>1032</code> + <message>One of quotes could not be saved during moving product(s) operation.</message> + </product_move_quote_save_fault> + </faults> + </cart_product> + <cart_customer translate="title" module="Mage_Checkout"> + <model>Mage_Checkout_Model_Cart_Customer_Api</model> + <title>Customer Information</title> + <acl>cart/customer</acl> + <methods> + <set translate="title" module="Mage_Checkout"> + <title>Set customer for shopping cart</title> + <method>set</method> + <acl>cart/customer/set</acl> + </set> + <addresses translate="title" module="Mage_Checkout"> + <title>Set customer's addresses in shopping cart</title> + <method>setAddresses</method> + <acl>cart/customer/addresses</acl> + </addresses> + </methods> + <faults module="Mage_Checkout"> + <store_not_exists> + <code>1001</code> + <message>Cannot perform operation because store does not exist.</message> + </store_not_exists> + <quote_not_exists> + <code>1002</code> + <message>Cannot perform operation because quote does not exist.</message> + </quote_not_exists> + <customer_not_set> + <code>1041</code> + <message>Customer is not set. </message> + </customer_not_set> + <customer_not_exists> + <code>1042</code> + <message>The customer ID is not valid or customer does not exist.</message> + </customer_not_exists> + <customer_not_created> + <code>1043</code> + <message>Customer could not be created. </message> + </customer_not_created> + <customer_data_invalid> + <code>1044</code> + <message>Customer data is not valid. </message> + </customer_data_invalid> + <customer_mode_is_unknown> + <code>1045</code> + <message>Customer mode is unknown</message> + </customer_mode_is_unknown> + <customer_address_data_empty> + <code>1051</code> + <message>Customer address data is empty.</message> + </customer_address_data_empty> + <customer_address_invalid> + <code>1052</code> + <message>Customer address data is not valid.</message> + </customer_address_invalid> + <invalid_address_id> + <code>1053</code> + <message>The customer address ID is not valid</message> + </invalid_address_id> + <address_is_not_set> + <code>1054</code> + <message>Customer address is not set.</message> + </address_is_not_set> + <address_not_belong_customer> + <code>1055</code> + <message>Customer address ID does not belong to customer which is set in quote.</message> + </address_not_belong_customer> + </faults> + </cart_customer> + <cart_shipping translate="title" module="Mage_Checkout"> + <model>Mage_Checkout_Model_Cart_Shipping_Api</model> + <title>Shipping information</title> + <acl>cart/shipping</acl> + <methods> + <method translate="title" module="Mage_Checkout"> + <title>Set shipping method</title> + <method>setShippingMethod</method> + <acl>cart/shipping/method</acl> + </method> + <list translate="title" module="Mage_Checkout"> + <title>Get list of available shipping methods</title> + <method>getShippingMethodsList</method> + <acl>cart/shipping/list</acl> + </list> + </methods> + <faults module="Mage_Checkout"> + <store_not_exists> + <code>1001</code> + <message>Cannot perform operation because store does not exist.</message> + </store_not_exists> + <quote_not_exists> + <code>1002</code> + <message>Cannot perform operation because quote does not exist.</message> + </quote_not_exists> + <shipping_address_is_not_set> + <code>1061</code> + <message>Cannot perform operation because customer shipping address is not set.</message> + </shipping_address_is_not_set> + <shipping_method_is_not_available> + <code>1062</code> + <message>Shipping method is not available.</message> + </shipping_method_is_not_available> + <shipping_method_is_not_set> + <code>1063</code> + <message>Cannot set shipping method. </message> + </shipping_method_is_not_set> + <shipping_methods_list_could_not_be_retrived> + <code>1064</code> + <message>Cannot receive the list of shipping methods. </message> + </shipping_methods_list_could_not_be_retrived> + </faults> + </cart_shipping> + <cart_payment translate="title" module="Mage_Checkout"> + <model>Mage_Checkout_Model_Cart_Payment_Api</model> + <title>Payment method information</title> + <acl>cart/payment</acl> + <methods> + <method translate="title" module="Mage_Checkout"> + <title>Set payment method</title> + <method>setPaymentMethod</method> + <acl>cart/payment/method</acl> + </method> + <list translate="title" module="Mage_Checkout"> + <title>Get list of available payment methods</title> + <method>getPaymentMethodsList</method> + <acl>cart/payment/list</acl> + </list> + </methods> + <faults module="Mage_Checkout"> + <store_not_exists> + <code>1001</code> + <message>Cannot perform operation because store does not exist.</message> + </store_not_exists> + <quote_not_exists> + <code>1002</code> + <message>Cannot perform operation because quote does not exist.</message> + </quote_not_exists> + <payment_method_empty> + <code>1071</code> + <message>Payment method data is empty.</message> + </payment_method_empty> + <billing_address_is_not_set> + <code>1072</code> + <message>Customer billing address is not set. It is required for payment method data.</message> + </billing_address_is_not_set> + <shipping_address_is_not_set> + <code>1073</code> + <message>Customer shipping address is not set. It is required for payment method data.</message> + </shipping_address_is_not_set> + <method_not_allowed> + <code>1074</code> + <message>Payment method is not allowed.</message> + </method_not_allowed> + <payment_method_is_not_set> + <code>1075</code> + <message>Payment method is not set. </message> + </payment_method_is_not_set> + </faults> + </cart_payment> + <cart_coupon translate="title" module="Mage_Checkout"> + <model>Mage_Checkout_Model_Cart_Coupon_Api</model> + <title>Shopping cart ability to set coupon code</title> + <acl>cart/coupon</acl> + <methods> + <add translate="title" module="Mage_Checkout"> + <title>Add coupon code for shopping cart</title> + <method>add</method> + <acl>cart/coupon/add</acl> + </add> + <remove translate="title" module="Mage_Checkout"> + <title>Remove coupon code from shopping cart</title> + <method>remove</method> + <acl>cart/coupon/remove</acl> + </remove> + </methods> + <faults module="Mage_Checkout"> + <store_not_exists> + <code>1001</code> + <message>Cannot perform operation because store does not exist.</message> + </store_not_exists> + <quote_not_exists> + <code>1002</code> + <message>Cannot perform operation because quote does not exist.</message> + </quote_not_exists> + <quote_is_empty> + <code>1081</code> + <message>Coupon could not be applied because quote is empty.</message> + </quote_is_empty> + <cannot_apply_coupon_code> + <code>1082</code> + <message>Coupon could not be applied.</message> + </cannot_apply_coupon_code> + <coupon_code_is_not_valid> + <code>1083</code> + <message>Coupon is not valid.</message> + </coupon_code_is_not_valid> + </faults> + </cart_coupon> + </resources> + <resources_alias> + <cart_customer_address>cart_customer</cart_customer_address> + </resources_alias> + <rest> + <mapping> + <cart_product> + <post> + <method>add</method> + </post> + <delete> + <method>remove</method> + </delete> + </cart_product> + <cart_shipping> + <post> + <method>method</method> + </post> + </cart_shipping> + <cart_payment> + <post> + <method>method</method> + </post> + </cart_payment> + <cart_customer> + <post> + <method>set</method> + </post> + </cart_customer> + <cart_customer_address> + <post> + <method>addresses</method> + </post> + </cart_customer_address> + <cart_payment> + <post> + <method>method</method> + </post> + </cart_payment> + </mapping> + </rest> + <acl> + <resources> + <cart translate="title" module="Mage_Checkout"> + <title>Shopping Cart</title> + <create translate="title" module="Mage_Checkout"> + <title>Create shopping cart</title> + </create> + <order translate="title" module="Mage_Checkout"> + <title>Create an order from shopping cart</title> + </order> + <info translate="title" module="Mage_Checkout"> + <title>Retrieve information about shopping cart</title> + </info> + <totals translate="title" module="Mage_Checkout"> + <title>Get total prices for shopping cart</title> + </totals> + <license translate="title" module="Mage_Checkout"> + <title>Get terms and conditions</title> + </license> + <product translate="title" module="Mage_Checkout"> + <title>Products</title> + <add translate="title" module="Mage_Checkout"> + <title>Add product(s) to shopping cart</title> + </add> + <update translate="title" module="Mage_Checkout"> + <title>Update product(s) quantities in shopping cart</title> + </update> + <remove translate="title" module="Mage_Checkout"> + <title>Remove product(s) from shopping cart</title> + </remove> + <list translate="title" module="Mage_Checkout"> + <title>Get list of products in shopping cart</title> + </list> + <moveToCustomerQuote> + <title>Move product(s) to customer quote</title> + </moveToCustomerQuote> + </product> + <customer translate="title" module="Mage_Checkout"> + <title>Customer's information</title> + <set translate="title" module="Mage_Checkout"> + <title>Set customer for shopping cart</title> + </set> + <addresses translate="title" module="Mage_Checkout"> + <title>Set customer's addresses in shopping cart</title> + </addresses> + </customer> + <shipping translate="title" module="Mage_Checkout"> + <title>Shipping methods in shopping cart</title> + <method translate="title" module="Mage_Checkout"> + <title>Set shipping method</title> + </method> + <list translate="title" module="Mage_Checkout"> + <title>Get list of available shipping methods</title> + </list> + </shipping> + <payment translate="title" module="Mage_Checkout"> + <title>Payment methods in shopping cart</title> + <method translate="title" module="Mage_Checkout"> + <title>Set payment method</title> + </method> + <list translate="title" module="Mage_Checkout"> + <title>Get list of available payment methods</title> + </list> + </payment> + <coupon> + <title>Shopping cart ability to set coupon code</title> + <add> + <title>Add coupon code for shopping cart</title> + </add> + <remove> + <title>Remove coupon code from shopping cart</title> + </remove> + </coupon> + </cart> + </resources> + </acl> + <v2> + <resources_function_prefix> + <cart>shoppingCart</cart> + <cart_product>shoppingCartProduct</cart_product> + <cart_customer>shoppingCartCustomer</cart_customer> + <cart_shipping>shoppingCartShipping</cart_shipping> + <cart_payment>shoppingCartPayment</cart_payment> + <cart_coupon>shoppingCartCoupon</cart_coupon> + </resources_function_prefix> + </v2> + </api> +</config> diff --git a/app/code/core/Mage/Checkout/etc/wsdl.xml b/app/code/core/Mage/Checkout/etc/wsdl.xml new file mode 100644 index 00000000000..7102732f4ef --- /dev/null +++ b/app/code/core/Mage/Checkout/etc/wsdl.xml @@ -0,0 +1,805 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <complexType name="shoppingCartAddressEntity"> + <all> + <element name="address_id" type="xsd:string" minOccurs="0"/> + <element name="created_at" type="xsd:string" minOccurs="0"/> + <element name="updated_at" type="xsd:string" minOccurs="0"/> + <element name="customer_id" type="xsd:string" minOccurs="0"/> + <element name="save_in_address_book" type="xsd:int" minOccurs="0"/> + <element name="customer_address_id" type="xsd:string" minOccurs="0"/> + <element name="address_type" type="xsd:string" minOccurs="0"/> + <element name="email" type="xsd:string" minOccurs="0"/> + <element name="prefix" type="xsd:string" minOccurs="0"/> + <element name="firstname" type="xsd:string" minOccurs="0"/> + <element name="middlename" type="xsd:string" minOccurs="0"/> + <element name="lastname" type="xsd:string" minOccurs="0"/> + <element name="suffix" type="xsd:string" minOccurs="0"/> + <element name="company" type="xsd:string" minOccurs="0"/> + <element name="street" type="xsd:string" minOccurs="0"/> + <element name="city" type="xsd:string" minOccurs="0"/> + <element name="region" type="xsd:string" minOccurs="0"/> + <element name="region_id" type="xsd:string" minOccurs="0"/> + <element name="postcode" type="xsd:string" minOccurs="0"/> + <element name="country_id" type="xsd:string" minOccurs="0"/> + <element name="telephone" type="xsd:string" minOccurs="0"/> + <element name="fax" type="xsd:string" minOccurs="0"/> + <element name="same_as_billing" type="xsd:int" minOccurs="0"/> + <element name="free_shipping" type="xsd:int" minOccurs="0"/> + <element name="shipping_method" type="xsd:string" minOccurs="0"/> + <element name="shipping_description" type="xsd:string" minOccurs="0"/> + <element name="weight" type="xsd:double" minOccurs="0"/> + <element name="fax" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartItemEntity"> + <all> + <element name="item_id" type="xsd:string" minOccurs="0"/> + <element name="created_at" type="xsd:string" minOccurs="0"/> + <element name="updated_at" type="xsd:string" minOccurs="0"/> + <element name="product_id" type="xsd:string" minOccurs="0"/> + <element name="store_id" type="xsd:string" minOccurs="0"/> + <element name="parent_item_id" type="xsd:string" minOccurs="0"/> + <element name="is_virtual" type="xsd:int" minOccurs="0"/> + <element name="sku" type="xsd:string" minOccurs="0"/> + <element name="name" type="xsd:string" minOccurs="0"/> + <element name="description" type="xsd:string" minOccurs="0"/> + <element name="applied_rule_ids" type="xsd:string" minOccurs="0"/> + <element name="additional_data" type="xsd:string" minOccurs="0"/> + <element name="free_shipping" type="xsd:string" minOccurs="0"/> + <element name="is_qty_decimal" type="xsd:string" minOccurs="0"/> + <element name="no_discount" type="xsd:string" minOccurs="0"/> + <element name="weight" type="xsd:double" minOccurs="0"/> + <element name="qty" type="xsd:double" minOccurs="0"/> + <element name="price" type="xsd:double" minOccurs="0"/> + <element name="base_price" type="xsd:double" minOccurs="0"/> + <element name="custom_price" type="xsd:double" minOccurs="0"/> + <element name="discount_percent" type="xsd:double" minOccurs="0"/> + <element name="discount_amount" type="xsd:double" minOccurs="0"/> + <element name="base_discount_amount" type="xsd:double" minOccurs="0"/> + <element name="tax_percent" type="xsd:double" minOccurs="0"/> + <element name="tax_amount" type="xsd:double" minOccurs="0"/> + <element name="base_tax_amount" type="xsd:double" minOccurs="0"/> + <element name="row_total" type="xsd:double" minOccurs="0"/> + <element name="base_row_total" type="xsd:double" minOccurs="0"/> + <element name="row_total_with_discount" type="xsd:double" minOccurs="0"/> + <element name="row_weight" type="xsd:double" minOccurs="0"/> + <element name="product_type" type="xsd:string" minOccurs="0"/> + <element name="base_tax_before_discount" type="xsd:double" minOccurs="0"/> + <element name="tax_before_discount" type="xsd:double" minOccurs="0"/> + <element name="original_custom_price" type="xsd:double" minOccurs="0"/> + <element name="base_cost" type="xsd:double" minOccurs="0"/> + <element name="price_incl_tax" type="xsd:double" minOccurs="0"/> + <element name="base_price_incl_tax" type="xsd:double" minOccurs="0"/> + <element name="row_total_incl_tax" type="xsd:double" minOccurs="0"/> + <element name="base_row_total_incl_tax" type="xsd:double" minOccurs="0"/> + <element name="gift_message_id" type="xsd:string" minOccurs="0"/> + <element name="gift_message" type="xsd:string" minOccurs="0"/> + <element name="gift_message_available" type="xsd:string" minOccurs="0"/> + <element name="weee_tax_applied" type="xsd:double" minOccurs="0"/> + <element name="weee_tax_applied_amount" type="xsd:double" minOccurs="0"/> + <element name="weee_tax_applied_row_amount" type="xsd:double" minOccurs="0"/> + <element name="base_weee_tax_applied_amount" type="xsd:double" minOccurs="0"/> + <element name="base_weee_tax_applied_row_amnt" type="xsd:double" minOccurs="0"/> + <element name="weee_tax_disposition" type="xsd:double" minOccurs="0"/> + <element name="weee_tax_row_disposition" type="xsd:double" minOccurs="0"/> + <element name="base_weee_tax_disposition" type="xsd:double" minOccurs="0"/> + <element name="base_weee_tax_row_disposition" type="xsd:double" minOccurs="0"/> + <element name="tax_class_id" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartItemEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:shoppingCartItemEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="shoppingCartPaymentEntity"> + <all> + <element name="payment_id" type="xsd:string" minOccurs="0"/> + <element name="created_at" type="xsd:string" minOccurs="0"/> + <element name="updated_at" type="xsd:string" minOccurs="0"/> + <element name="method" type="xsd:string" minOccurs="0"/> + <element name="cc_type" type="xsd:string" minOccurs="0"/> + <element name="cc_number_enc" type="xsd:string" minOccurs="0"/> + <element name="cc_last4" type="xsd:string" minOccurs="0"/> + <element name="cc_cid_enc" type="xsd:string" minOccurs="0"/> + <element name="cc_owner" type="xsd:string" minOccurs="0"/> + <element name="cc_exp_month" type="xsd:string" minOccurs="0"/> + <element name="cc_exp_year" type="xsd:string" minOccurs="0"/> + <element name="cc_ss_owner" type="xsd:string" minOccurs="0"/> + <element name="cc_ss_start_month" type="xsd:string" minOccurs="0"/> + <element name="cc_ss_start_year" type="xsd:string" minOccurs="0"/> + <element name="cc_ss_issue" type="xsd:string" minOccurs="0"/> + <element name="po_number" type="xsd:string" minOccurs="0"/> + <element name="additional_data" type="xsd:string" minOccurs="0"/> + <element name="additional_information" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartInfoEntity"> + <all> + <element name="store_id" type="xsd:string" minOccurs="0"/> + <element name="created_at" type="xsd:string" minOccurs="0"/> + <element name="updated_at" type="xsd:string" minOccurs="0"/> + <element name="converted_at" type="xsd:string" minOccurs="0"/> + <element name="quote_id" type="xsd:int" minOccurs="0"/> + <element name="is_active" type="xsd:int" minOccurs="0"/> + <element name="is_virtual" type="xsd:int" minOccurs="0"/> + <element name="is_multi_shipping" type="xsd:int" minOccurs="0"/> + <element name="items_count" type="xsd:double" minOccurs="0"/> + <element name="items_qty" type="xsd:double" minOccurs="0"/> + <element name="orig_order_id" type="xsd:string" minOccurs="0"/> + <element name="store_to_base_rate" type="xsd:string" minOccurs="0"/> + <element name="store_to_quote_rate" type="xsd:string" minOccurs="0"/> + <element name="base_currency_code" type="xsd:string" minOccurs="0"/> + <element name="store_currency_code" type="xsd:string" minOccurs="0"/> + <element name="quote_currency_code" type="xsd:string" minOccurs="0"/> + <element name="grand_total" type="xsd:string" minOccurs="0"/> + <element name="base_grand_total" type="xsd:string" minOccurs="0"/> + <element name="checkout_method" type="xsd:string" minOccurs="0"/> + <element name="customer_id" type="xsd:string" minOccurs="0"/> + <element name="customer_tax_class_id" type="xsd:string" minOccurs="0"/> + <element name="customer_group_id" type="xsd:int" minOccurs="0"/> + <element name="customer_email" type="xsd:string" minOccurs="0"/> + <element name="customer_prefix" type="xsd:string" minOccurs="0"/> + <element name="customer_firstname" type="xsd:string" minOccurs="0"/> + <element name="customer_middlename" type="xsd:string" minOccurs="0"/> + <element name="customer_lastname" type="xsd:string" minOccurs="0"/> + <element name="customer_suffix" type="xsd:string" minOccurs="0"/> + <element name="customer_note" type="xsd:string" minOccurs="0"/> + <element name="customer_note_notify" type="xsd:string" minOccurs="0"/> + <element name="customer_is_guest" type="xsd:string" minOccurs="0"/> + <element name="applied_rule_ids" type="xsd:string" minOccurs="0"/> + <element name="reserved_order_id" type="xsd:string" minOccurs="0"/> + <element name="password_hash" type="xsd:string" minOccurs="0"/> + <element name="coupon_code" type="xsd:string" minOccurs="0"/> + <element name="global_currency_code" type="xsd:string" minOccurs="0"/> + <element name="base_to_global_rate" type="xsd:double" minOccurs="0"/> + <element name="base_to_quote_rate" type="xsd:double" minOccurs="0"/> + <element name="customer_taxvat" type="xsd:string" minOccurs="0"/> + <element name="customer_gender" type="xsd:string" minOccurs="0"/> + <element name="subtotal" type="xsd:double" minOccurs="0"/> + <element name="base_subtotal" type="xsd:double" minOccurs="0"/> + <element name="subtotal_with_discount" type="xsd:double" minOccurs="0"/> + <element name="base_subtotal_with_discount" type="xsd:double" minOccurs="0"/> + <element name="ext_shipping_info" type="xsd:string" minOccurs="0"/> + <element name="gift_message_id" type="xsd:string" minOccurs="0"/> + <element name="gift_message" type="xsd:string" minOccurs="0"/> + <element name="customer_balance_amount_used" type="xsd:double" minOccurs="0"/> + <element name="base_customer_bal_amount_used" type="xsd:double" minOccurs="0"/> + <element name="use_customer_balance" type="xsd:string" minOccurs="0"/> + <element name="gift_cards_amount" type="xsd:string" minOccurs="0"/> + <element name="base_gift_cards_amount" type="xsd:string" minOccurs="0"/> + <element name="gift_cards_amount_used" type="xsd:string" minOccurs="0"/> + <element name="use_reward_points" type="xsd:string" minOccurs="0"/> + <element name="reward_points_balance" type="xsd:string" minOccurs="0"/> + <element name="base_reward_currency_amount" type="xsd:string" minOccurs="0"/> + <element name="reward_currency_amount" type="xsd:string" minOccurs="0"/> + <element name="shipping_address" type="typens:shoppingCartAddressEntity" minOccurs="0"/> + <element name="billing_address" type="typens:shoppingCartAddressEntity" minOccurs="0"/> + <element name="items" type="typens:shoppingCartItemEntityArray" minOccurs="0"/> + <element name="payment" type="typens:shoppingCartPaymentEntity" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartTotalsEntity"> + <all> + <element name="title" type="xsd:string" minOccurs="0"/> + <element name="amount" type="xsd:double" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartTotalsEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:shoppingCartTotalsEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="shoppingCartLicenseEntity"> + <all> + <element name="agreement_id" type="xsd:string" minOccurs="0"/> + <element name="name" type="xsd:string" minOccurs="0"/> + <element name="content" type="xsd:string" minOccurs="0"/> + <element name="is_active" type="xsd:int" minOccurs="0"/> + <element name="is_html" type="xsd:int" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartLicenseEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:shoppingCartLicenseEntity[]"/> + </restriction> + </complexContent> + </complexType> + + <complexType name="shoppingCartProductEntity"> + <all> + <element name="product_id" type="xsd:string" minOccurs="0"/> + <element name="sku" type="xsd:string" minOccurs="0"/> + <element name="qty" type="xsd:double" minOccurs="0"/> + <element name="options" type="typens:associativeArray" minOccurs="0"/> + <element name="bundle_option" type="typens:associativeArray" minOccurs="0"/> + <element name="bundle_option_qty" type="typens:associativeArray" minOccurs="0"/> + <element name="links" type="typens:ArrayOfString" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartProductEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:shoppingCartProductEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="shoppingCartProductResponseEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="shoppingCartCustomerEntity"> + <all> + <element name="mode" type="xsd:string" minOccurs="0"/> + <element name="customer_id" type="xsd:int" minOccurs="0"/> + <element name="email" type="xsd:string" minOccurs="0"/> + <element name="firstname" type="xsd:string" minOccurs="0"/> + <element name="lastname" type="xsd:string" minOccurs="0"/> + <element name="password" type="xsd:string" minOccurs="0"/> + <element name="confirmation" type="xsd:string" minOccurs="0"/> + <element name="website_id" type="xsd:int" minOccurs="0"/> + <element name="store_id" type="xsd:int" minOccurs="0"/> + <element name="group_id" type="xsd:int" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartCustomerAddressEntity"> + <all> + <element name="mode" type="xsd:string" minOccurs="0"/> + <element name="address_id" type="xsd:string" minOccurs="0"/> + <element name="firstname" type="xsd:string" minOccurs="0"/> + <element name="lastname" type="xsd:string" minOccurs="0"/> + <element name="company" type="xsd:string" minOccurs="0"/> + <element name="street" type="xsd:string" minOccurs="0"/> + <element name="city" type="xsd:string" minOccurs="0"/> + <element name="region" type="xsd:string" minOccurs="0"/> + <element name="region_id" type="xsd:string" minOccurs="0"/> + <element name="postcode" type="xsd:string" minOccurs="0"/> + <element name="country_id" type="xsd:string" minOccurs="0"/> + <element name="telephone" type="xsd:string" minOccurs="0"/> + <element name="fax" type="xsd:string" minOccurs="0"/> + <element name="is_default_billing" type="xsd:int" minOccurs="0"/> + <element name="is_default_shipping" type="xsd:int" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartCustomerAddressEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:shoppingCartCustomerAddressEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="shoppingCartShippingMethodEntity"> + <all> + <element name="code" type="xsd:string" minOccurs="0"/> + <element name="carrier" type="xsd:string" minOccurs="0"/> + <element name="carrier_title" type="xsd:string" minOccurs="0"/> + <element name="method" type="xsd:string" minOccurs="0"/> + <element name="method_title" type="xsd:string" minOccurs="0"/> + <element name="method_description" type="xsd:string" minOccurs="0"/> + <element name="price" type="xsd:double" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartShippingMethodEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:shoppingCartShippingMethodEntity[]"/> + </restriction> + </complexContent> + </complexType> + + <complexType name="shoppingCartPaymentMethodEntity"> + <all> + <element name="po_number" type="xsd:string" minOccurs="0"/> + <element name="method" type="xsd:string" minOccurs="0"/> + <element name="cc_cid" type="xsd:string" minOccurs="0"/> + <element name="cc_owner" type="xsd:string" minOccurs="0"/> + <element name="cc_number" type="xsd:string" minOccurs="0"/> + <element name="cc_type" type="xsd:string" minOccurs="0"/> + <element name="cc_exp_year" type="xsd:string" minOccurs="0"/> + <element name="cc_exp_month" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="shoppingCartPaymentMethodResponseEntity"> + <all> + <element name="code" type="xsd:string"/> + <element name="title" type="xsd:string"/> + <element name="cc_types" type="typens:associativeArray"/> + </all> + </complexType> + <complexType name="shoppingCartPaymentMethodResponseEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:shoppingCartPaymentMethodResponseEntity[]"/> + </restriction> + </complexContent> + </complexType> + </schema> + </types> + <message name="shoppingCartCreateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartCreateResponse"> + <part name="quoteId" type="xsd:int"/> + </message> + <message name="shoppingCartOrderRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + <part name="licenses" type="typens:ArrayOfString"/> + </message> + <message name="shoppingCartOrderResponse"> + <part name="result" type="xsd:string"/> + </message> + <message name="shoppingCartOrderWithPaymentRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + <part name="licenses" type="typens:ArrayOfString"/> + <part name="paymentData" type="typens:shoppingCartPaymentMethodEntity"/> + </message> + <message name="shoppingCartOrderWithPaymentResponse"> + <part name="result" type="xsd:string"/> + </message> + <message name="shoppingCartInfoRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartInfoResponse"> + <part name="result" type="typens:shoppingCartInfoEntity"/> + </message> + <message name="shoppingCartTotalsRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartTotalsResponse"> + <part name="result" type="typens:shoppingCartTotalsEntityArray"/> + </message> + <message name="shoppingCartLicenseRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartLicenseResponse"> + <part name="result" type="typens:shoppingCartLicenseEntityArray"/> + </message> + <message name="shoppingCartProductAddRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="products" type="typens:shoppingCartProductEntityArray"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartProductAddResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartProductUpdateRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="products" type="typens:shoppingCartProductEntityArray"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartProductUpdateResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartProductRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="products" type="typens:shoppingCartProductEntityArray"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartProductRemoveResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartProductListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartProductListResponse"> + <part name="result" type="typens:shoppingCartProductResponseEntityArray"/> + </message> + <message name="shoppingCartProductMoveToCustomerQuoteRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="products" type="typens:shoppingCartProductEntityArray"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartProductMoveToCustomerQuoteResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartCustomerSetRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="customer" type="typens:shoppingCartCustomerEntity"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartCustomerSetResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartCustomerAddressesRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="customer" type="typens:shoppingCartCustomerAddressEntityArray"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartCustomerAddressesResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartShippingMethodRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="method" type="xsd:string"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartShippingMethodResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartShippingListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartShippingListResponse"> + <part name="result" type="typens:shoppingCartShippingMethodEntityArray"/> + </message> + <message name="shoppingCartPaymentMethodRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="paymentData" type="typens:shoppingCartPaymentMethodEntity"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartPaymentMethodResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartPaymentListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartPaymentListResponse"> + <part name="result" type="typens:shoppingCartPaymentMethodResponseEntityArray"/> + </message> + <message name="shoppingCartCouponAddRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="couponCode" type="xsd:string"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartCouponAddResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <message name="shoppingCartCouponRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="quoteId" type="xsd:int"/> + <part name="store" type="xsd:string"/> + </message> + <message name="shoppingCartCouponRemoveResponse"> + <part name="result" type="xsd:boolean"/> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="shoppingCartCreate"> + <documentation>Create shopping cart</documentation> + <input message="typens:shoppingCartCreateRequest"/> + <output message="typens:shoppingCartCreateResponse"/> + </operation> + <operation name="shoppingCartInfo"> + <documentation>Retrieve information about shopping cart</documentation> + <input message="typens:shoppingCartInfoRequest"/> + <output message="typens:shoppingCartInfoResponse"/> + </operation> + <operation name="shoppingCartOrder"> + <documentation>Create an order from shopping cart</documentation> + <input message="typens:shoppingCartOrderRequest"/> + <output message="typens:shoppingCartOrderResponse"/> + </operation> + <operation name="shoppingCartOrderWithPayment"> + <documentation>Create an order from shopping cart with payment method</documentation> + <input message="typens:shoppingCartOrderWithPaymentRequest"/> + <output message="typens:shoppingCartOrderWithPaymentResponse"/> + </operation> + <operation name="shoppingCartTotals"> + <documentation>Get total prices for shopping cart</documentation> + <input message="typens:shoppingCartTotalsRequest"/> + <output message="typens:shoppingCartTotalsResponse"/> + </operation> + <operation name="shoppingCartLicense"> + <documentation>Get terms and conditions</documentation> + <input message="typens:shoppingCartLicenseRequest"/> + <output message="typens:shoppingCartLicenseResponse"/> + </operation> + <operation name="shoppingCartProductAdd"> + <documentation>Add product(s) to shopping cart</documentation> + <input message="typens:shoppingCartProductAddRequest"/> + <output message="typens:shoppingCartProductAddResponse"/> + </operation> + <operation name="shoppingCartProductUpdate"> + <documentation>Update product(s) quantities in shopping cart</documentation> + <input message="typens:shoppingCartProductUpdateRequest"/> + <output message="typens:shoppingCartProductUpdateResponse"/> + </operation> + <operation name="shoppingCartProductRemove"> + <documentation>Remove product(s) from shopping cart</documentation> + <input message="typens:shoppingCartProductRemoveRequest"/> + <output message="typens:shoppingCartProductRemoveResponse"/> + </operation> + <operation name="shoppingCartProductList"> + <documentation>Get list of products in shopping cart</documentation> + <input message="typens:shoppingCartProductListRequest"/> + <output message="typens:shoppingCartProductListResponse"/> + </operation> + <operation name="shoppingCartProductMoveToCustomerQuote"> + <documentation>Move product(s) to customer quote</documentation> + <input message="typens:shoppingCartProductMoveToCustomerQuoteRequest"/> + <output message="typens:shoppingCartProductMoveToCustomerQuoteResponse"/> + </operation> + <operation name="shoppingCartCustomerSet"> + <documentation>Set customer for shopping cart</documentation> + <input message="typens:shoppingCartCustomerSetRequest"/> + <output message="typens:shoppingCartCustomerSetResponse"/> + </operation> + <operation name="shoppingCartCustomerAddresses"> + <documentation>Set customer's addresses in shopping cart</documentation> + <input message="typens:shoppingCartCustomerAddressesRequest"/> + <output message="typens:shoppingCartCustomerAddressesResponse"/> + </operation> + <operation name="shoppingCartShippingMethod"> + <documentation>Set shipping method</documentation> + <input message="typens:shoppingCartShippingMethodRequest"/> + <output message="typens:shoppingCartShippingMethodResponse"/> + </operation> + <operation name="shoppingCartShippingList"> + <documentation>Get list of available shipping methods</documentation> + <input message="typens:shoppingCartShippingListRequest"/> + <output message="typens:shoppingCartShippingListResponse"/> + </operation> + <operation name="shoppingCartPaymentMethod"> + <documentation>Set payment method</documentation> + <input message="typens:shoppingCartPaymentMethodRequest"/> + <output message="typens:shoppingCartPaymentMethodResponse"/> + </operation> + <operation name="shoppingCartPaymentList"> + <documentation>Get list of available payment methods</documentation> + <input message="typens:shoppingCartPaymentListRequest"/> + <output message="typens:shoppingCartPaymentListResponse"/> + </operation> + <operation name="shoppingCartCouponAdd"> + <documentation>Add coupon code for shopping cart</documentation> + <input message="typens:shoppingCartCouponAddRequest"/> + <output message="typens:shoppingCartCouponAddResponse"/> + </operation> + <operation name="shoppingCartCouponRemove"> + <documentation>Remove coupon code from shopping cart</documentation> + <input message="typens:shoppingCartCouponRemoveRequest"/> + <output message="typens:shoppingCartCouponRemoveResponse"/> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + <operation name="shoppingCartCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartTotals"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartOrder"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartOrderWithPayment"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartLicense"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartProductAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartProductUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartProductRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartProductList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartProductMoveToCustomerQuote"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartCustomerSet"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartCustomerAddresses"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartShippingMethod"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartShippingList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartPaymentMethod"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartPaymentList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartCouponAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="shoppingCartCouponRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + </binding> +</definitions> diff --git a/app/code/core/Mage/Checkout/etc/wsi.xml b/app/code/core/Mage/Checkout/etc/wsi.xml new file mode 100644 index 00000000000..71c218acd90 --- /dev/null +++ b/app/code/core/Mage/Checkout/etc/wsi.xml @@ -0,0 +1,1018 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="shoppingCartAddressEntity"> + <xsd:sequence> + <xsd:element name="address_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="created_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="save_in_address_book" type="xsd:int" minOccurs="0"/> + <xsd:element name="customer_address_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="address_type" type="xsd:string" minOccurs="0"/> + <xsd:element name="email" type="xsd:string" minOccurs="0"/> + <xsd:element name="prefix" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="middlename" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="suffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="company" type="xsd:string" minOccurs="0"/> + <xsd:element name="street" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="region" type="xsd:string" minOccurs="0"/> + <xsd:element name="region_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="postcode" type="xsd:string" minOccurs="0"/> + <xsd:element name="country_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="telephone" type="xsd:string" minOccurs="0"/> + <xsd:element name="fax" type="xsd:string" minOccurs="0"/> + <xsd:element name="same_as_billing" type="xsd:int" minOccurs="0"/> + <xsd:element name="free_shipping" type="xsd:int" minOccurs="0"/> + <xsd:element name="shipping_method" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipping_description" type="xsd:string" minOccurs="0"/> + <xsd:element name="weight" type="xsd:double" minOccurs="0"/> + <xsd:element name="fax" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartItemEntity"> + <xsd:sequence> + <xsd:element name="item_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="created_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="product_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="store_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="parent_item_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="is_virtual" type="xsd:int" minOccurs="0"/> + <xsd:element name="sku" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + <xsd:element name="description" type="xsd:string" minOccurs="0"/> + <xsd:element name="applied_rule_ids" type="xsd:string" minOccurs="0"/> + <xsd:element name="additional_data" type="xsd:string" minOccurs="0"/> + <xsd:element name="free_shipping" type="xsd:string" minOccurs="0"/> + <xsd:element name="is_qty_decimal" type="xsd:string" minOccurs="0"/> + <xsd:element name="no_discount" type="xsd:string" minOccurs="0"/> + <xsd:element name="weight" type="xsd:double" minOccurs="0"/> + <xsd:element name="qty" type="xsd:double" minOccurs="0"/> + <xsd:element name="price" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_price" type="xsd:double" minOccurs="0"/> + <xsd:element name="custom_price" type="xsd:double" minOccurs="0"/> + <xsd:element name="discount_percent" type="xsd:double" minOccurs="0"/> + <xsd:element name="discount_amount" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_discount_amount" type="xsd:double" minOccurs="0"/> + <xsd:element name="tax_percent" type="xsd:double" minOccurs="0"/> + <xsd:element name="tax_amount" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_tax_amount" type="xsd:double" minOccurs="0"/> + <xsd:element name="row_total" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_row_total" type="xsd:double" minOccurs="0"/> + <xsd:element name="row_total_with_discount" type="xsd:double" minOccurs="0"/> + <xsd:element name="row_weight" type="xsd:double" minOccurs="0"/> + <xsd:element name="product_type" type="xsd:string" minOccurs="0"/> + <xsd:element name="base_tax_before_discount" type="xsd:double" minOccurs="0"/> + <xsd:element name="tax_before_discount" type="xsd:double" minOccurs="0"/> + <xsd:element name="original_custom_price" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_cost" type="xsd:double" minOccurs="0"/> + <xsd:element name="price_incl_tax" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_price_incl_tax" type="xsd:double" minOccurs="0"/> + <xsd:element name="row_total_incl_tax" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_row_total_incl_tax" type="xsd:double" minOccurs="0"/> + <xsd:element name="gift_message_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="gift_message" type="xsd:string" minOccurs="0"/> + <xsd:element name="gift_message_available" type="xsd:string" minOccurs="0"/> + <xsd:element name="weee_tax_applied" type="xsd:double" minOccurs="0"/> + <xsd:element name="weee_tax_applied_amount" type="xsd:double" minOccurs="0"/> + <xsd:element name="weee_tax_applied_row_amount" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_weee_tax_applied_amount" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_weee_tax_applied_row_amnt" type="xsd:double" minOccurs="0"/> + <xsd:element name="weee_tax_disposition" type="xsd:double" minOccurs="0"/> + <xsd:element name="weee_tax_row_disposition" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_weee_tax_disposition" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_weee_tax_row_disposition" type="xsd:double" minOccurs="0"/> + <xsd:element name="tax_class_id" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartItemEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:shoppingCartItemEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartPaymentEntity"> + <xsd:sequence> + <xsd:element name="payment_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="created_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="method" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_type" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_number_enc" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_last4" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_cid_enc" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_owner" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_exp_month" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_exp_year" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_ss_owner" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_ss_start_month" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_ss_start_year" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_ss_issue" type="xsd:string" minOccurs="0"/> + <xsd:element name="po_number" type="xsd:string" minOccurs="0"/> + <xsd:element name="additional_data" type="xsd:string" minOccurs="0"/> + <xsd:element name="additional_information" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartInfoEntity"> + <xsd:sequence> + <xsd:element name="store_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="created_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="converted_at" type="xsd:string" minOccurs="0"/> + <xsd:element name="quote_id" type="xsd:int" minOccurs="0"/> + <xsd:element name="is_active" type="xsd:int" minOccurs="0"/> + <xsd:element name="is_virtual" type="xsd:int" minOccurs="0"/> + <xsd:element name="is_multi_shipping" type="xsd:int" minOccurs="0"/> + <xsd:element name="items_count" type="xsd:double" minOccurs="0"/> + <xsd:element name="items_qty" type="xsd:double" minOccurs="0"/> + <xsd:element name="orig_order_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="store_to_base_rate" type="xsd:string" minOccurs="0"/> + <xsd:element name="store_to_quote_rate" type="xsd:string" minOccurs="0"/> + <xsd:element name="base_currency_code" type="xsd:string" minOccurs="0"/> + <xsd:element name="store_currency_code" type="xsd:string" minOccurs="0"/> + <xsd:element name="quote_currency_code" type="xsd:string" minOccurs="0"/> + <xsd:element name="grand_total" type="xsd:string" minOccurs="0"/> + <xsd:element name="base_grand_total" type="xsd:string" minOccurs="0"/> + <xsd:element name="checkout_method" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_tax_class_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_group_id" type="xsd:int" minOccurs="0"/> + <xsd:element name="customer_email" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_prefix" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_firstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_middlename" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_lastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_suffix" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_note" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_note_notify" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_is_guest" type="xsd:string" minOccurs="0"/> + <xsd:element name="applied_rule_ids" type="xsd:string" minOccurs="0"/> + <xsd:element name="reserved_order_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="password_hash" type="xsd:string" minOccurs="0"/> + <xsd:element name="coupon_code" type="xsd:string" minOccurs="0"/> + <xsd:element name="global_currency_code" type="xsd:string" minOccurs="0"/> + <xsd:element name="base_to_global_rate" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_to_quote_rate" type="xsd:double" minOccurs="0"/> + <xsd:element name="customer_taxvat" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_gender" type="xsd:string" minOccurs="0"/> + <xsd:element name="subtotal" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_subtotal" type="xsd:double" minOccurs="0"/> + <xsd:element name="subtotal_with_discount" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_subtotal_with_discount" type="xsd:double" minOccurs="0"/> + <xsd:element name="ext_shipping_info" type="xsd:string" minOccurs="0"/> + <xsd:element name="gift_message_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="gift_message" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_balance_amount_used" type="xsd:double" minOccurs="0"/> + <xsd:element name="base_customer_bal_amount_used" type="xsd:double" minOccurs="0"/> + <xsd:element name="use_customer_balance" type="xsd:string" minOccurs="0"/> + <xsd:element name="gift_cards_amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="base_gift_cards_amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="gift_cards_amount_used" type="xsd:string" minOccurs="0"/> + <xsd:element name="use_reward_points" type="xsd:string" minOccurs="0"/> + <xsd:element name="reward_points_balance" type="xsd:string" minOccurs="0"/> + <xsd:element name="base_reward_currency_amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="reward_currency_amount" type="xsd:string" minOccurs="0"/> + <xsd:element name="shipping_address" type="typens:shoppingCartAddressEntity" minOccurs="0"/> + <xsd:element name="billing_address" type="typens:shoppingCartAddressEntity" minOccurs="0"/> + <xsd:element name="items" type="typens:shoppingCartItemEntityArray" minOccurs="0"/> + <xsd:element name="payment" type="typens:shoppingCartPaymentEntity" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartTotalsEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0"/> + <xsd:element name="amount" type="xsd:double" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartTotalsEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:shoppingCartTotalsEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartLicenseEntity"> + <xsd:sequence> + <xsd:element name="agreement_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="name" type="xsd:string" minOccurs="0"/> + <xsd:element name="content" type="xsd:string" minOccurs="0"/> + <xsd:element name="is_active" type="xsd:int" minOccurs="0"/> + <xsd:element name="is_html" type="xsd:int" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartLicenseEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:shoppingCartLicenseEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartProductEntity"> + <xsd:sequence> + <xsd:element name="product_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="sku" type="xsd:string" minOccurs="0"/> + <xsd:element name="qty" type="xsd:double" minOccurs="0"/> + <xsd:element name="options" type="typens:associativeArray" minOccurs="0"/> + <xsd:element name="bundle_option" type="typens:associativeArray" minOccurs="0"/> + <xsd:element name="bundle_option_qty" type="typens:associativeArray" minOccurs="0"/> + <xsd:element name="links" type="typens:ArrayOfString" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartProductEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:shoppingCartProductEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartProductResponseEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartCustomerEntity"> + <xsd:sequence> + <xsd:element name="mode" type="xsd:string" minOccurs="0"/> + <xsd:element name="customer_id" type="xsd:int" minOccurs="0"/> + <xsd:element name="email" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="password" type="xsd:string" minOccurs="0"/> + <xsd:element name="confirmation" type="xsd:string" minOccurs="0"/> + <xsd:element name="website_id" type="xsd:int" minOccurs="0"/> + <xsd:element name="store_id" type="xsd:int" minOccurs="0"/> + <xsd:element name="group_id" type="xsd:int" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartCustomerAddressEntity"> + <xsd:sequence> + <xsd:element name="mode" type="xsd:string" minOccurs="0"/> + <xsd:element name="address_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="firstname" type="xsd:string" minOccurs="0"/> + <xsd:element name="lastname" type="xsd:string" minOccurs="0"/> + <xsd:element name="company" type="xsd:string" minOccurs="0"/> + <xsd:element name="street" type="xsd:string" minOccurs="0"/> + <xsd:element name="city" type="xsd:string" minOccurs="0"/> + <xsd:element name="region" type="xsd:string" minOccurs="0"/> + <xsd:element name="region_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="postcode" type="xsd:string" minOccurs="0"/> + <xsd:element name="country_id" type="xsd:string" minOccurs="0"/> + <xsd:element name="telephone" type="xsd:string" minOccurs="0"/> + <xsd:element name="fax" type="xsd:string" minOccurs="0"/> + <xsd:element name="is_default_billing" type="xsd:int" minOccurs="0"/> + <xsd:element name="is_default_shipping" type="xsd:int" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartCustomerAddressEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:shoppingCartCustomerAddressEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartShippingMethodEntity"> + <xsd:sequence> + <xsd:element name="code" type="xsd:string" minOccurs="0"/> + <xsd:element name="carrier" type="xsd:string" minOccurs="0"/> + <xsd:element name="carrier_title" type="xsd:string" minOccurs="0"/> + <xsd:element name="method" type="xsd:string" minOccurs="0"/> + <xsd:element name="method_title" type="xsd:string" minOccurs="0"/> + <xsd:element name="method_description" type="xsd:string" minOccurs="0"/> + <xsd:element name="price" type="xsd:double" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartShippingMethodEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:shoppingCartShippingMethodEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartPaymentMethodEntity"> + <xsd:sequence> + <xsd:element name="po_number" type="xsd:string" minOccurs="0"/> + <xsd:element name="method" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_cid" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_owner" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_number" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_type" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_exp_year" type="xsd:string" minOccurs="0"/> + <xsd:element name="cc_exp_month" type="xsd:string" minOccurs="0"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartPaymentMethodResponseEntity"> + <xsd:sequence> + <xsd:element name="code" type="xsd:string"/> + <xsd:element name="title" type="xsd:string"/> + <xsd:element name="cc_types" type="typens:associativeArray"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="shoppingCartPaymentMethodResponseEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:shoppingCartPaymentMethodResponseEntity"/> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="shoppingCartCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartOrderRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="agreements" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartOrderResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartOrderWithPaymentRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="licenses" type="typens:ArrayOfString" /> + <xsd:element minOccurs="0" maxOccurs="1" name="paymentData" type="typens:shoppingCartPaymentMethodEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartOrderWithPaymentResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:shoppingCartInfoEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartTotalsRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartTotalsResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:shoppingCartTotalsEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartLicenseRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartLicenseResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:shoppingCartLicenseEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productsData" type="typens:shoppingCartProductEntityArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productsData" type="typens:shoppingCartProductEntityArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productsData" type="typens:shoppingCartProductEntityArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:shoppingCartProductResponseEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductMoveToCustomerQuoteRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productsData" type="typens:shoppingCartProductEntityArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartProductMoveToCustomerQuoteResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCustomerSetRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerData" type="typens:shoppingCartCustomerEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCustomerSetResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCustomerAddressesRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerAddressData" type="typens:shoppingCartCustomerAddressEntityArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCustomerAddressesResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartShippingMethodRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="shippingMethod" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartShippingMethodResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartShippingListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartShippingListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:shoppingCartShippingMethodEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartPaymentMethodRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="paymentData" type="typens:shoppingCartPaymentMethodEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartPaymentMethodResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartPaymentListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartPaymentListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:shoppingCartPaymentMethodResponseEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCouponAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="couponCode" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCouponAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCouponRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="shoppingCartCouponRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="shoppingCartCreateRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCreateResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartOrderRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartOrderRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartOrderResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartOrderResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartOrderWithPaymentRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartOrderWithPaymentRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartOrderWithPaymentResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartOrderWithPaymentResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartInfoRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartInfoResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartTotalsRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartTotalsRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartTotalsResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartTotalsResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartLicenseRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartLicenseRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartLicenseResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartLicenseResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductAddRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartProductAddRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductAddResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartProductAddResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductUpdateRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartProductUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductUpdateResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartProductUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductRemoveRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartProductRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductRemoveResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartProductRemoveResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductListRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartProductListRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductListResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartProductListResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductMoveToCustomerQuoteRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartProductMoveToCustomerQuoteRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartProductMoveToCustomerQuoteResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartProductMoveToCustomerQuoteResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCustomerSetRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartCustomerSetRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCustomerSetResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartCustomerSetResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCustomerAddressesRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartCustomerAddressesRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCustomerAddressesResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartCustomerAddressesResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartShippingMethodRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartShippingMethodRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartShippingMethodResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartShippingMethodResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartShippingListRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartShippingListRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartShippingListResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartShippingListResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartPaymentMethodRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartPaymentMethodRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartPaymentMethodResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartPaymentMethodResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartPaymentListRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartPaymentListRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartPaymentListResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartPaymentListResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCouponAddRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartCouponAddRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCouponAddResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartCouponAddResponseParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCouponRemoveRequest"> + <wsdl:part name="parameters" element="typens:shoppingCartCouponRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="shoppingCartCouponRemoveResponse"> + <wsdl:part name="parameters" element="typens:shoppingCartCouponRemoveResponseParam" /> + </wsdl:message> + + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="shoppingCartCreate"> + <wsdl:documentation>Create shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartCreateRequest"/> + <wsdl:output message="typens:shoppingCartCreateResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartInfo"> + <wsdl:documentation>Retrieve information about shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartInfoRequest"/> + <wsdl:output message="typens:shoppingCartInfoResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartOrder"> + <wsdl:documentation>Create an order from shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartOrderRequest"/> + <wsdl:output message="typens:shoppingCartOrderResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartOrderWithPayment"> + <wsdl:documentation>Create an order from shopping cart with payment method</wsdl:documentation> + <wsdl:input message="typens:shoppingCartOrderWithPaymentRequest"/> + <wsdl:output message="typens:shoppingCartOrderWithPaymentResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartTotals"> + <wsdl:documentation>Get total prices for shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartTotalsRequest"/> + <wsdl:output message="typens:shoppingCartTotalsResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartLicense"> + <wsdl:documentation>Get terms and conditions</wsdl:documentation> + <wsdl:input message="typens:shoppingCartLicenseRequest"/> + <wsdl:output message="typens:shoppingCartLicenseResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductAdd"> + <wsdl:documentation>Add product(s) to shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartProductAddRequest"/> + <wsdl:output message="typens:shoppingCartProductAddResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductUpdate"> + <wsdl:documentation>Update product(s) quantities in shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartProductUpdateRequest"/> + <wsdl:output message="typens:shoppingCartProductUpdateResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductRemove"> + <wsdl:documentation>Remove product(s) from shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartProductRemoveRequest"/> + <wsdl:output message="typens:shoppingCartProductRemoveResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductList"> + <wsdl:documentation>Get list of products in shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartProductListRequest"/> + <wsdl:output message="typens:shoppingCartProductListResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductMoveToCustomerQuote"> + <wsdl:documentation>Move product(s) to customer quote</wsdl:documentation> + <wsdl:input message="typens:shoppingCartProductMoveToCustomerQuoteRequest"/> + <wsdl:output message="typens:shoppingCartProductMoveToCustomerQuoteResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartCustomerSet"> + <wsdl:documentation>Set customer for shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartCustomerSetRequest"/> + <wsdl:output message="typens:shoppingCartCustomerSetResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartCustomerAddresses"> + <wsdl:documentation>Set customer's addresses in shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartCustomerAddressesRequest"/> + <wsdl:output message="typens:shoppingCartCustomerAddressesResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartShippingMethod"> + <wsdl:documentation>Set shipping method</wsdl:documentation> + <wsdl:input message="typens:shoppingCartShippingMethodRequest"/> + <wsdl:output message="typens:shoppingCartShippingMethodResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartShippingList"> + <wsdl:documentation>Get list of available shipping methods</wsdl:documentation> + <wsdl:input message="typens:shoppingCartShippingListRequest"/> + <wsdl:output message="typens:shoppingCartShippingListResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartPaymentMethod"> + <wsdl:documentation>Set payment method</wsdl:documentation> + <wsdl:input message="typens:shoppingCartPaymentMethodRequest"/> + <wsdl:output message="typens:shoppingCartPaymentMethodResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartPaymentList"> + <wsdl:documentation>Get list of available payment methods</wsdl:documentation> + <wsdl:input message="typens:shoppingCartPaymentListRequest"/> + <wsdl:output message="typens:shoppingCartPaymentListResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartCouponAdd"> + <wsdl:documentation>Add coupon code for shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartCouponAddRequest"/> + <wsdl:output message="typens:shoppingCartCouponAddResponse"/> + </wsdl:operation> + <wsdl:operation name="shoppingCartCouponRemove"> + <wsdl:documentation>Remove coupon code from shopping cart</wsdl:documentation> + <wsdl:input message="typens:shoppingCartCouponRemoveRequest"/> + <wsdl:output message="typens:shoppingCartCouponRemoveResponse"/> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> + <wsdl:operation name="shoppingCartCreate"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartInfo"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartTotals"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartOrder"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartOrderWithPayment"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartLicense"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductAdd"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductUpdate"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductRemove"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductList"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartProductMoveToCustomerQuote"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartCustomerSet"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartCustomerAddresses"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartShippingMethod"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartShippingList"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartPaymentMethod"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartPaymentList"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartCouponAdd"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="shoppingCartCouponRemove"> + <soap:operation soapAction=""/> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> +</wsdl:definitions> diff --git a/app/code/core/Mage/Cms/Helper/Wysiwyg/Images.php b/app/code/core/Mage/Cms/Helper/Wysiwyg/Images.php index d9b871fbe09..a282b00c54a 100644 --- a/app/code/core/Mage/Cms/Helper/Wysiwyg/Images.php +++ b/app/code/core/Mage/Cms/Helper/Wysiwyg/Images.php @@ -86,7 +86,7 @@ class Mage_Cms_Helper_Wysiwyg_Images extends Mage_Core_Helper_Abstract */ public function getStorageRoot() { - return Mage::getConfig()->getOptions()->getMediaDir() . DS . Mage_Cms_Model_Wysiwyg_Config::IMAGE_DIRECTORY + return Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA) . DS . Mage_Cms_Model_Wysiwyg_Config::IMAGE_DIRECTORY . DS; } @@ -247,7 +247,7 @@ class Mage_Cms_Helper_Wysiwyg_Images extends Mage_Core_Helper_Abstract public function getCurrentUrl() { if (!$this->_currentUrl) { - $path = str_replace(Mage::getConfig()->getOptions()->getMediaDir(), '', $this->getCurrentPath()); + $path = str_replace(Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA), '', $this->getCurrentPath()); $path = trim($path, DS); $this->_currentUrl = Mage::app()->getStore($this->_storeId)->getBaseUrl('media') . $this->convertPathToUrl($path) . '/'; diff --git a/app/code/core/Mage/Cms/Model/Wysiwyg/Images/Storage.php b/app/code/core/Mage/Cms/Model/Wysiwyg/Images/Storage.php index abcd1c2839e..f9915a25832 100644 --- a/app/code/core/Mage/Cms/Model/Wysiwyg/Images/Storage.php +++ b/app/code/core/Mage/Cms/Model/Wysiwyg/Images/Storage.php @@ -430,7 +430,7 @@ class Mage_Cms_Model_Wysiwyg_Images_Storage extends Varien_Object */ public function getThumbsPath($filePath = false) { - $mediaRootDir = Mage::getConfig()->getOptions()->getMediaDir(); + $mediaRootDir = Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA); $thumbnailDir = $this->getThumbnailRoot(); if ($filePath && strpos($filePath, $mediaRootDir) === 0) { diff --git a/app/code/core/Mage/Connect/Block/Adminhtml/Extension/Custom/Edit/Tab/Local.php b/app/code/core/Mage/Connect/Block/Adminhtml/Extension/Custom/Edit/Tab/Local.php index 69afaf06fbf..e7f6898aa72 100644 --- a/app/code/core/Mage/Connect/Block/Adminhtml/Extension/Custom/Edit/Tab/Local.php +++ b/app/code/core/Mage/Connect/Block/Adminhtml/Extension/Custom/Edit/Tab/Local.php @@ -32,7 +32,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Connect_Block_Adminhtml_Extension_Custom_Edit_Tab_Local - extends Mage_Adminhtml_Block_Abstract + extends Mage_Core_Block_Template implements Mage_Adminhtml_Block_Widget_Tab_Interface { /** diff --git a/app/code/core/Mage/Connect/Model/Extension.php b/app/code/core/Mage/Connect/Model/Extension.php index 88b5769ac0e..33bd0947326 100644 --- a/app/code/core/Mage/Connect/Model/Extension.php +++ b/app/code/core/Mage/Connect/Model/Extension.php @@ -293,8 +293,10 @@ class Mage_Connect_Model_Extension extends Varien_Object public function createPackage() { $path = Mage::helper('Mage_Connect_Helper_Data')->getLocalPackagesPath(); - if (!Mage::getConfig()->createDirIfNotExists($path)) { - return false; + if (!is_dir($path)) { + if (!mkdir($path)) { + return false; + } } if (!$this->getPackageXml()) { $this->generatePackageXml(); @@ -311,8 +313,10 @@ class Mage_Connect_Model_Extension extends Varien_Object public function createPackageV1x() { $path = Mage::helper('Mage_Connect_Helper_Data')->getLocalPackagesPathV1x(); - if (!Mage::getConfig()->createDirIfNotExists($path)) { - return false; + if (!is_dir($path)) { + if (!mkdir($path)) { + return false; + } } if (!$this->getPackageXml()) { $this->generatePackageXml(); diff --git a/app/code/core/Mage/Core/Block/Template.php b/app/code/core/Mage/Core/Block/Template.php index 3d16eea7303..c68abf10665 100644 --- a/app/code/core/Mage/Core/Block/Template.php +++ b/app/code/core/Mage/Core/Block/Template.php @@ -38,13 +38,6 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract const XML_PATH_DEBUG_TEMPLATE_HINTS_BLOCKS = 'dev/debug/template_hints_blocks'; const XML_PATH_TEMPLATE_ALLOW_SYMLINK = 'dev/template/allow_symlink'; - /** - * View scripts directory - * - * @var string - */ - protected $_viewDir = ''; - /** * Assigned variables for view * @@ -67,11 +60,14 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract protected static $_showTemplateHintsBlocks; /** - * Path to template file in theme. - * - * @var string + * @var Mage_Core_Model_Dir */ - protected $_template; + protected $_dirs; + + /** + * @var Mage_Core_Model_Logger + */ + protected $_logger; /** * @var Magento_Filesystem @@ -79,6 +75,14 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract protected $_filesystem; /** + * Path to template file in theme. + * + * @var string + */ + protected $_template; + + /** + * Constructor * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -90,6 +94,8 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param array $data * @@ -107,24 +113,16 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, array $data = array() ) { - parent::__construct( - $request, - $layout, - $eventManager, - $urlBuilder, - $translator, - $cache, - $designPackage, - $session, - $storeConfig, - $frontController, - $helperFactory, - $data - ); + $this->_dirs = $dirs; + $this->_logger = $logger; $this->_filesystem = $filesystem; + parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, + $session, $storeConfig, $frontController, $helperFactory, $data); } /** @@ -179,7 +177,7 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract if ($area) { $params['area'] = $area; } - $templateName = Mage::getDesign()->getFilename($this->getTemplate(), $params); + $templateName = $this->_designPackage->getFilename($this->getTemplate(), $params); return $templateName; } @@ -215,24 +213,6 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract return $this; } - /** - * Set template location directory - * - * @param string $dir - * @return Mage_Core_Block_Template - */ - public function setScriptPath($dir) - { - if (Magento_Filesystem::isPathInDirectory($dir, Mage::getBaseDir('design')) - || $this->_getAllowSymlinks() - ) { - $this->_viewDir = $dir; - } else { - Mage::log('Not valid script path:' . $dir, Zend_Log::CRIT, null, true); - } - return $this; - } - /** * Check if direct output is allowed for block * @@ -266,7 +246,7 @@ class Mage_Core_Block_Template extends Mage_Core_Block_Abstract */ public function fetchView($fileName) { - $viewShortPath = str_replace(Mage::getBaseDir(), '', $fileName); + $viewShortPath = str_replace($this->_dirs->getDir(Mage_Core_Model_Dir::ROOT), '', $fileName); Magento_Profiler::start('TEMPLATE:' . $fileName, array('group' => 'TEMPLATE', 'file_name' => $viewShortPath)); // EXTR_SKIP protects from overriding @@ -295,13 +275,13 @@ HTML; } try { - if ((Magento_Filesystem::isPathInDirectory($fileName, Mage::getBaseDir('app')) - || Magento_Filesystem::isPathInDirectory($fileName, $this->_viewDir) + if ((Magento_Filesystem::isPathInDirectory($fileName, $this->_dirs->getDir(Mage_Core_Model_Dir::APP)) + || Magento_Filesystem::isPathInDirectory($fileName, $this->_dirs->getDir(Mage_Core_Model_Dir::THEMES)) || $this->_getAllowSymlinks()) && $this->_filesystem->isFile($fileName) ) { include $fileName; } else { - Mage::log("Invalid template file: '{$fileName}'", Zend_Log::CRIT, null, true); + $this->_logger->log("Invalid template file: '{$fileName}'", Zend_Log::CRIT); } } catch (Exception $e) { @@ -325,29 +305,16 @@ HTML; } /** - * Render block + * Render block HTML * * @return string */ - public function renderView() + protected function _toHtml() { if (!$this->getTemplate()) { return ''; } - $this->setScriptPath(Mage::getBaseDir('design')); - $html = $this->fetchView($this->getTemplateFile()); - return $html; - } - - /** - * Render block HTML - * - * @return string - */ - protected function _toHtml() - { - $html = $this->renderView(); - return $html; + return $this->fetchView($this->getTemplateFile()); } /** diff --git a/app/code/core/Mage/Core/Controller/Varien/Router/Base.php b/app/code/core/Mage/Core/Controller/Varien/Router/Base.php index f14298d53d5..cc761c071b5 100644 --- a/app/code/core/Mage/Core/Controller/Varien/Router/Base.php +++ b/app/code/core/Mage/Core/Controller/Varien/Router/Base.php @@ -56,7 +56,7 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie protected $_baseController; /** - * @var Magento_ObjectManager + * @var Mage_Core_Model_App */ protected $_app; @@ -90,11 +90,11 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie public function collectRoutes($configArea, $useRouterName) { $routers = array(); - $routersConfigNode = Mage::getConfig()->getNode($configArea.'/routers'); + $routersConfigNode = Mage::getConfig()->getNode($configArea . '/routers'); if ($routersConfigNode) { $routers = $routersConfigNode->children(); } - foreach ($routers as $routerName=>$routerConfig) { + foreach ($routers as $routerName => $routerConfig) { $use = (string)$routerConfig->use; if ($use == $useRouterName) { $modules = array((string)$routerConfig->args->module); @@ -178,7 +178,7 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie return null; } - $this->_app->loadDiConfiguration($this->_areaCode); + $this->_app->getConfig()->loadDiConfiguration($this->_areaCode); return $this->_matchController($request, $params); } @@ -212,7 +212,7 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie } for ($i = 0, $l = sizeof($params); $i < $l; $i += 2) { - $output['variables'][$params[$i]] = isset($params[$i+1]) ? urldecode($params[$i+1]) : ''; + $output['variables'][$params[$i]] = isset($params[$i+1]) ? urldecode($params[$i + 1]) : ''; } return $output; } @@ -386,7 +386,7 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie $action = $this->_matchActionName($request, $params['actionName']); //checking if this place should be secure - $this->_checkShouldBeSecure($request, '/'.$moduleFrontName.'/'.$controller.'/'.$action); + $this->_checkShouldBeSecure($request, '/' . $moduleFrontName . '/' . $controller . '/' . $action); $controllerClassName = $this->_validateControllerClassName($moduleName, $controller); if (false == $controllerClassName) { @@ -558,7 +558,7 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie if (count($parts)) { $file .= DS . implode(DS, $parts); } - $file .= DS.uc_words($controller, DS).'Controller.php'; + $file .= DS . uc_words($controller, DS) . 'Controller.php'; return $file; } @@ -576,7 +576,7 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie public function getControllerClassName($realModule, $controller) { - $class = $realModule.'_'.uc_words($controller).'Controller'; + $class = $realModule . '_' . uc_words($controller) . 'Controller'; return $class; } @@ -641,11 +641,12 @@ class Mage_Core_Controller_Varien_Router_Base extends Mage_Core_Controller_Varie protected function _getCurrentSecureUrl($request) { - if ($alias = $request->getAlias(Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS)) { - return Mage::getBaseUrl('link', true).ltrim($alias, '/'); + $alias = $request->getAlias(Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS); + if ($alias) { + return Mage::getBaseUrl('link', true) . ltrim($alias, '/'); } - return Mage::getBaseUrl('link', true).ltrim($request->getPathInfo(), '/'); + return Mage::getBaseUrl('link', true) . ltrim($request->getPathInfo(), '/'); } /** diff --git a/app/code/core/Mage/Core/Helper/Data.php b/app/code/core/Mage/Core/Helper/Data.php index f32493c6e69..523d5a50972 100644 --- a/app/code/core/Mage/Core/Helper/Data.php +++ b/app/code/core/Mage/Core/Helper/Data.php @@ -89,11 +89,10 @@ class Mage_Core_Helper_Data extends Mage_Core_Helper_Abstract { if ($this->_encryptor === null) { $encryptionModel = (string)Mage::getConfig()->getNode(self::XML_PATH_ENCRYPTION_MODEL); - if ($encryptionModel) { - $this->_encryptor = new $encryptionModel; - } else { - $this->_encryptor = Mage::getModel('Mage_Core_Model_Encryption'); + if (empty($encryptionModel)) { + $encryptionModel = 'Mage_Core_Model_Encryption'; } + $this->_encryptor = Mage::getModel($encryptionModel); $this->_encryptor->setHelper($this); } diff --git a/app/code/core/Mage/Core/Model/App.php b/app/code/core/Mage/Core/Model/App.php index eabc2776843..aa38dca9352 100644 --- a/app/code/core/Mage/Core/Model/App.php +++ b/app/code/core/Mage/Core/Model/App.php @@ -35,6 +35,34 @@ */ class Mage_Core_Model_App { + /** + * Scope code initialization option + */ + const INIT_OPTION_SCOPE_CODE = 'MAGE_RUN_CODE'; + + /** + * Scope type initialization option + */ + const INIT_OPTION_SCOPE_TYPE = 'MAGE_RUN_TYPE'; + + /** + * Custom directory paths initialization option + */ + const INIT_OPTION_URIS = 'app_uris'; + + /** + * Custom directory absolute paths initialization option + */ + const INIT_OPTION_DIRS = 'app_dirs'; + + /**#@+ + * Available scope types + */ + const SCOPE_TYPE_STORE = 'store'; + const SCOPE_TYPE_GROUP = 'group'; + const SCOPE_TYPE_WEBSITE = 'website'; + /**#@-*/ + const XML_PATH_INSTALL_DATE = 'global/install/date'; const XML_PATH_SKIP_PROCESS_MODULES_UPDATES = 'global/skip_process_modules_updates'; @@ -74,10 +102,6 @@ class Mage_Core_Model_App */ const ADMIN_STORE_ID = 0; - /** - * Dependency injection configuration node name - */ - const CONFIGURATION_DI_NODE = 'di'; /** * Application loaded areas array @@ -121,6 +145,13 @@ class Mage_Core_Model_App */ protected $_design; + /** + * Initialization parameters + * + * @var array + */ + protected $_initParams = null; + /** * Application configuration object * @@ -210,7 +241,6 @@ class Mage_Core_Model_App */ protected $_response; - /** * Events cache * @@ -268,32 +298,32 @@ class Mage_Core_Model_App /** * Initialize application without request processing * - * @param string|array $code - * @param string $type - * @param string|array $options + * @param array $params * @return Mage_Core_Model_App */ - public function init($code, $type = null, $options = array()) + public function init(array $params) { $this->_initEnvironment(); - if (is_string($options)) { - $options = array('etc_dir'=>$options); - } + $this->_initParams = $params; + $this->_initFilesystem(); + $logger = $this->_initLogger(); Magento_Profiler::start('init_config'); - $this->_config = Mage::getConfig(); - $this->_config->setOptions($options); + /** @var $config Mage_Core_Model_Config */ + $config = $this->_objectManager->create('Mage_Core_Model_Config'); + $this->_config = $config; $this->_initBaseConfig(); - $logger = $this->_initLogger(); $this->_initCache(); - $this->_config->init($options); + $this->_config->init(); $this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS); - $this->loadDiConfiguration(); Magento_Profiler::stop('init_config'); - if (Mage::isInstalled($options)) { - $this->_initCurrentStore($code, $type); - $logger->initForStore($this->_store); + if (Mage::isInstalled()) { + $this->_initCurrentStore( + $this->getInitParam(self::INIT_OPTION_SCOPE_CODE), + $this->getInitParam(self::INIT_OPTION_SCOPE_TYPE) ?: self::SCOPE_TYPE_STORE + ); + $logger->initForStore($this->_store, $this->_config); $this->_initRequest(); } return $this; @@ -302,19 +332,21 @@ class Mage_Core_Model_App /** * Common logic for all run types * - * @param string|array $options + * @param array $params * @return Mage_Core_Model_App */ - public function baseInit($options) + public function baseInit(array $params) { $this->_initEnvironment(); + $this->_initParams = $params; + $this->_initFilesystem(); + $this->_initLogger(); - $this->_config = Mage::getConfig(); - $this->_config->setOptions($options); - + /** @var $config Mage_Core_Model_Config */ + $config = $this->_objectManager->get('Mage_Core_Model_Config'); + $this->_config = $config; $this->_initBaseConfig(); - $cacheInitOptions = is_array($options) && array_key_exists('cache', $options) ? $options['cache'] : array(); - $this->_initCache($cacheInitOptions); + $this->_initCache($this->getInitParam(Mage_Core_Model_Cache::APP_INIT_PARAM) ?: array()); return $this; } @@ -324,43 +356,37 @@ class Mage_Core_Model_App * * @see Mage_Core_Model_App->run() * - * @param string|array $scopeCode - * @param string $scopeType - * @param string|array $options + * @param array $params * @param string|array $modules * @return Mage_Core_Model_App */ - public function initSpecified($scopeCode, $scopeType = null, $options = array(), $modules = array()) + public function initSpecified(array $params, $modules = array()) { - $this->baseInit($options); + $this->baseInit($params); if (!empty($modules)) { $this->_config->addAllowedModules($modules); } $this->_initModules(); - $this->_initCurrentStore($scopeCode, $scopeType); + $this->_initCurrentStore( + $this->getInitParam(self::INIT_OPTION_SCOPE_CODE), + $this->getInitParam(self::INIT_OPTION_SCOPE_TYPE) ?: self::SCOPE_TYPE_STORE + ); return $this; } /** * Run application. Run process responsible for request processing and sending response. - * List of supported parameters: - * scope_code - code of default scope (website/store_group/store code) - * scope_type - type of default scope (website/group/store) - * options - configuration options * - * @param array $params application run parameters + * @param array $params * @return Mage_Core_Model_App */ - public function run($params) + public function run(array $params) { - $options = isset($params['options']) ? $params['options'] : array(); - Magento_Profiler::start('init'); - $this->baseInit($options); - Mage::register('application_params', $params); + $this->baseInit($params); Magento_Profiler::stop('init'); @@ -368,16 +394,18 @@ class Mage_Core_Model_App $this->getResponse()->sendResponse(); } else { Magento_Profiler::start('init'); - $logger = $this->_initLogger(); + $this->_initModules(); $this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS); - $this->loadDiConfiguration(); if ($this->_config->isLocalConfigLoaded()) { - $scopeCode = isset($params['scope_code']) ? $params['scope_code'] : ''; - $scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store'; - $this->_initCurrentStore($scopeCode, $scopeType); - $logger->initForStore($this->_store); + $this->_initCurrentStore( + $this->getInitParam(self::INIT_OPTION_SCOPE_CODE), + $this->getInitParam(self::INIT_OPTION_SCOPE_TYPE) ?: self::SCOPE_TYPE_STORE + ); + /** @var $logger Mage_Core_Model_Logger */ + $logger = $this->_objectManager->get('Mage_Core_Model_Logger'); + $logger->initForStore($this->_store, $this->_config); $this->_initRequest(); Mage_Core_Model_Resource_Setup::applyAllDataUpdates(); } @@ -389,6 +417,19 @@ class Mage_Core_Model_App return $this; } + /** + * Get initialization parameter + * + * Returns false if key does not exist in array or the value is null + * + * @param string $key + * @return mixed|bool + */ + public function getInitParam($key) + { + return isset($this->_initParams[$key]) ? $this->_initParams[$key] : false; + } + /** * Whether the application has been installed or not * @@ -423,6 +464,23 @@ class Mage_Core_Model_App return $this; } + /** + * Create necessary directories in the file system + */ + protected function _initFileSystem() + { + $customDirs = $this->getInitParam(self::INIT_OPTION_URIS) ?: array(); + $customPaths = $this->getInitParam(self::INIT_OPTION_DIRS) ?: array(); + $dirs = new Mage_Core_Model_Dir(BP, $customDirs, $customPaths); + $this->_objectManager->addSharedInstance($dirs, 'Mage_Core_Model_Dir'); + foreach (Mage_Core_Model_Dir::getWritableDirCodes() as $code) { + $path = $dirs->getDir($code); + if ($path && !is_dir($path)) { + mkdir($path); + } + } + } + /** * Initialize base system configuration (local.xml and config.xml files). * Base configuration provide ability initialize DB connection and cache backend @@ -488,7 +546,7 @@ class Mage_Core_Model_App protected function _initLogger() { /** @var $logger Mage_Core_Model_Logger */ - $logger = $this->_objectManager->get('Mage_Core_Model_Logger'); + $logger = $this->_objectManager->create('Mage_Core_Model_Logger'); $logger->addStreamLog(Mage_Core_Model_Logger::LOGGER_SYSTEM) ->addStreamLog(Mage_Core_Model_Logger::LOGGER_EXCEPTION); return $logger; @@ -540,16 +598,16 @@ class Mage_Core_Model_App if (empty($scopeCode) && !is_null($this->_website)) { $scopeCode = $this->_website->getCode(); - $scopeType = 'website'; + $scopeType = self::SCOPE_TYPE_WEBSITE; } switch ($scopeType) { - case Mage_Core_Model_App_Options::APP_RUN_TYPE_STORE: + case self::SCOPE_TYPE_STORE: $this->_currentStore = $scopeCode; break; - case Mage_Core_Model_App_Options::APP_RUN_TYPE_GROUP: + case self::SCOPE_TYPE_GROUP: $this->_currentStore = $this->_getStoreByGroup($scopeCode); break; - case Mage_Core_Model_App_Options::APP_RUN_TYPE_WEBSITE: + case self::SCOPE_TYPE_WEBSITE: $this->_currentStore = $this->_getStoreByWebsite($scopeCode); break; default: @@ -1109,7 +1167,7 @@ class Mage_Core_Model_App public function getGroup($id = null) { if (is_null($id)) { - $id = $this->getStore()->getGroup()->getId(); + $id = $this->getStore()->getGroupId(); } elseif ($id instanceof Mage_Core_Model_Store_Group) { return $id; } @@ -1612,18 +1670,4 @@ class Mage_Core_Model_App { return Mage::getIsDeveloperMode(); } - - /** - * Load di configuration for given area - * - * @param string $areaCode - */ - public function loadDiConfiguration($areaCode = Mage_Core_Model_App_Area::AREA_GLOBAL) - { - $configurationNode = $this->_config->getNode($areaCode . '/' . self::CONFIGURATION_DI_NODE); - if ($configurationNode) { - $configuration = $configurationNode->asArray(); - $this->_objectManager->setConfiguration($configuration); - } - } } diff --git a/app/code/core/Mage/Core/Model/App/Emulation.php b/app/code/core/Mage/Core/Model/App/Emulation.php index b1dd0f4178f..438c732d9ee 100644 --- a/app/code/core/Mage/Core/Model/App/Emulation.php +++ b/app/code/core/Mage/Core/Model/App/Emulation.php @@ -130,7 +130,7 @@ class Mage_Core_Model_App_Emulation extends Varien_Object 'store' => Mage::app()->getStore() ); - $storeTheme = $design->getConfigurationDesignTheme($area, array('useId' => true, 'store' => $storeId)); + $storeTheme = $design->getConfigurationDesignTheme($area, array('store' => $storeId)); $design->setDesignTheme($storeTheme, $area); if ($area == Mage_Core_Model_App_Area::AREA_FRONTEND) { diff --git a/app/code/core/Mage/Core/Model/App/Options.php b/app/code/core/Mage/Core/Model/App/Options.php deleted file mode 100644 index 960dc267a36..00000000000 --- a/app/code/core/Mage/Core/Model/App/Options.php +++ /dev/null @@ -1,133 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Mage - * @package Mage_Core - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -class Mage_Core_Model_App_Options -{ - /**@+ - * Application option names - */ - const OPTION_APP_RUN_CODE = 'MAGE_RUN_CODE'; - const OPTION_APP_RUN_TYPE = 'MAGE_RUN_TYPE'; - const OPTION_LOCAL_CONFIG_EXTRA_FILE = 'MAGE_LOCAL_CONFIG'; - /**@-*/ - - /**@+ - * Supported application run types - */ - const APP_RUN_TYPE_STORE = 'store'; - const APP_RUN_TYPE_GROUP = 'group'; - const APP_RUN_TYPE_WEBSITE = 'website'; - /**@-*/ - - /** - * Shorthand for the list of supported application run types - * - * @var array - */ - protected $_supportedRunTypes = array( - self::APP_RUN_TYPE_STORE, self::APP_RUN_TYPE_GROUP, self::APP_RUN_TYPE_WEBSITE - ); - - /** - * Store or website code - * - * @var string - */ - protected $_runCode = ''; - - /** - * Run store or run website - * - * @var string - */ - protected $_runType = self::APP_RUN_TYPE_STORE; - - /** - * Application run options - * - * @var array - */ - protected $_runOptions = array(); - - /** - * Constructor - * - * @param array $options Source of option values - * @throws InvalidArgumentException - */ - public function __construct(array $options) - { - if (isset($options[self::OPTION_APP_RUN_CODE])) { - $this->_runCode = $options[self::OPTION_APP_RUN_CODE]; - } - - if (isset($options[self::OPTION_APP_RUN_TYPE])) { - $this->_runType = $options[self::OPTION_APP_RUN_TYPE]; - if (!in_array($this->_runType, $this->_supportedRunTypes)) { - throw new InvalidArgumentException(sprintf( - 'Application run type "%s" is not recognized, supported values: "%s".', - $this->_runType, - implode('", "', $this->_supportedRunTypes) - )); - } - } - - if (!empty($options[self::OPTION_LOCAL_CONFIG_EXTRA_FILE])) { - $localConfigFile = $options[self::OPTION_LOCAL_CONFIG_EXTRA_FILE]; - $this->_runOptions[Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE] = $localConfigFile; - } - } - - /** - * Retrieve application run code - * - * @return string - */ - public function getRunCode() - { - return $this->_runCode; - } - - /** - * Retrieve application run type - * - * @return string - */ - public function getRunType() - { - return $this->_runType; - } - - /** - * Retrieve application run options - * - * @return array - */ - public function getRunOptions() - { - return $this->_runOptions; - } -} diff --git a/app/code/core/Mage/Core/Model/Cache.php b/app/code/core/Mage/Core/Model/Cache.php index 9104d3f6302..217f503840b 100644 --- a/app/code/core/Mage/Core/Model/Cache.php +++ b/app/code/core/Mage/Core/Model/Cache.php @@ -37,9 +37,9 @@ class Mage_Core_Model_Cache const XML_PATH_TYPES = 'global/cache/types'; /** - * @var Mage_Core_Model_Config + * Inject custom cache settings in application initialization */ - protected $_config; + const APP_INIT_PARAM = 'cache'; /** * @var Mage_Core_Helper_Abstract @@ -107,17 +107,25 @@ class Mage_Core_Model_Cache */ protected $_allowedCacheOptions = null; + /** + * @var Magento_ObjectManager + */ + protected $_objectManager; + /** * Class constructor. Initialize cache instance based on options * + * @param Mage_Core_Model_App $app + * @param Mage_Core_Model_Dir $dirs * @param array $options */ - public function __construct(array $options = array()) + public function __construct(Magento_ObjectManager $objectManager, array $options = array()) { - $this->_config = isset($options['config']) ? $options['config'] : Mage::getConfig(); + $this->_objectManager = $objectManager; $this->_helper = isset($options['helper']) ? $options['helper'] : Mage::helper('Mage_Core_Helper_Data'); - $this->_defaultBackendOptions['cache_dir'] = $this->_config->getOptions()->getDir('cache'); + $dirs = $objectManager->get('Mage_Core_Model_Dir'); + $this->_defaultBackendOptions['cache_dir'] = $dirs->getDir(Mage_Core_Model_Dir::CACHE); /** * Initialize id prefix */ @@ -126,7 +134,7 @@ class Mage_Core_Model_Cache $this->_idPrefix = $options['prefix']; } if (empty($this->_idPrefix)) { - $this->_idPrefix = substr(md5($this->_config->getOptions()->getEtcDir()), 0, 3).'_'; + $this->_idPrefix = substr(md5($dirs->getDir(Mage_Core_Model_Dir::CONFIG)), 0, 3) . '_'; } $backend = $this->_getBackendOptions($options); @@ -563,7 +571,7 @@ class Mage_Core_Model_Cache $this->_allowedCacheOptions = unserialize($options); } - if ($this->_config->getOptions()->getData('global_ban_use_cache')) { + if ($this->_objectManager->get('Mage_Core_Model_App')->getInitParam('global_ban_use_cache')) { foreach ($this->_allowedCacheOptions as $key => $val) { $this->_allowedCacheOptions[$key] = false; } @@ -641,7 +649,7 @@ class Mage_Core_Model_Cache public function getTagsByType($type) { $path = self::XML_PATH_TYPES.'/'.$type.'/tags'; - $tagsConfig = $this->_config->getNode($path); + $tagsConfig = $this->_objectManager->get('Mage_Core_Model_Config')->getNode($path); if ($tagsConfig) { $tags = (string) $tagsConfig; $tags = explode(',', $tags); @@ -659,7 +667,7 @@ class Mage_Core_Model_Cache public function getTypes() { $types = array(); - $config = $this->_config->getNode(self::XML_PATH_TYPES); + $config = $this->_objectManager->get('Mage_Core_Model_Config')->getNode(self::XML_PATH_TYPES); if ($config) { foreach ($config->children() as $type=>$node) { $types[$type] = new Varien_Object(array( diff --git a/app/code/core/Mage/Core/Model/Config.php b/app/code/core/Mage/Core/Model/Config.php index 9ca5a3418cb..788c0ced759 100644 --- a/app/code/core/Mage/Core/Model/Config.php +++ b/app/code/core/Mage/Core/Model/Config.php @@ -1,7 +1,5 @@ <?php /** - * Core configuration class - * * Magento * * NOTICE OF LICENSE @@ -20,12 +18,15 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * + * @category Mage + * @package Mage_Core * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - /** + * Core configuration class + * * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.ExcessivePublicCount) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) @@ -33,6 +34,11 @@ */ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base { + /** + * Dependency injection configuration node name + */ + const CONFIGURATION_DI_NODE = 'di'; + /** * Configuration cache tag */ @@ -48,12 +54,15 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ const SCOPE_WEBSITES = 'websites'; - /**@+ - * Option key names + /** + * Read additional file during initialization + */ + const INIT_OPTION_EXTRA_FILE = 'MAGE_CONFIG_FILE'; + + /** + * Read additional data (XML-string) during initialization */ - const OPTION_LOCAL_CONFIG_EXTRA_FILE = 'local_config'; - const OPTION_LOCAL_CONFIG_EXTRA_DATA = 'local_config_extra_data'; - /**@-*/ + const INIT_OPTION_EXTRA_DATA = 'MAGE_CONFIG_DATA'; /** * Local configuration file @@ -102,13 +111,6 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ protected $_cacheLoadedSections = array(); - /** - * Configuration options - * - * @var Mage_Core_Model_Config_Options - */ - protected $_options; - /** * Storage for generated class names * @@ -130,20 +132,6 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ protected $_secureUrlCache = array(); - /** - * System environment server variables - * - * @var array - */ - protected $_distroServerVars; - - /** - * Array which is using for replace placeholders of server variables - * - * @var array - */ - protected $_substServerVars; - /** * Resource model * Used for operations with DB @@ -268,11 +256,6 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base { $this->_objectManager = $objectManager; $this->setCacheId('config_global'); - $options = $sourceData; - if (!is_array($options)) { - $options = array($options); - } - $this->_options = $this->_objectManager->create('Mage_Core_Model_Config_Options', array('data' => $options)); $this->_prototype = $this->_objectManager->create('Mage_Core_Model_Config_Base'); $this->_prototype->loadString('<config/>'); $this->_cacheChecksum = null; @@ -305,41 +288,15 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base return $this->_configDataModel; } - /** - * Get configuration options object - * - * @return Mage_Core_Model_Config_Options - */ - public function getOptions() - { - return $this->_options; - } - - /** - * Set configuration options - * - * @param array $options - * @return Mage_Core_Model_Config - */ - public function setOptions($options) - { - if (is_array($options)) { - $this->getOptions()->addData($options); - } - return $this; - } - /** * Initialization of core configuration * - * @param array $options * @return Mage_Core_Model_Config */ - public function init($options = array()) + public function init() { $this->setCacheChecksum(null); $this->_cacheLoadedSections = array(); - $this->setOptions($options); $this->loadBase(); $cacheLoad = $this->loadModulesCache(); @@ -360,7 +317,9 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ public function loadBase() { - $etcDir = $this->getOptions()->getEtcDir(); + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = $this->_objectManager->get('Mage_Core_Model_Dir'); + $etcDir = $dirs->getDir(Mage_Core_Model_Dir::CONFIG); if (!$this->getNode()) { $this->loadString('<config/>'); } @@ -386,7 +345,11 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ protected function _loadLocalConfig() { - $etcDir = $this->getOptions()->getEtcDir(); + /** @var $app Mage_Core_Model_App */ + $app = $this->_objectManager->get('Mage_Core_Model_App'); + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = $this->_objectManager->get('Mage_Core_Model_Dir'); + $etcDir = $dirs->getDir(Mage_Core_Model_Dir::CONFIG); $localConfigParts = array(); $localConfigFile = $etcDir . DIRECTORY_SEPARATOR . self::LOCAL_CONFIG_FILE; @@ -397,7 +360,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base $localConfigParts[] = $localConfig; // 2. app/etc/<dir>/<file>.xml - $localConfigExtraFile = $this->getOptions()->getData(self::OPTION_LOCAL_CONFIG_EXTRA_FILE); + $localConfigExtraFile = $app->getInitParam(self::INIT_OPTION_EXTRA_FILE); if (preg_match('/^[a-z\d_-]+\/[a-z\d_-]+\.xml$/', $localConfigExtraFile)) { $localConfigExtraFile = $etcDir . DIRECTORY_SEPARATOR . $localConfigExtraFile; $localConfig = clone $this->_prototype; @@ -407,7 +370,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base } // 3. extra local configuration string - $localConfigExtraData = $this->getOptions()->getData(self::OPTION_LOCAL_CONFIG_EXTRA_DATA); + $localConfigExtraData = $app->getInitParam(self::INIT_OPTION_EXTRA_DATA); if ($localConfigExtraData) { $localConfig = clone $this->_prototype; $localConfig->loadString($localConfigExtraData); @@ -451,7 +414,9 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ public function loadLocales() { - $localeDir = $this->getOptions()->getLocaleDir(); + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = $this->_objectManager->get('Mage_Core_Model_Dir'); + $localeDir = $dirs->getDir(Mage_Core_Model_Dir::LOCALE); $files = glob($localeDir . DS . '*' . DS . 'config.xml'); if (is_array($files) && !empty($files)) { @@ -478,6 +443,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base Magento_Profiler::stop('init_modules_config_cache'); if ($loaded) { $this->_useCache = true; + $this->loadDiConfiguration(); return true; } } @@ -505,11 +471,26 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base $this->_loadLocalConfig(); $this->applyExtends(); + $this->loadDiConfiguration(); Magento_Profiler::stop('load_modules'); Magento_Profiler::stop('config'); return $this; } + /** + * Load di configuration for given area + * + * @param string $areaCode + */ + public function loadDiConfiguration($areaCode = Mage_Core_Model_App_Area::AREA_GLOBAL) + { + $configurationNode = $this->getNode($areaCode . '/' . self::CONFIGURATION_DI_NODE); + if ($configurationNode) { + $configuration = $configurationNode->asArray(); + $this->_objectManager->setConfiguration($configuration); + } + } + /** * Check if local configuration (DB connection, etc) is loaded * @@ -541,14 +522,13 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base /** * Reinitialize configuration * - * @param array $options - * @return Mage_Core_Model_Config + * @return Mage_Core_Model_Config */ - public function reinit($options = array()) + public function reinit() { $this->_allowCacheForInit = false; $this->_useCache = false; - return $this->init($options); + return $this->init(); } /** @@ -588,7 +568,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base * @param array $tags cache tags * @return Mage_Core_Model_Config */ - public function saveCache($tags=array()) + public function saveCache($tags = array()) { if (!Mage::app()->useCache('config')) { return $this; @@ -664,7 +644,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ if (!$xmlString) { $this->_useCache = false; - $this->reinit($this->_options); + $this->reinit(); return false; } else { $xml = simplexml_load_string($xmlString, $this->_elementClass); @@ -876,7 +856,9 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ protected function _getDeclaredModuleFiles() { - $codeDir = $this->getOptions()->getCodeDir(); + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = $this->_objectManager->get('Mage_Core_Model_Dir'); + $codeDir = $dirs->getDir(Mage_Core_Model_Dir::MODULES); $moduleFiles = glob($codeDir . DS . '*' . DS . '*' . DS . '*' . DS . 'etc' . DS . 'config.xml'); if (!$moduleFiles) { @@ -900,7 +882,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base } } - $etcDir = $this->getOptions()->getEtcDir(); + $etcDir = $dirs->getDir(Mage_Core_Model_Dir::CONFIG); $additionalFiles = glob($etcDir . DS . 'modules' . DS . '*.xml'); foreach ($additionalFiles as $v) { @@ -1112,15 +1094,6 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base } return $result; } - /** - * Retrieve temporary directory path - * - * @return string - */ - public function getTempVarDir() - { - return $this->getOptions()->getVarDir(); - } /** * Get default server variables values @@ -1128,57 +1101,23 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @return array */ - public function getDistroServerVars() + public function getDistroBaseUrl() { - if (!$this->_distroServerVars) { + if (isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['HTTP_HOST'])) { + $secure = (!empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] != 'off')) + || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443'); + $scheme = ($secure ? 'https' : 'http') . '://' ; - if (isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['HTTP_HOST'])) { - $secure = (!empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] != 'off')) - || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443'); - $scheme = ($secure ? 'https' : 'http') . '://' ; + $hostArr = explode(':', $_SERVER['HTTP_HOST']); + $host = $hostArr[0]; + $port = isset($hostArr[1]) && (!$secure && $hostArr[1] != 80 || $secure && $hostArr[1] != 443) + ? ':'. $hostArr[1] + : ''; + $path = Mage::app()->getRequest()->getBasePath(); - $hostArr = explode(':', $_SERVER['HTTP_HOST']); - $host = $hostArr[0]; - $port = ''; - if (isset($hostArr[1]) && (!$secure && $hostArr[1] != 80 || $secure && $hostArr[1] != 443)) { - $port = ':' . $hostArr[1]; - } - $path = Mage::app()->getRequest()->getBasePath(); - - $baseUrl = $scheme . $host . $port . rtrim($path, '/') . '/'; - } else { - $baseUrl = 'http://localhost/'; - } - - $options = $this->getOptions(); - $this->_distroServerVars = array( - 'root_dir' => $options->getBaseDir(), - 'app_dir' => $options->getAppDir(), - 'var_dir' => $options->getVarDir(), - 'base_url' => $baseUrl, - ); - - foreach ($this->_distroServerVars as $k => $v) { - $this->_substServerVars['{{' . $k . '}}'] = $v; - } + return $scheme . $host . $port . rtrim($path, '/') . '/'; } - return $this->_distroServerVars; - } - - /** - * Replace distro vars with values - * - * @param array $data - * @return string|array - */ - public function substDistroServerVars($data) - { - $this->getDistroServerVars(); - return str_replace( - array_keys($this->_substServerVars), - array_values($this->_substServerVars), - $data - ); + return 'http://localhost/'; } /** @@ -1222,33 +1161,6 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base return new $className($module); } - /** - * Get temporary data directory name - * - * @param string $path - * @param string $type - * @return string - */ - public function getVarDir($path = null, $type = 'var') - { - $dir = Mage::getBaseDir($type) . ($path !== null ? DS . $path : ''); - if (!$this->createDirIfNotExists($dir)) { - return false; - } - return $dir; - } - - /** - * Create dir if not exists - * - * @param string $dir - * @return bool - */ - public function createDirIfNotExists($dir) - { - return $this->getOptions()->createDirIfNotExists($dir); - } - /** * Get module directory by directory type * @@ -1263,7 +1175,9 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base } $codePool = (string)$this->getModuleConfig($moduleName)->codePool; - $dir = $this->getOptions()->getCodeDir() . DS . $codePool . DS . uc_words($moduleName, DS); + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = $this->_objectManager->get('Mage_Core_Model_Dir'); + $dir = $dirs->getDir(Mage_Core_Model_Dir::MODULES) . DS . $codePool . DS . uc_words($moduleName, DS); switch ($type) { case 'etc': @@ -1705,6 +1619,26 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base return $areas[$areaCode]; } + /** + * Identify front name of the requested area. Return current area front name if area code is not specified. + * + * @param string|null $areaCode + * @return string + * @throws LogicException If front name is not defined. + */ + public function getAreaFrontName($areaCode = null) + { + $areaCode = empty($areaCode) ? $this->getCurrentAreaCode() : $areaCode; + $areaConfig = $this->getAreaConfig($areaCode); + if (!isset($areaConfig['frontName'])) { + throw new LogicException(sprintf( + 'Area "%s" must have front name defined in the application config.', + $areaCode + )); + } + return $areaConfig['frontName']; + } + /** * Load allowed areas from config * @@ -1723,7 +1657,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base continue; } /** - * TODO: Check of 'routers' nodes existance is excessive: + * TODO: Check of 'routers' nodes existence is excessive: * TODO: 'routers' check is moved Mage_Core_Model_Config::getRouters() */ @@ -1810,7 +1744,6 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ public function __destruct() { - $this->_cacheLoadedSections = array(); $this->_prototype = null; parent::__destruct(); } diff --git a/app/code/core/Mage/Core/Model/Config/Options.php b/app/code/core/Mage/Core/Model/Config/Options.php deleted file mode 100644 index 216ad012cbf..00000000000 --- a/app/code/core/Mage/Core/Model/Config/Options.php +++ /dev/null @@ -1,325 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Mage - * @package Mage_Core - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -/** - * Configuration options storage and logic - * - * @category Mage - * @package Mage_Core - * @author Magento Core Team <core@magentocommerce.com> - */ -class Mage_Core_Model_Config_Options extends Varien_Object -{ - /** - * Var directory - * - * @var string - */ - const VAR_DIRECTORY = 'var'; - - /** - * Public directory - * - * @var string - */ - const PUB_DIRECTORY = 'pub'; - - /** - * Flag cache for existing or already created directories - * - * @var array - */ - protected $_dirExists = array(); - - /** - * Flag cache for existing or already created directories - * - * @var array - */ - protected $_io; - - /** - * Initialize default values of the options - * - * @param array $data - */ - public function __construct(array $data = array()) - { - $this->_io = isset($data['io']) ? $data['io'] : new Varien_Io_File(); - unset ($data['io']); - parent::__construct($data); - $appRoot = isset($data['app_dir']) ? $data['app_dir'] : Mage::getRoot(); - $root = dirname($appRoot); - - $this->_data['app_dir'] = $appRoot; - $this->_data['base_dir'] = $root; - $this->_data['code_dir'] = $appRoot . DIRECTORY_SEPARATOR . 'code'; - $this->_data['design_dir'] = $appRoot . DIRECTORY_SEPARATOR . 'design'; - $this->_data['etc_dir'] = $appRoot . DIRECTORY_SEPARATOR . 'etc'; - $this->_data['lib_dir'] = $root . DIRECTORY_SEPARATOR . 'lib'; - $this->_data['locale_dir'] = $appRoot . DIRECTORY_SEPARATOR . 'locale'; - $this->_data['pub_dir'] = $root . DIRECTORY_SEPARATOR . 'pub'; - $this->_data['js_dir'] = $this->_data['pub_dir'] . DIRECTORY_SEPARATOR . 'lib'; - $this->_data['media_dir'] = isset($data['media_dir']) - ? $data['media_dir'] - : $this->_data['pub_dir'] . DIRECTORY_SEPARATOR . 'media'; - $this->_data['var_dir'] = $this->getVarDir(); - $this->_data['tmp_dir'] = $this->_data['var_dir'] . DIRECTORY_SEPARATOR . 'tmp'; - $this->_data['cache_dir'] = $this->_data['var_dir'] . DIRECTORY_SEPARATOR . 'cache'; - $this->_data['log_dir'] = $this->_data['var_dir'] . DIRECTORY_SEPARATOR . 'log'; - $this->_data['session_dir'] = $this->_data['var_dir'] . DIRECTORY_SEPARATOR . 'session'; - $this->_data['upload_dir'] = $this->_data['media_dir'] . DIRECTORY_SEPARATOR . 'upload'; - $this->_data['export_dir'] = $this->_data['var_dir'] . DIRECTORY_SEPARATOR . 'export'; - } - - /** - * Directory getter that returm path to directory based on path - * - * @throws Mage_Core_Exception - * @param string $type - * @return string - */ - public function getDir($type) - { - $method = 'get'.ucwords($type).'Dir'; - $dir = $this->$method(); - if (!$dir) { - throw Mage::exception('Mage_Core', 'Invalid dir type requested: '.$type); - } - return $dir; - } - - /** - * Application folder paths getter - * - * @return string - */ - public function getAppDir() - { - return $this->_data['app_dir']; - } - - /** - * Base folder paths getter - * - * @return string - */ - public function getBaseDir() - { - return $this->_data['base_dir']; - } - - /** - * Code folder paths getter - * - * @return string - */ - public function getCodeDir() - { - return $this->_data['code_dir']; - } - - /** - * Design folder paths getter - * - * @return string - */ - public function getDesignDir() - { - return $this->_data['design_dir']; - } - - /** - * Configuration (etc) folder paths getter - * - * @return string - */ - public function getEtcDir() - { - return $this->_data['etc_dir']; - } - - /** - * Libraries folder paths getter - * - * @return string - */ - public function getLibDir() - { - return $this->_data['lib_dir']; - } - - /** - * Locale folder paths getter - * - * @return string - */ - public function getLocaleDir() - { - return $this->_data['locale_dir']; - } - - /** - * Public folder paths getter - * - * @return string - */ - public function getPubDir() - { - return $this->_data['pub_dir']; - } - - /** - * JS libraries folder paths getter - * - * @return string - */ - public function getJsDir() - { - return $this->_data['js_dir']; - } - - /** - * Media folder paths getter - * - * @return string - */ - public function getMediaDir() - { - return $this->_data['media_dir']; - } - - /** - * Var folder paths getter - * - * @return string - * @throws Mage_Core_Exception - */ - public function getVarDir() - { - $dir = isset($this->_data['var_dir']) ? $this->_data['var_dir'] - : $this->_data['base_dir'] . DIRECTORY_SEPARATOR . self::VAR_DIRECTORY; - if (!$this->createDirIfNotExists($dir)) { - throw new Mage_Core_Exception('Unable to find writable var_dir'); - } - return $dir; - } - - /** - * Temporary folder paths getter - * - * @return string - * @throws Mage_Core_Exception - */ - public function getTmpDir() - { - $dir = $this->_data['tmp_dir']; - if (!$this->createDirIfNotExists($dir)) { - throw new Mage_Core_Exception('Unable to find writable tmp_dir'); - } - return $dir; - } - - /** - * Cache folder paths getter - * - * @return string - */ - public function getCacheDir() - { - $dir = $this->_data['cache_dir']; - $this->createDirIfNotExists($dir); - return $dir; - } - - /** - * Log folder paths getter - * - * @return string - */ - public function getLogDir() - { - $dir = $this->_data['log_dir']; - $this->createDirIfNotExists($dir); - return $dir; - } - - /** - * Session folder paths getter - * - * @return string - */ - public function getSessionDir() - { - $dir = $this->_data['session_dir']; - $this->createDirIfNotExists($dir); - return $dir; - } - - /** - * Files upload folder paths getter - * - * @return string - */ - public function getUploadDir() - { - $dir = $this->_data['upload_dir']; - $this->createDirIfNotExists($dir); - return $dir; - } - - /** - * Export files folder paths getter - * - * @return string - */ - public function getExportDir() - { - $dir = $this->_data['export_dir']; - $this->createDirIfNotExists($dir); - return $dir; - } - - /** - * Create writable directory if it not exists - * - * @param string - * @return bool - */ - public function createDirIfNotExists($dir) - { - if (!empty($this->_dirExists[$dir])) { - return true; - } - try { - $this->_io->checkAndCreateFolder($dir); - } catch (Exception $e) { - return false; - } - $this->_dirExists[$dir] = true; - return true; - } -} diff --git a/app/code/core/Mage/Core/Model/Design/Fallback.php b/app/code/core/Mage/Core/Model/Design/Fallback.php index e35d351afc5..a12d50f48e5 100644 --- a/app/code/core/Mage/Core/Model/Design/Fallback.php +++ b/app/code/core/Mage/Core/Model/Design/Fallback.php @@ -49,22 +49,75 @@ class Mage_Core_Model_Design_Fallback implements Mage_Core_Model_Design_Fallback */ protected $_appConfig; + /** + * @var Mage_Core_Model_Dir + */ + protected $_dirs = null; + + /** + * @var Magento_ObjectManager|null + */ + protected $_objectManager = null; + /** * Constructor. * Following entries in $params are required: 'area', 'package', 'theme', 'locale'. The 'appConfig' and * 'themeConfig' may contain application config and theme config, respectively. If these these entries are not * present or null, then they will be retrieved from global application instance. * + * @param Mage_Core_Model_Dir $dirs + * @param Magento_ObjectManager $objectManager * @param Magento_Filesystem $filesystem - * @param array $data + * @param array $params + * @throws InvalidArgumentException */ - public function __construct(Magento_Filesystem $filesystem, $data) - { + public function __construct( + Mage_Core_Model_Dir $dirs, + Magento_ObjectManager $objectManager, + Magento_Filesystem $filesystem, + $params + ) { + $this->_dirs = $dirs; + $this->_objectManager = $objectManager; $this->_filesystem = $filesystem; - $this->_area = $data['area']; - $this->_locale = $data['locale']; - $this->_theme = $data['themeModel']; - $this->_appConfig = isset($data['appConfig']) ? $data['appConfig'] : Mage::getConfig(); + if (!array_key_exists('area', $params) || !array_key_exists('themeModel', $params) + || !array_key_exists('locale', $params) + ) { + throw new InvalidArgumentException("Missing one of the param keys: 'area', 'themeModel', 'locale'."); + } + $this->_area = $params['area']; + $this->_theme = $params['themeModel']; + $this->_locale = $params['locale']; + } + + /** + * Get area code + * + * @return string + */ + public function getArea() + { + return $this->_area; + } + + /** + * Get theme code + * + * @return string + */ + public function getTheme() + { + return $this->_theme->getThemeCode(); + } + + /** + * Get locale code + * + * @return null|string + */ + public function getLocale() + { + return $this->_locale; } /** @@ -76,7 +129,7 @@ class Mage_Core_Model_Design_Fallback implements Mage_Core_Model_Design_Fallback */ public function getFile($file, $module = null) { - $dir = $this->_appConfig->getOptions()->getDesignDir(); + $dir = $this->_dirs->getDir(Mage_Core_Model_Dir::THEMES); $dirs = array(); $themeModel = $this->_theme; while ($themeModel) { @@ -85,7 +138,12 @@ class Mage_Core_Model_Design_Fallback implements Mage_Core_Model_Design_Fallback $themeModel = $themeModel->getParentTheme(); } - $moduleDir = $module ? array($this->_appConfig->getModuleDir('view', $module) . "/{$this->_area}") : array(); + if ($module) { + $moduleDir = array($this->_objectManager->get('Mage_Core_Model_Config')->getModuleDir('view', $module) + . "/{$this->_area}"); + } else { + $moduleDir = array(); + } return $this->_fallback($file, $dirs, $module, $moduleDir); } @@ -97,7 +155,7 @@ class Mage_Core_Model_Design_Fallback implements Mage_Core_Model_Design_Fallback */ public function getLocaleFile($file) { - $dir = $this->_appConfig->getOptions()->getDesignDir(); + $dir = $this->_dirs->getDir(Mage_Core_Model_Dir::THEMES); $dirs = array(); $themeModel = $this->_theme; while ($themeModel) { @@ -118,8 +176,8 @@ class Mage_Core_Model_Design_Fallback implements Mage_Core_Model_Design_Fallback */ public function getViewFile($file, $module = null) { - $dir = $this->_appConfig->getOptions()->getDesignDir(); - $moduleDir = $module ? $this->_appConfig->getModuleDir('view', $module) : ''; + $dir = $this->_dirs->getDir(Mage_Core_Model_Dir::THEMES); + $moduleDir = $module ? $this->_objectManager->get('Mage_Core_Model_Config')->getModuleDir('view', $module) : ''; $dirs = array(); $themeModel = $this->_theme; @@ -131,7 +189,7 @@ class Mage_Core_Model_Design_Fallback implements Mage_Core_Model_Design_Fallback } $extraDirs = array( - $this->_appConfig->getOptions()->getJsDir(), + $this->_dirs->getDir(Mage_Core_Model_Dir::PUB_LIB), Mage::getDesign()->getCustomizationDir() ); diff --git a/app/code/core/Mage/Core/Model/Design/Fallback/CachingProxy.php b/app/code/core/Mage/Core/Model/Design/Fallback/CachingProxy.php index 68e23926eea..6d0ab0f4b39 100644 --- a/app/code/core/Mage/Core/Model/Design/Fallback/CachingProxy.php +++ b/app/code/core/Mage/Core/Model/Design/Fallback/CachingProxy.php @@ -30,21 +30,6 @@ */ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_Design_FallbackInterface { - /** - * @var string - */ - protected $_area; - - /** - * @var Mage_Core_Model_Theme - */ - protected $_theme; - - /** - * @var string|null - */ - protected $_locale; - /** * Whether object can save map changes upon destruction * @@ -71,7 +56,7 @@ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_De * * @var array */ - protected $_map; + protected $_map = array(); /** * Proxied fallback model @@ -81,78 +66,62 @@ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_De protected $_fallback; /** - * Directory to keep map file - * - * @var string + * @var Magento_Filesystem */ - protected $_mapDir; + protected $_filesystem; /** * Path to Magento base directory * * @var string */ - protected $_basePath; - - /** - * @var Magento_Filesystem - */ - protected $_filesystem; + protected $_baseDir; /** - * Constructor. - * Following entries in $params are required: 'area', 'package', 'theme', 'locale', 'canSaveMap', - * 'mapDir', 'baseDir'. + * Read the class map according to provided fallback model and parameters * + * @param Mage_Core_Model_Design_Fallback $fallback * @param Magento_Filesystem $filesystem - * @param array $data - */ - public function __construct(Magento_Filesystem $filesystem, array $data = array()) - { + * @param string $mapDir directory where to look the map files in + * @param string $baseDir base directory path to prepend to file paths + * @param bool $canSaveMap whether to update map file in destructor + * @throws InvalidArgumentException + */ + public function __construct( + Mage_Core_Model_Design_Fallback $fallback, + Magento_Filesystem $filesystem, + $mapDir, + $baseDir, + $canSaveMap = true + ) { + $this->_fallback = $fallback; $this->_filesystem = $filesystem; - $this->_area = $data['area']; - $this->_theme = $data['themeModel']; - $this->_locale = $data['locale']; - $this->_canSaveMap = $data['canSaveMap']; - $this->_mapDir = $data['mapDir']; - $this->_basePath = $data['baseDir'] ? $data['baseDir'] . DIRECTORY_SEPARATOR : ''; - - $this->_mapFile = - "{$this->_mapDir}/{$this->_area}_{$this->_theme->getId()}_{$this->_locale}.ser"; - $this->_map = $this->_filesystem->isFile($this->_mapFile) - ? unserialize($this->_filesystem->read($this->_mapFile)) - : array(); + if (!$filesystem->isDirectory($baseDir)) { + throw new InvalidArgumentException("Wrong base directory specified: '{$baseDir}'"); + } + $this->_baseDir = $baseDir; + $this->_canSaveMap = $canSaveMap; + $this->_mapFile = $mapDir . DIRECTORY_SEPARATOR + . "{$fallback->getArea()}_{$fallback->getTheme()}_{$fallback->getLocale()}.ser"; + if ($this->_filesystem->isFile($this->_mapFile)) { + $this->_map = unserialize($this->_filesystem->read($this->_mapFile)); + } } + /** + * Write the serialized class map to the file + */ public function __destruct() { if ($this->_isMapChanged && $this->_canSaveMap) { - if (!$this->_filesystem->isDirectory($this->_mapDir)) { - $this->_filesystem->createDirectory($this->_mapDir, 0777); + $dir = dirname($this->_mapFile); + if (!$this->_filesystem->isDirectory($dir)) { + $this->_filesystem->createDirectory($dir, 0777); } $this->_filesystem->write($this->_mapFile, serialize($this->_map)); } } - /** - * Return instance of fallback model. Create it, if it has not been created yet. - * - * @return Mage_Core_Model_Design_Fallback - */ - protected function _getFallback() - { - if (!$this->_fallback) { - $this->_fallback = Mage::getModel('Mage_Core_Model_Design_Fallback', array( - 'data' => array( - 'area' => $this->_area, - 'themeModel' => $this->_theme, - 'locale' => $this->_locale - ) - )); - } - return $this->_fallback; - } - /** * Return relative file name from map * @@ -167,7 +136,7 @@ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_De if (isset($this->_map[$mapKey])) { $value = $this->_map[$mapKey]; if ((string) $value !== '') { - return $this->_basePath . $value; + return $this->_baseDir . DIRECTORY_SEPARATOR . $value; } else { return $value; } @@ -183,26 +152,23 @@ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_De * @param string $file * @param string|null $module * @param string $filePath - * @return Mage_Core_Model_Design_Fallback_CachingProxy - * @throws Mage_Core_Exception + * @throws Magento_Exception */ protected function _setToMap($prefix, $file, $module, $filePath) { - $basePathLen = strlen($this->_basePath); - if (((string)$filePath !== '') && strncmp($filePath, $this->_basePath, $basePathLen)) { - throw new Mage_Core_Exception( - "Attempt to store fallback path '{$filePath}', which is not within '{$this->_basePath}'" + $pattern = $this->_baseDir . DIRECTORY_SEPARATOR; + if (0 !== strpos($filePath, $pattern, 0)) { + throw new Magento_Exception( + "Attempt to store fallback path '{$filePath}', which is not within '{$pattern}'" ); } - $mapKey = "$prefix|$file|$module"; - $this->_map[$mapKey] = substr($filePath, $basePathLen); + $this->_map[$mapKey] = substr($filePath, strlen($pattern)); $this->_isMapChanged = true; - return $this; } /** - * Get existing file name, using map and fallback mechanism + * Proxy to Mage_Core_Model_Design_Fallback::getFile() * * @param string $file * @param string|null $module @@ -212,14 +178,14 @@ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_De { $result = $this->_getFromMap('theme', $file, $module); if (!$result) { - $result = $this->_getFallback()->getFile($file, $module); + $result = $this->_fallback->getFile($file, $module); $this->_setToMap('theme', $file, $module, $result); } return $result; } /** - * Get locale file name, using map and fallback mechanism + * Proxy to Mage_Core_Model_Design_Fallback::getLocaleFile() * * @param string $file * @return string @@ -228,14 +194,14 @@ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_De { $result = $this->_getFromMap('locale', $file); if (!$result) { - $result = $this->_getFallback()->getLocaleFile($file); + $result = $this->_fallback->getLocaleFile($file); $this->_setToMap('locale', $file, null, $result); } return $result; } /** - * Get Theme file name, using map and fallback mechanism + * Proxy to Mage_Core_Model_Design_Fallback::getViewFile() * * @param string $file * @param string|null $module @@ -245,22 +211,23 @@ class Mage_Core_Model_Design_Fallback_CachingProxy implements Mage_Core_Model_De { $result = $this->_getFromMap('view', $file, $module); if (!$result) { - $result = $this->_getFallback()->getViewFile($file, $module); + $result = $this->_fallback->getViewFile($file, $module); $this->_setToMap('view', $file, $module, $result); } return $result; } /** - * Object notified, that theme file was published, thus it can return published file name on next calls + * Object notified, that view file was published, thus it can return published file name on next calls * * @param string $publicFilePath * @param string $file * @param string|null $module - * @return Mage_Core_Model_Design_FallbackInterface + * @return Mage_Core_Model_Design_Fallback_CachingProxy */ public function notifyViewFilePublished($publicFilePath, $file, $module = null) { - return $this->_setToMap('view', $file, $module, $publicFilePath); + $this->_setToMap('view', $file, $module, $publicFilePath); + return $this; } } diff --git a/app/code/core/Mage/Core/Model/Design/Package.php b/app/code/core/Mage/Core/Model/Design/Package.php index 4be237dd863..97b7c23ad9b 100644 --- a/app/code/core/Mage/Core/Model/Design/Package.php +++ b/app/code/core/Mage/Core/Model/Design/Package.php @@ -84,9 +84,19 @@ class Mage_Core_Model_Design_Package /**#@-*/ /** - * Path to configuration node for file duplication + * Path to configuration node that indicates how to materialize view files: with or without "duplication" */ - const XML_PATH_ALLOW_DUPLICATION = 'default/design/theme/allow_view_files_duplication'; + const XML_PATH_ALLOW_DUPLICATION = 'global/design/theme/allow_view_files_duplication'; + + /** + * Path to config node that allows automatically updating map files in runtime + */ + const XML_PATH_ALLOW_MAP_UPDATE = 'global/dev/design_fallback/allow_map_update'; + + /** + * Sub-directory where to store maps of view files fallback (if used) + */ + const FALLBACK_MAP_DIR = 'maps/fallback'; /** * PCRE that matches non-absolute URLs in CSS content @@ -255,36 +265,29 @@ class Mage_Core_Model_Design_Package * @param array $params * @return string|int */ - public function getConfigurationDesignTheme($area = null, $params = array()) + public function getConfigurationDesignTheme($area = null, array $params = array()) { if (!$area) { $area = $this->getArea(); } - $useId = isset($params['useId']) ? $params['useId'] : true; $store = isset($params['store']) ? $params['store'] : null; - $designTheme = (string)Mage::getStoreConfig($this->getConfigPathByArea($area, $useId), $store); - if (empty($designTheme)) { - $designTheme = (string)Mage::getConfig()->getNode($this->getConfigPathByArea($area, $useId)); + if ($this->_isThemePerStoveView($area)) { + return Mage::getStoreConfig(self::XML_PATH_THEME_ID, $store) + ?: (string)Mage::getConfig()->getNode($area . '/' . self::XML_PATH_THEME); } - return $designTheme; + return (string)Mage::getConfig()->getNode($area . '/' . self::XML_PATH_THEME); } - /** - * Get configuration xml path to current theme for area + * Whether themes in specified area are supposed to be configured per store view * * @param string $area - * @param bool $useId - * @return string + * @return bool */ - public function getConfigPathByArea($area, $useId = true) + private function _isThemePerStoveView($area) { - $xmlPath = $useId ? self::XML_PATH_THEME_ID : self::XML_PATH_THEME; - if ($area !== self::DEFAULT_AREA) { - $xmlPath = $area . '/' . $xmlPath; - } - return $xmlPath; + return $area == self::DEFAULT_AREA; } /** @@ -324,7 +327,7 @@ class Mage_Core_Model_Design_Package } if (!empty($params['themeId'])) { - $params['themeModel'] = $this->_getLoadDesignTheme($params['themeId']); + $params['themeModel'] = $this->_getLoadDesignTheme($params['themeId'], $params['area']); } elseif (!empty($params['package']) && isset($params['theme'])) { $themePath = $params['package'] . '/' . $params['theme']; $params['themeModel'] = $this->_getLoadDesignTheme($themePath, $params['area']); @@ -419,18 +422,30 @@ class Mage_Core_Model_Design_Package */ protected function _getFallback($params) { - if (!isset($params['skipProxy'])) { - $params['skipProxy'] = $this->_isDeveloperMode(); - } + $skipProxy = (isset($params['skipProxy']) && $params['skipProxy']) ?: $this->_isDeveloperMode(); $cacheKey = join('|', array( $params['area'], $params['themeModel']->getCacheKey(), $params['locale'], - $params['skipProxy'] + $skipProxy )); if (!isset($this->_fallback[$cacheKey])) { - $this->_fallback[$cacheKey] = $this->_createFallback($params); + $fallback = Mage::getObjectManager()->create('Mage_Core_Model_Design_Fallback', array('params' => $params)); + if ($skipProxy) { + $this->_fallback[$cacheKey] = $fallback; + } else { + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = Mage::getObjectManager()->get('Mage_Core_Model_Dir'); + $proxy = new Mage_Core_Model_Design_Fallback_CachingProxy( + $fallback, + $this->_filesystem, + $dirs->getDir(Mage_Core_Model_Dir::VAR_DIR) . DIRECTORY_SEPARATOR . self::FALLBACK_MAP_DIR, + $dirs->getDir(Mage_Core_Model_Dir::ROOT), + (bool)(string)Mage::app()->getConfig()->getNode(self::XML_PATH_ALLOW_MAP_UPDATE) + ); + $this->_fallback[$cacheKey] = $proxy; + } } return $this->_fallback[$cacheKey]; } @@ -546,19 +561,16 @@ class Mage_Core_Model_Design_Package */ protected function _getPublicFileUrl($file, $isSecure = null) { - $publicDirUrlTypes = array( - Mage_Core_Model_Store::URL_TYPE_THEME => $this->getPublicDir(), - Mage_Core_Model_Store::URL_TYPE_JS => Mage::getBaseDir('js'), - ); - foreach ($publicDirUrlTypes as $publicUrlType => $publicDir) { - $publicDir .= DS; - if (strpos($file, $publicDir) !== 0) { - continue; + foreach (array( + Mage_Core_Model_Store::URL_TYPE_LIB => Mage_Core_Model_Dir::PUB_LIB, + Mage_Core_Model_Store::URL_TYPE_MEDIA => Mage_Core_Model_Dir::MEDIA + ) as $urlType => $dirType) { + $dir = Mage::getBaseDir($dirType); + if (strpos($file, $dir) === 0) { + $relativePath = ltrim(substr($file, strlen($dir)), DIRECTORY_SEPARATOR); + $relativePath = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath); + return Mage::getBaseUrl($urlType, $isSecure) . $relativePath; } - $url = str_replace($publicDir, '', $file); - $url = str_replace(DS, '/', $url); - $url = Mage::getBaseUrl($publicUrlType, $isSecure) . $url; - return $url; } throw new Magento_Exception( "Cannot build URL for the file '$file' because it does not reside in a public directory." @@ -708,7 +720,7 @@ class Mage_Core_Model_Design_Package */ protected function _needToProcessFile($filePath) { - $jsPath = Mage::getBaseDir('js') . DS; + $jsPath = Mage::getBaseDir(Mage_Core_Model_Dir::PUB_LIB) . DS; if (strncmp($filePath, $jsPath, strlen($jsPath)) === 0) { return false; } @@ -761,7 +773,7 @@ class Mage_Core_Model_Design_Package */ public function getPublicDir() { - return Mage::getBaseDir('media') . DIRECTORY_SEPARATOR . self::PUBLIC_BASE_THEME_DIR; + return Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA) . DIRECTORY_SEPARATOR . self::PUBLIC_BASE_THEME_DIR; } /** @@ -771,7 +783,7 @@ class Mage_Core_Model_Design_Package */ public function getCustomizationDir() { - return Mage::getBaseDir('media') . DIRECTORY_SEPARATOR . Mage_Core_Model_Design_Package::PUBLIC_BASE_THEME_DIR + return Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA) . DIRECTORY_SEPARATOR . Mage_Core_Model_Design_Package::PUBLIC_BASE_THEME_DIR . DIRECTORY_SEPARATOR . Mage_Core_Model_Design_Package::PUBLIC_CUSTOMIZATION_THEME_DIR; } @@ -807,7 +819,7 @@ class Mage_Core_Model_Design_Package */ protected function _buildPublicViewSufficientFilename($filename, array $params) { - $designDir = Mage::getBaseDir('design') . DS; + $designDir = Mage::getBaseDir(Mage_Core_Model_Dir::THEMES) . DS; if (0 === strpos($filename, $designDir)) { // theme file $publicFile = substr($filename, strlen($designDir)); @@ -877,7 +889,7 @@ class Mage_Core_Model_Design_Package $relativeThemeFile = $fileUrl; } else { /* Check if module file overridden on theme level based on _module property and file path */ - if ($params['module'] && strpos($parentFilePath, Mage::getBaseDir('design')) === 0) { + if ($params['module'] && strpos($parentFilePath, Mage::getBaseDir(Mage_Core_Model_Dir::THEMES)) === 0) { /* Add module directory to relative URL for canonization */ $relativeThemeFile = dirname($params['module'] . DS . $parentFileName) . DS . $fileUrl; @@ -944,7 +956,7 @@ class Mage_Core_Model_Design_Package { $filesToMerge = array(); $mergedFile = array(); - $jsDir = Mage::getBaseDir('js'); + $jsDir = Mage::getBaseDir(Mage_Core_Model_Dir::PUB_LIB); $publicDir = $this->_buildPublicViewFilename(''); foreach ($files as $file) { $params = array(); diff --git a/app/code/core/Mage/Core/Model/Dir.php b/app/code/core/Mage/Core/Model/Dir.php new file mode 100644 index 00000000000..02d94af059f --- /dev/null +++ b/app/code/core/Mage/Core/Model/Dir.php @@ -0,0 +1,311 @@ +<?php +/** + * Application file system directories dictionary + * + * Provides information about what directories are available in the application + * Serves as customizaiton point to specify different directories or add own + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Core_Model_Dir +{ + /** + * Code base root + */ + const ROOT = 'base'; + + /** + * Most of entire application + */ + const APP = 'app'; + + /** + * Modules + */ + const MODULES = 'code'; + + /** + * Themes + */ + const THEMES = 'design'; + + /** + * Initial configuration of the application + */ + const CONFIG = 'etc'; + + /** + * Libraries or third-party components + */ + const LIB = 'lib'; + + /** + * Files with translation of system labels and messages from en_US to other languages + */ + const LOCALE = 'locale'; + + /** + * Directory within document root of a web-server to access static view files publicly + */ + const PUB = 'pub'; + + /** + * Libraries/components that need to be accessible publicly through web-server (such as various DHTML components) + */ + const PUB_LIB = 'pub_lib'; + + /** + * Storage of files entered or generated by the end-user + */ + const MEDIA = 'media'; + + /** + * Various files generated by the system in runtime + */ + const VAR_DIR = 'var'; + + /** + * Temporary files + */ + const TMP = 'tmp'; + + /** + * File system caching directory (if file system caching is used) + */ + const CACHE = 'cache'; + + /** + * Logs of system messages and errors + */ + const LOG = 'log'; + + /** + * File system session directory (if file system session storage is used) + */ + const SESSION = 'session'; + + /** + * Temporary directory for uploading files by end-user + */ + const UPLOAD = 'upload'; + + /** + * Default values for directories (and URIs) + * + * Format: array(<code> => <relative_path>) + * + * @var array + */ + private static $_defaults = array( + self::ROOT => '', + self::APP => 'app', + self::MODULES => 'app/code', + self::THEMES => 'app/design', + self::CONFIG => 'app/etc', + self::LIB => 'lib', + self::LOCALE => 'app/locale', + self::VAR_DIR => 'var', + self::TMP => 'var/tmp', + self::CACHE => 'var/cache', + self::LOG => 'var/log', + self::SESSION => 'var/session', + self::PUB => 'pub', + self::PUB_LIB => 'pub/lib', + self::MEDIA => 'pub/media', + self::UPLOAD => 'pub/media/upload', + ); + + /** + * Paths of URIs designed for building URLs + * + * Values are to be initialized in constructor. + * They are declared like this here for convenience of distinguishing which directories are intended to be URIs. + * + * @var array + */ + private $_uris = array( + self::PUB => '', + self::PUB_LIB => '', + self::MEDIA => '', + self::UPLOAD => '', + ); + + /** + * Absolute paths to directories + * + * @var array + */ + private $_dirs = array(); + + /** + * List of directories that application requires to be writable in order to operate + * + * @return array + */ + public static function getWritableDirCodes() + { + return array(self::MEDIA, self::VAR_DIR, self::TMP, self::CACHE, self::LOG, self::SESSION); + } + + /** + * Initialize URIs and paths + * + * @param string $baseDir + * @param array $uris custom URIs + * @param array $dirs custom directories (full system paths) + */ + public function __construct($baseDir, array $uris = array(), array $dirs = array()) + { + // uris + foreach (array_keys($this->_uris) as $code) { + $this->_uris[$code] = self::$_defaults[$code]; + } + foreach ($uris as $code => $uri) { + $this->_setUri($code, $uri); + } + foreach ($this->_getDefaultReplacements($uris) as $code => $replacement) { + $this->_setUri($code, $replacement); + } + + // dirs + foreach (self::$_defaults as $code => $path) { + $this->_setDir($code, $baseDir . ($path ? DIRECTORY_SEPARATOR . $path : '')); + } + foreach ($dirs as $code => $path) { + $this->_setDir($code, $path); + } + foreach ($this->_getDefaultReplacements($dirs) as $code => $replacement) { + $this->_setDir($code, $replacement); + } + } + + /** + * URI getter + * + * @param string $code + * @return string|bool + */ + public function getUri($code) + { + return isset($this->_uris[$code]) ? $this->_uris[$code] : false; + } + + /** + * Set URI + * + * The method is private on purpose: it must be used only in constructor. Users of this object must not be able + * to alter its state, otherwise it may compromise application integrity. + * Path must be usable as a fragment of a URL path. + * For interoperability and security purposes, no uppercase or "upper directory" paths like "." or ".." + * + * @param $code + * @param $uri + * @throws InvalidArgumentException + */ + private function _setUri($code, $uri) + { + if (!preg_match('/^([a-z0-9_]+[a-z0-9\._]*(\/[a-z0-9_]+[a-z0-9\._]*)*)?$/', $uri)) { + throw new InvalidArgumentException( + "Must be relative directory path in lowercase with '/' directory separator: '{$uri}'" + ); + } + $this->_uris[$code] = $uri; + } + + /** + * Directory path getter + * + * @param string $code + * @return string|bool + */ + public function getDir($code) + { + return isset($this->_dirs[$code]) ? $this->_dirs[$code] : false; + } + + /** + * Set directory + * + * @param string $code + * @param string $path + */ + private function _setDir($code, $path) + { + $this->_dirs[$code] = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $path); + } + + /** + * Using default relations, find replacements for child directories if their parent has changed + * + * For example, "var" has children "var/tmp" and "var/cache". If "var" is customized as "var.test", and its children + * are not, then they will be automatically replaced to "var.test/tmp" and "var.test/cache" + * + * @param array $source + * @return array + */ + private function _getDefaultReplacements(array $source) + { + $result = array(); + foreach ($source as $parentCode => $parent) { + foreach ($this->_getChildren($parentCode) as $childCode) { + if (!isset($source[$childCode])) { + if (empty(self::$_defaults[$parentCode])) { + $fragment = self::$_defaults[$childCode]; + } else { + $fragment = str_replace(self::$_defaults[$parentCode], '', self::$_defaults[$childCode]); + } + $fragment = ltrim($fragment, '/'); + if (!empty($parent)) { + $fragment = '/' . $fragment; + } + $result[$childCode] = $parent . $fragment; + } + } + } + return $result; + } + + /** + * Analyze defaults and determine child codes of specified element + * + * @param string $code + * @return array + */ + private function _getChildren($code) + { + $result = array(); + if (!isset(self::$_defaults[$code])) { + return $result; + } + $parent = self::$_defaults[$code]; + foreach (self::$_defaults as $childCode => $child) { + if ($code != $childCode) { + if ($parent && $child && 0 === strpos($child, $parent)) { + $result[] = $childCode; + } elseif (empty($parent)) { + $result[] = $childCode; + } + } + } + return $result; + } +} diff --git a/app/code/core/Mage/Core/Model/Encryption.php b/app/code/core/Mage/Core/Model/Encryption.php index 1e8f48b92e2..2882f5c4111 100755 --- a/app/code/core/Mage/Core/Model/Encryption.php +++ b/app/code/core/Mage/Core/Model/Encryption.php @@ -38,18 +38,41 @@ class Mage_Core_Model_Encryption */ protected $_crypt; /** - * @var Mage_Core_Helper_Data + * @var string */ protected $_helper; + /** + * @var Magento_ObjectManager|null + */ + protected $_objectManager = null; + + /** + * @param Magento_ObjectManager $objectManager + */ + public function __construct(Magento_ObjectManager $objectManager) + { + $this->_objectManager = $objectManager; + } + /** * Set helper instance * - * @param Mage_Core_Helper_Data $helper + * @param Mage_Core_Helper_Data|string $helper * @return Mage_Core_Model_Encryption + * @throws InvalidArgumentException */ public function setHelper($helper) { + if (!is_string($helper)) { + if ($helper instanceof Mage_Core_Helper_Data) { + $helper = get_class($helper); + } else { + throw new InvalidArgumentException( + 'Input parameter "$helper" must be either "string" or instance of "Mage_Core_Helper_Data"' + ); + } + } $this->_helper = $helper; return $this; } @@ -69,7 +92,7 @@ class Mage_Core_Model_Encryption public function getHash($password, $salt = false) { if (is_integer($salt)) { - $salt = $this->_helper->getRandomString($salt); + $salt = $this->_objectManager->get($this->_helper)->getRandomString($salt); } return $salt === false ? $this->hash($password) : $this->hash($salt . $password) . ':' . $salt; } diff --git a/app/code/core/Mage/Core/Model/Layout/Argument/Processor.php b/app/code/core/Mage/Core/Model/Layout/Argument/Processor.php index 3d6184ecd09..e9fdc1f5413 100644 --- a/app/code/core/Mage/Core/Model/Layout/Argument/Processor.php +++ b/app/code/core/Mage/Core/Model/Layout/Argument/Processor.php @@ -38,11 +38,6 @@ class Mage_Core_Model_Layout_Argument_Processor */ protected $_handlerFactory; - /** - * @var Mage_Core_Model_Config - */ - protected $_objectFactory; - /** * @var Mage_Core_Model_Layout_Argument_Updater */ diff --git a/app/code/core/Mage/Core/Model/Layout/Merge.php b/app/code/core/Mage/Core/Model/Layout/Merge.php index 5cd7ef0d454..e168830d79f 100644 --- a/app/code/core/Mage/Core/Model/Layout/Merge.php +++ b/app/code/core/Mage/Core/Model/Layout/Merge.php @@ -111,7 +111,7 @@ class Mage_Core_Model_Layout_Merge $this->_theme = $arguments['theme']; } elseif (isset($arguments['area'])) { $this->_area = $arguments['area']; - $this->_theme = Mage::getDesign()->getConfigurationDesignTheme($arguments['area']); + $this->_theme = null; } else { $this->_area = Mage::getDesign()->getArea(); $this->_theme = Mage::getDesign()->getDesignTheme()->getId(); diff --git a/app/code/core/Mage/Core/Model/Layout/ScheduledStructure.php b/app/code/core/Mage/Core/Model/Layout/ScheduledStructure.php index e49727f6038..324b874be1c 100644 --- a/app/code/core/Mage/Core/Model/Layout/ScheduledStructure.php +++ b/app/code/core/Mage/Core/Model/Layout/ScheduledStructure.php @@ -339,19 +339,4 @@ class Mage_Core_Model_Layout_ScheduledStructure $this->_scheduledElements = array(); $this->_scheduledStructure = array(); } - - /** - * Cleanup circular references - * - * Destructor should be called explicitly in order to work around the PHP bug - * https://bugs.php.net/bug.php?id=62468 - */ - public function __destruct() - { - $this->_scheduledStructure = array(); - $this->_scheduledElements = array(); - $this->_scheduledMoves = array(); - $this->_scheduledRemoves = array(); - $this->_scheduledPaths = array(); - } } diff --git a/app/code/core/Mage/Core/Model/Logger.php b/app/code/core/Mage/Core/Model/Logger.php index 402828073ce..b3f1509a396 100644 --- a/app/code/core/Mage/Core/Model/Logger.php +++ b/app/code/core/Mage/Core/Model/Logger.php @@ -42,18 +42,13 @@ class Mage_Core_Model_Logger protected $_loggers = array(); /** - * @var Mage_Core_Model_Config + * @var Mage_Core_Model_Dir */ - protected $_config = null; + protected $_dirs = null; - /** - * Instantiate with config model - * - * @param Mage_Core_Model_Config $config - */ - public function __construct(Mage_Core_Model_Config $config) + public function __construct(Mage_Core_Model_Dir $dirs) { - $this->_config = $config; + $this->_dirs = $dirs; } /** @@ -63,16 +58,17 @@ class Mage_Core_Model_Logger * * @param string $loggerKey * @param string $fileOrWrapper + * @param string $writerClass * @return Mage_Core_Model_Logger * @link http://php.net/wrappers */ - public function addStreamLog($loggerKey, $fileOrWrapper = '') + public function addStreamLog($loggerKey, $fileOrWrapper = '', $writerClass = '') { $file = $fileOrWrapper ?: "{$loggerKey}.log"; if (!preg_match('#^[a-z][a-z0-9+.-]*\://#i', $file)) { - $file = $this->_config->getOptions()->getLogDir() . DIRECTORY_SEPARATOR . $file; + $logDir = $this->_dirs->getDir(Mage_Core_Model_Dir::LOG); + $file = $logDir . DIRECTORY_SEPARATOR . $file; } - $writerClass = (string)$this->_config->getNode('global/log/core/writer_model'); if (!$writerClass || !is_subclass_of($writerClass, 'Zend_Log_Writer_Stream')) { $writerClass = 'Zend_Log_Writer_Stream'; } @@ -89,13 +85,15 @@ class Mage_Core_Model_Logger * Reset all loggers and initialize them according to store configuration * * @param Mage_Core_Model_Store $store + * @param Mage_Core_Model_Config $config */ - public function initForStore(Mage_Core_Model_Store $store) + public function initForStore(Mage_Core_Model_Store $store, Mage_Core_Model_Config $config) { $this->_loggers = array(); if ($store->getConfig('dev/log/active')) { - $this->addStreamLog(self::LOGGER_SYSTEM, $store->getConfig('dev/log/file')); - $this->addStreamLog(self::LOGGER_EXCEPTION, $store->getConfig('dev/log/exception_file')); + $writer = (string)$config->getNode('global/log/core/writer_model'); + $this->addStreamLog(self::LOGGER_SYSTEM, $store->getConfig('dev/log/file'), $writer); + $this->addStreamLog(self::LOGGER_EXCEPTION, $store->getConfig('dev/log/exception_file'), $writer); } } diff --git a/app/code/core/Mage/Core/Model/Magento/Api.php b/app/code/core/Mage/Core/Model/Magento/Api.php new file mode 100644 index 00000000000..fdb10b15f73 --- /dev/null +++ b/app/code/core/Mage/Core/Model/Magento/Api.php @@ -0,0 +1,49 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Core + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Magento info API + * + * @category Mage + * @package Mage_Core + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Core_Model_Magento_Api extends Mage_Api_Model_Resource_Abstract +{ + /** + * Retrieve information about current Magento installation + * + * @return array + */ + public function info() + { + $result = array(); + $result['magento_edition'] = Mage::getEdition(); + $result['magento_version'] = Mage::getVersion(); + + return $result; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Core/_files/load_configuration.php b/app/code/core/Mage/Core/Model/Magento/Api/V2.php similarity index 81% rename from dev/tests/integration/testsuite/Mage/Core/_files/load_configuration.php rename to app/code/core/Mage/Core/Model/Magento/Api/V2.php index b6f8c24ac67..84f9698af28 100644 --- a/dev/tests/integration/testsuite/Mage/Core/_files/load_configuration.php +++ b/app/code/core/Mage/Core/Model/Magento/Api/V2.php @@ -18,14 +18,19 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Mage - * @package Mage_Core + * @category Mage + * @package Mage_Directory * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -$areaConfig = Mage::getModel( - 'Mage_Core_Model_Config_Base', - array('sourceData' => dirname(__FILE__).'/etc/config.xml') -); -Mage::app()->getConfig()->extend($areaConfig); +/** + * Magento info API V2 + * + * @category Mage + * @package Mage_Core + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Core_Model_Magento_Api_V2 extends Mage_Core_Model_Magento_Api +{ +} diff --git a/app/code/core/Mage/Core/Model/Observer.php b/app/code/core/Mage/Core/Model/Observer.php index c848b029c9c..2229101f412 100644 --- a/app/code/core/Mage/Core/Model/Observer.php +++ b/app/code/core/Mage/Core/Model/Observer.php @@ -117,7 +117,7 @@ class Mage_Core_Model_Observer $baseDir = $observer->getEvent()->getBaseDir(); $pathPattern = $observer->getEvent()->getPathPattern(); try { - Mage::getModel('Mage_Core_Model_Theme_Registration')->register($baseDir, $pathPattern); + Mage::getObjectManager()->get('Mage_Core_Model_Theme_Registration')->register($baseDir, $pathPattern); } catch (Mage_Core_Exception $e) { Mage::logException($e); } diff --git a/app/code/core/Mage/Core/Model/Store.php b/app/code/core/Mage/Core/Model/Store.php index a5fade2330f..87c2a644dc0 100644 --- a/app/code/core/Mage/Core/Model/Store.php +++ b/app/code/core/Mage/Core/Model/Store.php @@ -48,21 +48,26 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract */ const ENTITY = 'core_store'; - /** - * Configuration pathes - */ - const XML_PATH_STORE_STORE_NAME = 'general/store_information/name'; - const XML_PATH_STORE_STORE_PHONE = 'general/store_information/phone'; - const XML_PATH_STORE_IN_URL = 'web/url/use_store'; - const XML_PATH_USE_REWRITES = 'web/seo/use_rewrites'; - const XML_PATH_UNSECURE_BASE_URL = 'web/unsecure/base_url'; - const XML_PATH_SECURE_BASE_URL = 'web/secure/base_url'; - const XML_PATH_SECURE_IN_FRONTEND = 'web/secure/use_in_frontend'; - const XML_PATH_SECURE_IN_ADMINHTML = 'web/secure/use_in_adminhtml'; - const XML_PATH_SECURE_BASE_LINK_URL = 'web/secure/base_link_url'; - const XML_PATH_UNSECURE_BASE_LINK_URL = 'web/unsecure/base_link_url'; - const XML_PATH_OFFLOADER_HEADER = 'web/secure/offloader_header'; - const XML_PATH_PRICE_SCOPE = 'catalog/price/scope'; + /**#@+ + * Configuration paths + */ + const XML_PATH_STORE_STORE_NAME = 'general/store_information/name'; + const XML_PATH_STORE_STORE_PHONE = 'general/store_information/phone'; + const XML_PATH_STORE_IN_URL = 'web/url/use_store'; + const XML_PATH_USE_REWRITES = 'web/seo/use_rewrites'; + const XML_PATH_UNSECURE_BASE_URL = 'web/unsecure/base_url'; + const XML_PATH_SECURE_BASE_URL = 'web/secure/base_url'; + const XML_PATH_SECURE_IN_FRONTEND = 'web/secure/use_in_frontend'; + const XML_PATH_SECURE_IN_ADMINHTML = 'web/secure/use_in_adminhtml'; + const XML_PATH_SECURE_BASE_LINK_URL = 'web/secure/base_link_url'; + const XML_PATH_UNSECURE_BASE_LINK_URL = 'web/unsecure/base_link_url'; + const XML_PATH_SECURE_BASE_LIB_URL = 'web/secure/base_lib_url'; + const XML_PATH_UNSECURE_BASE_LIB_URL = 'web/unsecure/base_lib_url'; + const XML_PATH_SECURE_BASE_MEDIA_URL = 'web/secure/base_media_url'; + const XML_PATH_UNSECURE_BASE_MEDIA_URL = 'web/unsecure/base_media_url'; + const XML_PATH_OFFLOADER_HEADER = 'web/secure/offloader_header'; + const XML_PATH_PRICE_SCOPE = 'catalog/price/scope'; + /**#@- */ /** * Price scope constants @@ -76,9 +81,8 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract const URL_TYPE_LINK = 'link'; const URL_TYPE_DIRECT_LINK = 'direct_link'; const URL_TYPE_WEB = 'web'; - const URL_TYPE_JS = 'js'; + const URL_TYPE_LIB = 'lib'; const URL_TYPE_MEDIA = 'media'; - const URL_TYPE_THEME = 'theme'; /** * Code constants @@ -106,6 +110,11 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract */ const MEDIA_REWRITE_SCRIPT = 'get.php/'; + /** + * A placeholder for generating base URL + */ + const BASE_URL_PLACEHOLDER = '{{base_url}}'; + /** * Cache flag * @@ -134,13 +143,6 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract */ protected $_priceFilter; - /** - * Website model - * - * @var Mage_Core_Model_Website - */ - protected $_website; - /** * Group model * @@ -405,29 +407,26 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract } /** - * Set website model + * Set relation to the website * * @param Mage_Core_Model_Website $website */ public function setWebsite(Mage_Core_Model_Website $website) { - $this->_website = $website; + $this->setWebsiteId($website->getId()); } /** * Retrieve store website * - * @return Mage_Core_Model_Website + * @return Mage_Core_Model_Website|bool */ public function getWebsite() { if (is_null($this->getWebsiteId())) { return false; } - if (is_null($this->_website)) { - $this->_website = Mage::app()->getWebsite($this->getWebsiteId()); - } - return $this->_website; + return Mage::app()->getWebsite($this->getWebsiteId()); } /** @@ -463,24 +462,17 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract if (is_string($sValue) && preg_match('/{{(.*)}}.*/', $sValue, $matches)) { $placeholder = $matches[1]; $url = false; - if ($placeholder == 'unsecure_base_url' || $placeholder == 'unsecure_public_url') { + if ($placeholder == 'unsecure_base_url') { $url = $this->getConfig(self::XML_PATH_UNSECURE_BASE_URL); - } elseif ($placeholder == 'secure_base_url' || $placeholder == 'secure_public_url') { + } elseif ($placeholder == 'secure_base_url') { $url = $this->getConfig(self::XML_PATH_SECURE_BASE_URL); } - if ($placeholder == 'unsecure_public_url' || $placeholder == 'secure_public_url') { - $pubName = Mage_Core_Model_Config_Options::PUB_DIRECTORY; - $url.= (substr(dirname($_SERVER['SCRIPT_FILENAME']), -4) == '/' . $pubName) ? '' : $pubName . '/'; - // @TODO: investigate how to build correct public URLs from API - if (Mage::registry('custom_entry_point')) { - $url .= $pubName . '/'; - } - } if ($url) { $sValue = str_replace('{{' . $placeholder . '}}', $url, $sValue); - } elseif (strpos($sValue, '{{base_url}}') !== false) { - $sValue = Mage::getConfig()->substDistroServerVars($sValue); + } elseif (strpos($sValue, Mage_Core_Model_Store::BASE_URL_PLACEHOLDER) !== false) { + $distroBaseUrl = Mage::getConfig()->getDistroBaseUrl(); + $sValue = str_replace(Mage_Core_Model_Store::BASE_URL_PLACEHOLDER, $distroBaseUrl, $sValue); } } @@ -489,19 +481,6 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract return $sValue; } - /** - * Retrieve default base path - * - * @return string - */ - public function getDefaultBasePath() - { - if (!isset($_SERVER['SCRIPT_NAME'])) { - return '/'; - } - return rtrim(Mage::app()->getRequest()->getBasePath() . '/') . '/'; - } - /** * Retrieve url using store configuration specific * @@ -532,47 +511,57 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract { $cacheKey = $type . '/' . (is_null($secure) ? 'null' : ($secure ? 'true' : 'false')); if (!isset($this->_baseUrlCache[$cacheKey])) { + $secure = is_null($secure) ? $this->isCurrentlySecure() : (bool)$secure; + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = Mage::getObjectManager()->get('Mage_Core_Model_Dir'); + switch ($type) { case self::URL_TYPE_WEB: - $secure = is_null($secure) ? $this->isCurrentlySecure() : (bool)$secure; - $url = $this->getConfig('web/' . ($secure ? 'secure' : 'unsecure') . '/base_url'); + $path = $secure ? self::XML_PATH_SECURE_BASE_URL : self::XML_PATH_UNSECURE_BASE_URL; + $url = $this->getConfig($path); break; case self::URL_TYPE_LINK: - $secure = (bool) $secure; - $url = $this->getConfig('web/' . ($secure ? 'secure' : 'unsecure') . '/base_link_url'); + $path = $secure ? self::XML_PATH_SECURE_BASE_LINK_URL : self::XML_PATH_UNSECURE_BASE_LINK_URL; + $url = $this->getConfig($path); $url = $this->_updatePathUseRewrites($url); $url = $this->_updatePathUseStoreView($url); break; case self::URL_TYPE_DIRECT_LINK: - $secure = (bool) $secure; - $url = $this->getConfig('web/' . ($secure ? 'secure' : 'unsecure') . '/base_link_url'); + $path = $secure ? self::XML_PATH_SECURE_BASE_LINK_URL : self::XML_PATH_UNSECURE_BASE_LINK_URL; + $url = $this->getConfig($path); $url = $this->_updatePathUseRewrites($url); break; - case self::URL_TYPE_JS: - $secure = is_null($secure) ? $this->isCurrentlySecure() : (bool) $secure; - $url = $this->getConfig('web/' . ($secure ? 'secure' : 'unsecure') . '/base_public_url') . 'lib/'; - break; - - case self::URL_TYPE_THEME: - $secure = is_null($secure) ? $this->isCurrentlySecure() : (bool) $secure; - $url = $this->getConfig('web/' . ($secure ? 'secure' : 'unsecure') . '/base_public_url') - . 'media/theme/'; + case self::URL_TYPE_LIB: + $path = $secure ? self::XML_PATH_SECURE_BASE_LIB_URL : self::XML_PATH_UNSECURE_BASE_LIB_URL; + $url = $this->getConfig($path); + if (!$url) { + $url = $this->getBaseUrl(self::URL_TYPE_WEB, $secure) + . $dirs->getUri(Mage_Core_Model_Dir::PUB_LIB); + } break; case self::URL_TYPE_MEDIA: - $url = $this->_updateMediaPathUseRewrites($secure); + $url = $this->_getMediaScriptUrl($dirs, $secure); + if (!$url) { + $path = $secure ? self::XML_PATH_SECURE_BASE_MEDIA_URL : self::XML_PATH_UNSECURE_BASE_MEDIA_URL; + $url = $this->getConfig($path); + if (!$url) { + $url = $this->getBaseUrl(self::URL_TYPE_WEB, $secure) + . $dirs->getUri(Mage_Core_Model_Dir::MEDIA); + } + } break; default: - throw Mage::exception('Mage_Core', Mage::helper('Mage_Core_Helper_Data')->__('Invalid base url type')); + throw new InvalidArgumentException('Invalid base url type'); } - if (false !== strpos($url, '{{base_url}}')) { - $baseUrl = Mage::getConfig()->substDistroServerVars('{{base_url}}'); - $url = str_replace('{{base_url}}', $baseUrl, $url); + if (false !== strpos($url, Mage_Core_Model_Store::BASE_URL_PLACEHOLDER)) { + $distroBaseUrl = Mage::getConfig()->getDistroBaseUrl(); + $url = str_replace(Mage_Core_Model_Store::BASE_URL_PLACEHOLDER, $distroBaseUrl, $url); } $this->_baseUrlCache[$cacheKey] = rtrim($url, '/') . '/'; @@ -619,22 +608,19 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract * If we use Database file storage and server doesn't support rewrites (.htaccess in media folder) * we have to put name of fetching media script exactly into URL * - * @param null|boolean $secure - * @param string $type - * @return string + * @param Mage_Core_Model_Dir $dirs + * @param bool $secure + * @return string|bool */ - protected function _updateMediaPathUseRewrites($secure = null, $type = self::URL_TYPE_MEDIA) + protected function _getMediaScriptUrl(Mage_Core_Model_Dir $dirs, $secure) { - $secure = is_null($secure) ? $this->isCurrentlySecure() : (bool) $secure; - $secureStringFlag = $secure ? 'secure' : 'unsecure'; - $url = $this->getConfig('web/' . $secureStringFlag . '/base_' . $type . '_url'); if (!$this->getConfig(self::XML_PATH_USE_REWRITES) && Mage::helper('Mage_Core_Helper_File_Storage_Database')->checkDbUsage() ) { - $urlStart = $this->getConfig('web/' . $secureStringFlag . '/base_public_url'); - $url = str_replace($urlStart, $urlStart . self::MEDIA_REWRITE_SCRIPT, $url); + return $this->getBaseUrl(self::URL_TYPE_WEB, $secure) . $dirs->getUri(Mage_Core_Model_Dir::PUB) + . '/' . self::MEDIA_REWRITE_SCRIPT; } - return $url; + return false; } /** @@ -1009,23 +995,20 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract */ public function setGroup($group) { - $this->_group = $group; + $this->setGroupId($group->getId()); } /** * Retrieve group model * - * @return Mage_Core_Model_Store_Group + * @return Mage_Core_Model_Store_Group|bool */ public function getGroup() { if (is_null($this->getGroupId())) { return false; } - if (is_null($this->_group)) { - $this->_group = Mage::getModel('Mage_Core_Model_Store_Group')->load($this->getGroupId()); - } - return $this->_group; + return Mage::app()->getGroup($this->getGroupId()); } /** diff --git a/app/code/core/Mage/Core/Model/Store/Api.php b/app/code/core/Mage/Core/Model/Store/Api.php new file mode 100644 index 00000000000..5f125dc368a --- /dev/null +++ b/app/code/core/Mage/Core/Model/Store/Api.php @@ -0,0 +1,96 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Core + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Store API + * + * @category Mage + * @package Mage_Core + * @author Magento Core Team <core@magentocommerce.com> + */ + +class Mage_Core_Model_Store_Api extends Mage_Api_Model_Resource_Abstract +{ + /** + * Retrieve stores list + * + * @return array + */ + public function items() + { + // Retrieve stores + $stores = Mage::app()->getStores(); + + // Make result array + $result = array(); + foreach ($stores as $store) { + $result[] = array( + 'store_id' => $store->getId(), + 'code' => $store->getCode(), + 'website_id' => $store->getWebsiteId(), + 'group_id' => $store->getGroupId(), + 'name' => $store->getName(), + 'sort_order' => $store->getSortOrder(), + 'is_active' => $store->getIsActive() + ); + } + + return $result; + } + + /** + * Retrieve store data + * + * @param string|int $storeId + * @return array + */ + public function info($storeId) + { + // Retrieve store info + try { + $store = Mage::app()->getStore($storeId); + } catch (Mage_Core_Model_Store_Exception $e) { + $this->_fault('store_not_exists'); + } + + if (!$store->getId()) { + $this->_fault('store_not_exists'); + } + + // Basic store data + $result = array(); + $result['store_id'] = $store->getId(); + $result['code'] = $store->getCode(); + $result['website_id'] = $store->getWebsiteId(); + $result['group_id'] = $store->getGroupId(); + $result['name'] = $store->getName(); + $result['sort_order'] = $store->getSortOrder(); + $result['is_active'] = $store->getIsActive(); + + return $result; + } + +} diff --git a/app/code/core/Mage/Adminhtml/Block/Abstract.php b/app/code/core/Mage/Core/Model/Store/Api/V2.php similarity index 85% rename from app/code/core/Mage/Adminhtml/Block/Abstract.php rename to app/code/core/Mage/Core/Model/Store/Api/V2.php index 6731c563995..66dad500410 100644 --- a/app/code/core/Mage/Adminhtml/Block/Abstract.php +++ b/app/code/core/Mage/Core/Model/Store/Api/V2.php @@ -19,18 +19,18 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category Mage - * @package Mage_Adminhtml + * @package Mage_Directory * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ /** + * Directory Country Api V2 + * * @category Mage - * @package Mage_Adminhtml + * @package Mage_Core * @author Magento Core Team <core@magentocommerce.com> - * @deprecated Moved to module Mage_Backend */ -class Mage_Adminhtml_Block_Abstract extends Mage_Backend_Block_Abstract +class Mage_Core_Model_Store_Api_V2 extends Mage_Core_Model_Store_Api { - } diff --git a/app/code/core/Mage/Core/Model/Store/Group.php b/app/code/core/Mage/Core/Model/Store/Group.php index f53b7712b06..6b5bff23f59 100644 --- a/app/code/core/Mage/Core/Model/Store/Group.php +++ b/app/code/core/Mage/Core/Model/Store/Group.php @@ -92,13 +92,6 @@ class Mage_Core_Model_Store_Group extends Mage_Core_Model_Abstract */ protected $_defaultStore; - /** - * Website model - * - * @var Mage_Core_Model_Website - */ - protected $_website; - /** * @var bool */ @@ -268,29 +261,26 @@ class Mage_Core_Model_Store_Group extends Mage_Core_Model_Abstract } /** - * Set website model + * Set relation to the website * * @param Mage_Core_Model_Website $website */ public function setWebsite(Mage_Core_Model_Website $website) { - $this->_website = $website; + $this->setWebsiteId($website->getId()); } /** * Retrieve website model * - * @return Mage_Core_Model_Website + * @return Mage_Core_Model_Website|bool */ public function getWebsite() { if (is_null($this->getWebsiteId())) { return false; } - if (is_null($this->_website)) { - $this->_website = Mage::app()->getWebsite($this->getWebsiteId()); - } - return $this->_website; + return Mage::app()->getWebsite($this->getWebsiteId()); } /** diff --git a/app/code/core/Mage/Core/Model/Theme.php b/app/code/core/Mage/Core/Model/Theme.php index 2bf939db1ee..ab0f6e6484e 100644 --- a/app/code/core/Mage/Core/Model/Theme.php +++ b/app/code/core/Mage/Core/Model/Theme.php @@ -380,7 +380,8 @@ class Mage_Core_Model_Theme extends Mage_Core_Model_Abstract */ public static function getPreviewImageDirectoryUrl() { - return Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_THEME) . self::IMAGE_DIR_PREVIEW . '/'; + return Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA) + . Mage_Core_Model_Design_Package::PUBLIC_BASE_THEME_DIR . '/' . self::IMAGE_DIR_PREVIEW . '/'; } /** diff --git a/app/code/core/Mage/Core/Model/Theme/Registration.php b/app/code/core/Mage/Core/Model/Theme/Registration.php index 4ba0e34826e..5671f150471 100644 --- a/app/code/core/Mage/Core/Model/Theme/Registration.php +++ b/app/code/core/Mage/Core/Model/Theme/Registration.php @@ -94,8 +94,6 @@ class Mage_Core_Model_Theme_Registration $this->_registerThemeRecursively($theme); } - $this->registerDefaultThemes(); - /** @var $dbCollection Mage_Core_Model_Resource_Theme_Collection */ $dbCollection = $this->getThemeModel()->getResourceCollection(); $dbCollection->checkParentInThemes(); @@ -139,53 +137,6 @@ class Mage_Core_Model_Theme_Registration return $this; } - /** - * Get default theme design paths specified in configuration - * - * @return array - */ - protected function _getDefaultThemes() - { - $themesByArea = array(); - $themeItems = $this->_collection->getItems(); - /** @var $theme Mage_Core_Model_Theme */ - foreach ($themeItems as $theme) { - $area = $theme->getArea(); - if (!isset($themesByArea[$area])) { - $themePath = $this->_getDesign()->getConfigurationDesignTheme($area, array('useId' => false)); - $fullPath = $area . '/' . $themePath; - $themesByArea[$area] = isset($themeItems[$fullPath]) ? $themeItems[$fullPath] : null; - } - } - return $themesByArea; - } - - /** - * Set default themes stored in configuration - * - * @return Mage_Core_Model_Theme_Registration - */ - public function registerDefaultThemes() - { - /** @var $theme Mage_Core_Model_Theme */ - foreach ($this->_getDefaultThemes() as $area => $theme) { - if ($theme && $theme->getId()) { - Mage::app()->getConfig()->saveConfig($this->_getDesign()->getConfigPathByArea($area), $theme->getId()); - } - } - return $this; - } - - /** - * Get current design model - * - * @return Mage_Core_Model_Design_Package - */ - protected function _getDesign() - { - return Mage::getDesign(); - } - /** * Get theme from DB by full path * diff --git a/app/code/core/Mage/Core/Model/Theme/Service.php b/app/code/core/Mage/Core/Model/Theme/Service.php index 9d77b139ace..dbbd7e2bc11 100644 --- a/app/code/core/Mage/Core/Model/Theme/Service.php +++ b/app/code/core/Mage/Core/Model/Theme/Service.php @@ -121,8 +121,7 @@ class Mage_Core_Model_Theme_Service public function assignThemeToStores( $themeId, array $stores = array(), - $scope = Mage_Core_Model_Config::SCOPE_STORES, - $area = Mage_Core_Model_App_Area::AREA_FRONTEND + $scope = Mage_Core_Model_Config::SCOPE_STORES ) { /** @var $theme Mage_Core_Model_Theme */ $theme = $this->_themeFactory->create()->load($themeId); @@ -132,7 +131,7 @@ class Mage_Core_Model_Theme_Service $themeCustomization = $theme->isVirtual() ? $theme : $this->createThemeCustomization($theme); - $configPath = $this->_design->getConfigPathByArea($area); + $configPath = Mage_Core_Model_Design_Package::XML_PATH_THEME_ID; // Unassign given theme from stores that were unchecked /** @var $config Mage_Core_Model_Config_Data */ @@ -158,7 +157,6 @@ class Mage_Core_Model_Theme_Service 'themeId' => $themeId, 'stores' => $stores, 'scope' => $scope, - 'area' => $area, 'theme' => $theme, 'themeCustomization' => $themeCustomization, ) diff --git a/app/code/core/Mage/Core/Model/Translate.php b/app/code/core/Mage/Core/Model/Translate.php index 9b149871abb..6d4f65d0c66 100644 --- a/app/code/core/Mage/Core/Model/Translate.php +++ b/app/code/core/Mage/Core/Model/Translate.php @@ -112,13 +112,20 @@ class Mage_Core_Model_Translate */ protected $_localeHierarchy = array(); + /** + * @var Mage_Core_Model_Design_Package + */ + protected $_designPackage; + /** * Initialize translate model * + * @param Mage_Core_Model_Design_Package $designPackage * @param array $data */ - public function __construct(array $data = array()) + public function __construct(Mage_Core_Model_Design_Package $designPackage, array $data = array()) { + $this->_designPackage = $designPackage; if (isset($data['locale_hierarchy']) && is_array($data['locale_hierarchy'])) { $this->_localeHierarchy = $data['locale_hierarchy']; } else { @@ -207,7 +214,7 @@ class Mage_Core_Model_Translate $this->_config[self::CONFIG_KEY_STORE] = Mage::app()->getStore()->getId(); } if (!isset($this->_config[self::CONFIG_KEY_DESIGN_THEME])) { - $this->_config[self::CONFIG_KEY_DESIGN_THEME] = Mage::getDesign()->getDesignTheme()->getId(); + $this->_config[self::CONFIG_KEY_DESIGN_THEME] = $this->_designPackage->getDesignTheme()->getId(); } return $this; } @@ -266,6 +273,7 @@ class Mage_Core_Model_Translate * * @param array $data * @param string $scope + * @param boolean $forceReload * @return Mage_Core_Model_Translate */ protected function _addData($data, $scope, $forceReload=false) @@ -313,7 +321,7 @@ class Mage_Core_Model_Translate { $requiredLocaleList = $this->_composeRequiredLocaleList($this->getLocale()); foreach ($requiredLocaleList as $locale) { - $file = Mage::getDesign()->getLocaleFileName('translate.csv', array('locale' => $locale)); + $file = $this->_designPackage->getLocaleFileName('translate.csv', array('locale' => $locale)); $this->_addData($this->_getFileData($file), false, $forceReload); } return $this; @@ -322,6 +330,7 @@ class Mage_Core_Model_Translate /** * Loading current store translation from DB * + * @param boolean $forceReload * @return Mage_Core_Model_Translate */ protected function _loadDbTranslation($forceReload = false) @@ -517,7 +526,6 @@ class Mage_Core_Model_Translate /** * Loading data cache * - * @param string $area * @return array | false */ protected function _loadCache() @@ -533,7 +541,6 @@ class Mage_Core_Model_Translate /** * Saving data cache * - * @param string $area * @return Mage_Core_Model_Translate */ protected function _saveCache() diff --git a/app/code/core/Mage/Core/etc/api.xml b/app/code/core/Mage/Core/etc/api.xml new file mode 100644 index 00000000000..648c653c8c9 --- /dev/null +++ b/app/code/core/Mage/Core/etc/api.xml @@ -0,0 +1,103 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Core + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <core_store translate="title" module="Mage_Core"> + <model>Mage_Core_Model_Store_Api</model> + <title>Store API</title> + <acl>core/store</acl> + <methods> + <list translate="title" module="Mage_Core"> + <title>Retrieve store list</title> + <method>items</method> + <acl>core/store/list</acl> + </list> + <info translate="title" module="Mage_Core"> + <title>Retrieve store data</title> + <acl>core/store/info</acl> + </info> + </methods> + <faults module="Mage_Core"> + <store_not_exists> + <code>100</code> + <message>Requested store view is not found.</message> + </store_not_exists> + </faults> + </core_store> + <core_magento translate="title" module="Mage_Core"> + <model>Mage_Core_Model_Magento_Api</model> + <title>Magento info API</title> + <acl>core/magento</acl> + <methods> + <info translate="title" module="Mage_Core"> + <title>Get info about current Magento installation</title> + <acl>core/magento/info</acl> + </info> + </methods> + </core_magento> + </resources> + <resources_alias> + <store>core_store</store> + <magento>core_magento</magento> + </resources_alias> + <v2> + <resources_function_prefix> + <store>store</store> + <magento>magento</magento> + </resources_function_prefix> + </v2> + <rest> + <mapping> + </mapping> + </rest> + <acl> + <resources> + <core translate="title" module="Mage_Core"> + <title>Core</title> + <sort_order>1</sort_order> + <store translate="title" module="Mage_Core"> + <title>Store</title> + <info translate="title" module="Mage_Core"> + <title>Retrieve store data</title> + </info> + <list translate="title" module="Mage_Core"> + <title>List of stores</title> + </list> + </store> + <magento translate="title" module="Mage_Core"> + <title>Magento info</title> + <info translate="title" module="Mage_Core"> + <title>Retrieve info about current Magento installation</title> + </info> + </magento> + </core> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/Core/etc/config.xml b/app/code/core/Mage/Core/etc/config.xml index 7cfcd73d5ce..c93420ebf08 100644 --- a/app/code/core/Mage/Core/etc/config.xml +++ b/app/code/core/Mage/Core/etc/config.xml @@ -71,6 +71,11 @@ </collections> </types> </cache> + <design> + <theme> + <allow_view_files_duplication>1</allow_view_files_duplication> + </theme> + </design> <session> <validation> <http_user_agent_skip> @@ -116,6 +121,11 @@ </di> </global> <frontend> + <design> + <theme> + <full_name>default/demo</full_name> + </theme> + </design> <events> <controller_action_layout_generate_blocks_after> <observers> @@ -217,10 +227,6 @@ </install> <default> <design> - <theme> - <full_name>default/demo</full_name> - <allow_view_files_duplication>1</allow_view_files_duplication> - </theme> <pagination> <list_allow_all>1</list_allow_all> <pagination_frame>5</pagination_frame> @@ -308,15 +314,11 @@ <base_url>{{base_url}}</base_url> <base_web_url>{{unsecure_base_url}}</base_web_url> <base_link_url>{{unsecure_base_url}}</base_link_url> - <base_public_url>{{unsecure_public_url}}</base_public_url> - <base_media_url>{{unsecure_public_url}}media/</base_media_url> </unsecure> <secure> - <base_url>{{base_url}}</base_url> + <base_url>{{unsecure_base_url}}</base_url> <base_web_url>{{secure_base_url}}</base_web_url> <base_link_url>{{secure_base_url}}</base_link_url> - <base_public_url>{{secure_public_url}}</base_public_url> - <base_media_url>{{secure_public_url}}media/</base_media_url> <use_in_frontend>0</use_in_frontend> <use_in_adminhtml>0</use_in_adminhtml> <offloader_header>SSL_OFFLOADED</offloader_header> diff --git a/app/code/core/Mage/Core/etc/wsdl.xml b/app/code/core/Mage/Core/etc/wsdl.xml new file mode 100644 index 00000000000..8f3116b73f2 --- /dev/null +++ b/app/code/core/Mage/Core/etc/wsdl.xml @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="storeEntity"> + <all> + <element name="store_id" type="xsd:int" /> + <element name="code" type="xsd:string" /> + <element name="website_id" type="xsd:int" /> + <element name="group_id" type="xsd:int" /> + <element name="name" type="xsd:string" /> + <element name="sort_order" type="xsd:int" /> + <element name="is_active" type="xsd:int" /> + </all> + </complexType> + <complexType name="storeEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:storeEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="magentoInfoEntity"> + <all> + <element name="magento_version" type="xsd:string" /> + <element name="magento_edition" type="xsd:string" /> + </all> + </complexType> + </schema> + </types> + <message name="storeListRequest"> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="storeListResponse"> + <part name="stores" type="typens:storeEntityArray" /> + </message> + <message name="magentoInfoRequest"> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="magentoInfoResponse"> + <part name="info" type="typens:magentoInfoEntity" /> + </message> + <message name="storeInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="storeId" type="xsd:string" /> + </message> + <message name="storeInfoResponse"> + <part name="info" type="typens:storeEntity" /> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="storeList"> + <documentation>List of stores</documentation> + <input message="typens:storeListRequest" /> + <output message="typens:storeListResponse" /> + </operation> + <operation name="storeInfo"> + <documentation>Store view info</documentation> + <input message="typens:storeInfoRequest" /> + <output message="typens:storeInfoResponse" /> + </operation> + <operation name="magentoInfo"> + <documentation>Info about current Magento installation</documentation> + <input message="typens:magentoInfoRequest" /> + <output message="typens:magentoInfoResponse" /> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="storeList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="storeInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="magentoInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/Core/etc/wsi.xml b/app/code/core/Mage/Core/etc/wsi.xml new file mode 100644 index 00000000000..7e2b3b71557 --- /dev/null +++ b/app/code/core/Mage/Core/etc/wsi.xml @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="storeEntity"> + <xsd:sequence> + <xsd:element name="store_id" type="xsd:int" /> + <xsd:element name="code" type="xsd:string" /> + <xsd:element name="website_id" type="xsd:int" /> + <xsd:element name="group_id" type="xsd:int" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="sort_order" type="xsd:int" /> + <xsd:element name="is_active" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="storeEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:storeEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="magentoInfoEntity"> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="magento_version" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="magento_edition" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:element name="storeListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="storeListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:storeEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="storeInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="storeId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="storeInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:storeEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="magentoInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="magentoInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:magentoInfoEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="storeListRequest"> + <wsdl:part name="parameters" element="typens:storeListRequestParam" /> + </wsdl:message> + <wsdl:message name="storeListResponse"> + <wsdl:part name="parameters" element="typens:storeListResponseParam" /> + </wsdl:message> + <wsdl:message name="storeInfoRequest"> + <wsdl:part name="parameters" element="typens:storeInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="storeInfoResponse"> + <wsdl:part name="parameters" element="typens:storeInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="magentoInfoRequest"> + <wsdl:part name="parameters" element="typens:magentoInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="magentoInfoResponse"> + <wsdl:part name="parameters" element="typens:magentoInfoResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="storeList"> + <wsdl:documentation>List of stores</wsdl:documentation> + <wsdl:input message="typens:storeListRequest" /> + <wsdl:output message="typens:storeListResponse" /> + </wsdl:operation> + <wsdl:operation name="storeInfo"> + <wsdl:documentation>Store view info</wsdl:documentation> + <wsdl:input message="typens:storeInfoRequest" /> + <wsdl:output message="typens:storeInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="magentoInfo"> + <wsdl:documentation>Info about current Magento installation</wsdl:documentation> + <wsdl:input message="typens:magentoInfoRequest" /> + <wsdl:output message="typens:magentoInfoResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="storeList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="storeInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="magentoInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="{{var wsdl.name}}Service"> + <wsdl:port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/app/code/core/Mage/Customer/Model/Address/Api.php b/app/code/core/Mage/Customer/Model/Address/Api.php new file mode 100644 index 00000000000..8ff9218547c --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Address/Api.php @@ -0,0 +1,143 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Customer address api + * + * @category Mage + * @package Mage_Customer + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Customer_Model_Address_Api extends Mage_Customer_Model_Api_Resource +{ + protected $_mapAttributes = array( + 'customer_address_id' => 'entity_id' + ); + + public function __construct() + { + $this->_ignoredAttributeCodes[] = 'parent_id'; + } + + /** + * Retrive customer addresses list + * + * @param int $customerId + * @return array + */ + public function items($customerId) + { + $customer = Mage::getModel('Mage_Customer_Model_Customer') + ->load($customerId); + /* @var $customer Mage_Customer_Model_Customer */ + + if (!$customer->getId()) { + $this->_fault('customer_not_exists'); + } + + $result = array(); + foreach ($customer->getAddresses() as $address) { + $data = $address->toArray(); + $row = array(); + + foreach ($this->_mapAttributes as $attributeAlias => $attributeCode) { + $row[$attributeAlias] = isset($data[$attributeCode]) ? $data[$attributeCode] : null; + } + + foreach ($this->getAllowedAttributes($address) as $attributeCode => $attribute) { + if (isset($data[$attributeCode])) { + $row[$attributeCode] = $data[$attributeCode]; + } + } + + $row['is_default_billing'] = $customer->getDefaultBilling() == $address->getId(); + $row['is_default_shipping'] = $customer->getDefaultShipping() == $address->getId(); + + $result[] = $row; + + } + + return $result; + } + + /** + * Retrieve address data + * + * @param int $addressId + * @return array + */ + public function info($addressId) + { + $address = Mage::getModel('Mage_Customer_Model_Address') + ->load($addressId); + + if (!$address->getId()) { + $this->_fault('not_exists'); + } + + $result = array(); + + foreach ($this->_mapAttributes as $attributeAlias => $attributeCode) { + $result[$attributeAlias] = $address->getData($attributeCode); + } + + foreach ($this->getAllowedAttributes($address) as $attributeCode => $attribute) { + $result[$attributeCode] = $address->getData($attributeCode); + } + + + if ($customer = $address->getCustomer()) { + $result['is_default_billing'] = $customer->getDefaultBilling() == $address->getId(); + $result['is_default_shipping'] = $customer->getDefaultShipping() == $address->getId(); + } + + return $result; + } + + /** + * Delete address + * + * @param int $addressId + * @return boolean + */ + public function delete($addressId) + { + $address = Mage::getModel('Mage_Customer_Model_Address') + ->load($addressId); + + if (!$address->getId()) { + $this->_fault('not_exists'); + } + + try { + $address->delete(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_deleted', $e->getMessage()); + } + + return true; + } +} // Class Mage_Customer_Model_Address_Api End diff --git a/app/code/core/Mage/Customer/Model/Address/Api/V2.php b/app/code/core/Mage/Customer/Model/Address/Api/V2.php new file mode 100644 index 00000000000..953c798b1e2 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Address/Api/V2.php @@ -0,0 +1,163 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Customer address api V2 + * + * @category Mage + * @package Mage_Customer + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Customer_Model_Address_Api_V2 extends Mage_Customer_Model_Address_Api +{ + /** + * Create new address for customer + * + * @param int $customerId + * @param array $addressData + * @return int + */ + public function create($customerId, $addressData) + { + $customer = Mage::getModel('Mage_Customer_Model_Customer') + ->load($customerId); + /* @var $customer Mage_Customer_Model_Customer */ + + if (!$customer->getId()) { + $this->_fault('customer_not_exists'); + } + + $address = Mage::getModel('Mage_Customer_Model_Address'); + + foreach ($this->getAllowedAttributes($address) as $attributeCode=>$attribute) { + if (isset($addressData->$attributeCode)) { + $address->setData($attributeCode, $addressData->$attributeCode); + } + } + + if (isset($addressData->is_default_billing)) { + $address->setIsDefaultBilling($addressData->is_default_billing); + } + + if (isset($addressData->is_default_shipping)) { + $address->setIsDefaultShipping($addressData->is_default_shipping); + } + + $address->setCustomerId($customer->getId()); + + $valid = $address->validate(); + + if (is_array($valid)) { + $this->_fault('data_invalid', implode("\n", $valid)); + } + + try { + $address->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $address->getId(); + } + + /** + * Retrieve address data + * + * @param int $addressId + * @return array + */ + public function info($addressId) + { + $address = Mage::getModel('Mage_Customer_Model_Address') + ->load($addressId); + + if (!$address->getId()) { + $this->_fault('not_exists'); + } + + $result = array(); + + foreach ($this->_mapAttributes as $attributeAlias => $attributeCode) { + $result[$attributeAlias] = $address->getData($attributeCode); + } + + foreach ($this->getAllowedAttributes($address) as $attributeCode => $attribute) { + $result[$attributeCode] = $address->getData($attributeCode); + } + + + if ($customer = $address->getCustomer()) { + $result['is_default_billing'] = $customer->getDefaultBilling() == $address->getId(); + $result['is_default_shipping'] = $customer->getDefaultShipping() == $address->getId(); + } + + return $result; + } + + /** + * Update address data + * + * @param int $addressId + * @param array $addressData + * @return boolean + */ + public function update($addressId, $addressData) + { + $address = Mage::getModel('Mage_Customer_Model_Address') + ->load($addressId); + + if (!$address->getId()) { + $this->_fault('not_exists'); + } + + foreach ($this->getAllowedAttributes($address) as $attributeCode=>$attribute) { + if (isset($addressData->$attributeCode)) { + $address->setData($attributeCode, $addressData->$attributeCode); + } + } + + if (isset($addressData->is_default_billing)) { + $address->setIsDefaultBilling($addressData->is_default_billing); + } + + if (isset($addressData->is_default_shipping)) { + $address->setIsDefaultShipping($addressData->is_default_shipping); + } + + $valid = $address->validate(); + if (is_array($valid)) { + $this->_fault('data_invalid', implode("\n", $valid)); + } + + try { + $address->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } +} // Class Mage_Customer_Model_Address_Api End diff --git a/app/code/core/Mage/Customer/Model/Api/Resource.php b/app/code/core/Mage/Customer/Model/Api/Resource.php new file mode 100644 index 00000000000..109181556b3 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Api/Resource.php @@ -0,0 +1,90 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Customer abstract API resource + * + * @category Mage + * @package Mage_Customer + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Customer_Model_Api_Resource extends Mage_Api_Model_Resource_Abstract +{ + /** + * Default ignored attribute codes + * + * @var array + */ + protected $_ignoredAttributeCodes = array('entity_id', 'attribute_set_id', 'entity_type_id'); + + /** + * Default ignored attribute types + * + * @var array + */ + protected $_ignoredAttributeTypes = array(); + + /** + * Check is attribute allowed + * + * @param Mage_Eav_Model_Entity_Attribute_Abstract $attribute + * @param array $attributes + * @return boolean + */ + protected function _isAllowedAttribute($attribute, array $filter = null) + { + if (!is_null($filter) + && !( in_array($attribute->getAttributeCode(), $filter) + || in_array($attribute->getAttributeId(), $filter))) { + return false; + } + + return !in_array($attribute->getFrontendInput(), $this->_ignoredAttributeTypes) + && !in_array($attribute->getAttributeCode(), $this->_ignoredAttributeCodes); + } + + /** + * Return list of allowed attributes + * + * @param Mage_Eav_Model_Entity_Abstract $entity + * @param array $filter + * @return array + */ + public function getAllowedAttributes($entity, array $filter = null) + { + $attributes = $entity->getResource() + ->loadAllAttributes($entity) + ->getAttributesByCode(); + $result = array(); + foreach ($attributes as $attribute) { + if ($this->_isAllowedAttribute($attribute, $filter)) { + $result[$attribute->getAttributeCode()] = $attribute; + } + } + + return $result; + } +} // Class Mage_Customer_Model_Api_Resource End diff --git a/app/code/core/Mage/Customer/Model/Customer/Api.php b/app/code/core/Mage/Customer/Model/Customer/Api.php new file mode 100644 index 00000000000..75469a0f3d3 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Customer/Api.php @@ -0,0 +1,196 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Customer api + * + * @category Mage + * @package Mage_Customer + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Customer_Model_Customer_Api extends Mage_Customer_Model_Api_Resource +{ + protected $_mapAttributes = array( + 'customer_id' => 'entity_id' + ); + /** + * Prepare data to insert/update. + * Creating array for stdClass Object + * + * @param stdClass $data + * @return array + */ + protected function _prepareData($data) + { + foreach ($this->_mapAttributes as $attributeAlias=>$attributeCode) { + if(isset($data[$attributeAlias])) + { + $data[$attributeCode] = $data[$attributeAlias]; + unset($data[$attributeAlias]); + } + } + return $data; + } + + /** + * Create new customer + * + * @param array $customerData + * @return int + */ + public function create($customerData) + { + $customerData = $this->_prepareData($customerData); + try { + $customer = Mage::getModel('Mage_Customer_Model_Customer') + ->setData($customerData) + ->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + return $customer->getId(); + } + + /** + * Retrieve customer data + * + * @param int $customerId + * @param array $attributes + * @return array + */ + public function info($customerId, $attributes = null) + { + $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId); + + if (!$customer->getId()) { + $this->_fault('not_exists'); + } + + if (!is_null($attributes) && !is_array($attributes)) { + $attributes = array($attributes); + } + + $result = array(); + + foreach ($this->_mapAttributes as $attributeAlias=>$attributeCode) { + $result[$attributeAlias] = $customer->getData($attributeCode); + } + + foreach ($this->getAllowedAttributes($customer, $attributes) as $attributeCode=>$attribute) { + $result[$attributeCode] = $customer->getData($attributeCode); + } + + return $result; + } + + /** + * Retrieve customers data + * + * @param object|array $filters + * @return array + */ + public function items($filters) + { + $collection = Mage::getModel('Mage_Customer_Model_Customer')->getCollection()->addAttributeToSelect('*'); + /** @var $apiHelper Mage_Api_Helper_Data */ + $apiHelper = Mage::helper('Mage_Api_Helper_Data'); + $filters = $apiHelper->parseFilters($filters, $this->_mapAttributes); + try { + foreach ($filters as $field => $value) { + $collection->addFieldToFilter($field, $value); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('filters_invalid', $e->getMessage()); + } + $result = array(); + foreach ($collection as $customer) { + $data = $customer->toArray(); + $row = array(); + foreach ($this->_mapAttributes as $attributeAlias => $attributeCode) { + $row[$attributeAlias] = (isset($data[$attributeCode]) ? $data[$attributeCode] : null); + } + foreach ($this->getAllowedAttributes($customer) as $attributeCode => $attribute) { + if (isset($data[$attributeCode])) { + $row[$attributeCode] = $data[$attributeCode]; + } + } + $result[] = $row; + } + + return $result; + } + + /** + * Update customer data + * + * @param int $customerId + * @param array $customerData + * @return boolean + */ + public function update($customerId, $customerData) + { + $customerData = $this->_prepareData($customerData); + + $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId); + + if (!$customer->getId()) { + $this->_fault('not_exists'); + } + + foreach ($this->getAllowedAttributes($customer) as $attributeCode=>$attribute) { + if (isset($customerData[$attributeCode])) { + $customer->setData($attributeCode, $customerData[$attributeCode]); + } + } + + $customer->save(); + return true; + } + + /** + * Delete customer + * + * @param int $customerId + * @return boolean + */ + public function delete($customerId) + { + $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId); + + if (!$customer->getId()) { + $this->_fault('not_exists'); + } + + try { + $customer->delete(); + } catch (Mage_Core_Exception $e) { + $this->_fault('not_deleted', $e->getMessage()); + } + + return true; + } + +} // Class Mage_Customer_Model_Customer_Api End diff --git a/app/code/core/Mage/Customer/Model/Customer/Api/V2.php b/app/code/core/Mage/Customer/Model/Customer/Api/V2.php new file mode 100644 index 00000000000..bf85c7f144e --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Customer/Api/V2.php @@ -0,0 +1,50 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Customer api V2 + * + * @category Mage + * @package Mage_Customer + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Customer_Model_Customer_Api_V2 extends Mage_Customer_Model_Customer_Api +{ + /** + * Prepare data to insert/update. + * Creating array for stdClass Object + * + * @param stdClass $data + * @return array + */ + protected function _prepareData($data) + { + if (null !== ($_data = get_object_vars($data))) { + return parent::_prepareData($_data); + } + return array(); + } +} diff --git a/app/code/core/Mage/Customer/Model/Group/Api.php b/app/code/core/Mage/Customer/Model/Group/Api.php new file mode 100644 index 00000000000..a4ee0448257 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Group/Api.php @@ -0,0 +1,53 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Customer groups api + * + * @category Mage + * @package Mage_Customer + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Customer_Model_Group_Api extends Mage_Api_Model_Resource_Abstract +{ + /** + * Retrieve groups + * + * @return array + */ + public function items() + { + $collection = Mage::getModel('Mage_Customer_Model_Group')->getCollection(); + + $result = array(); + foreach ($collection as $group) { + /* @var $group Mage_Customer_Model_Group */ + $result[] = $group->toArray(array('customer_group_id', 'customer_group_code')); + } + + return $result; + } +} diff --git a/app/code/core/Mage/Customer/Model/Group/Api/V2.php b/app/code/core/Mage/Customer/Model/Group/Api/V2.php new file mode 100644 index 00000000000..13a3e260aef --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Group/Api/V2.php @@ -0,0 +1,36 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Customer groups api V2 + * + * @category Mage + * @package Mage_Customer + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Customer_Model_Group_Api_V2 extends Mage_Customer_Model_Group_Api +{ +} diff --git a/app/code/core/Mage/Customer/etc/api.xml b/app/code/core/Mage/Customer/etc/api.xml new file mode 100644 index 00000000000..5a0522bfdc6 --- /dev/null +++ b/app/code/core/Mage/Customer/etc/api.xml @@ -0,0 +1,179 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Customer + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <customer translate="title" module="Mage_Customer"> + <model>Mage_Customer_Model_Customer_Api</model> + <title>Customer API</title> + <acl>customer</acl> + <methods> + <list translate="title" module="Mage_Customer"> + <title>Retrieve customers</title> + <method>items</method> + <acl>customer/info</acl> + </list> + <create translate="title" module="Mage_Customer"> + <title>Create customer</title> + <acl>customer/create</acl> + </create> + <info translate="title" module="Mage_Customer"> + <title>Retrieve customer data</title> + <acl>customer/info</acl> + </info> + <update translate="title" module="Mage_Customer"> + <title>Update customer data</title> + <acl>customer/update</acl> + </update> + <delete translate="title" module="Mage_Customer"> + <title>Delete customer</title> + <acl>customer/delete</acl> + </delete> + </methods> + <faults module="Mage_Customer"> + <data_invalid> + <code>100</code> + <message>Provided customer data is invalid. Details are in error message.</message> + </data_invalid> + <filters_invalid> + <code>101</code> + <message>Specified filters are invalid. Details are in error message.</message> + </filters_invalid> + <not_exists> + <code>102</code> + <message>Customer does not exist.</message> + </not_exists> + <not_deleted> + <code>103</code> + <message>Customer is not deleted. Details are in error message.</message> + </not_deleted> + </faults> + </customer> + <customer_group> + <model>Mage_Customer_Model_Group_Api</model> + <title>Customer's Groups API</title> + <acl>customer</acl> + <methods> + <list translate="title" module="Mage_Customer"> + <title>Retrieve customer groups</title> + <method>items</method> + </list> + </methods> + </customer_group> + <customer_address> + <model>Mage_Customer_Model_Address_Api</model> + <title>Customer Address API</title> + <acl>customer/address</acl> + <methods> + <list translate="title" module="Mage_Customer"> + <title>Retrieve customer addresses</title> + <method>items</method> + <acl>customer/address/info</acl> + </list> + <create translate="title" module="Mage_Customer"> + <title>Create customer address</title> + <acl>customer/address/create</acl> + </create> + <info translate="title" module="Mage_Customer"> + <title>Retrieve address data</title> + <acl>customer/address/info</acl> + </info> + <update translate="title" module="Mage_Customer"> + <title>Update customer address data</title> + <acl>customer/address/update</acl> + </update> + <delete translate="title" module="Mage_Customer"> + <title>Delete customer address</title> + <acl>customer/address/delete</acl> + </delete> + </methods> + <faults module="Mage_Customer"> + <data_invalid> + <code>100</code> + <message>Provided address data is invalid. Details are in error message.</message> + </data_invalid> + <customer_not_exists> + <code>101</code> + <message>Customer does not exist.</message> + </customer_not_exists> + <not_exists> + <code>102</code> + <message>Address does not exist.</message> + </not_exists> + <not_deleted> + <code>103</code> + <message>Address is not deleted. Details are in error message.</message> + </not_deleted> + </faults> + </customer_address> + </resources> + <v2> + <resources_function_prefix> + <customer>customerCustomer</customer> + <customer_group>customerGroup</customer_group> + <customer_address>customerAddress</customer_address> + </resources_function_prefix> + </v2> + <acl> + <resources> + <customer translate="title" module="Mage_Customer"> + <title>Customers</title> + <sort_order>3</sort_order> + <create translate="title" module="Mage_Customer"> + <title>Create</title> + </create> + <update translate="title" module="Mage_Customer"> + <title>Update</title> + </update> + <delete translate="title" module="Mage_Customer"> + <title>Delete</title> + </delete> + <info translate="title" module="Mage_Customer"> + <title>Retrieve customer info</title> + </info> + <address translate="title" module="Mage_Customer"> + <title>Addresses</title> + <sort_order>100</sort_order> + <create translate="title" module="Mage_Customer"> + <title>Create</title> + </create> + <update translate="title" module="Mage_Customer"> + <title>Update</title> + </update> + <delete translate="title" module="Mage_Customer"> + <title>Delete</title> + </delete> + <info translate="title" module="Mage_Customer"> + <title>Retrieve address info</title> + </info> + </address> + </customer> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/Customer/etc/wsdl.xml b/app/code/core/Mage/Customer/etc/wsdl.xml new file mode 100644 index 00000000000..133b8876396 --- /dev/null +++ b/app/code/core/Mage/Customer/etc/wsdl.xml @@ -0,0 +1,354 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="customerCustomerEntityToCreate"> + <all> + <element name="customer_id" type="xsd:int" minOccurs="0" /> + <element name="email" type="xsd:string" minOccurs="0" /> + <element name="firstname" type="xsd:string" minOccurs="0" /> + <element name="lastname" type="xsd:string" minOccurs="0" /> + <element name="password" type="xsd:string" minOccurs="0" /> + <element name="website_id" type="xsd:int" minOccurs="0" /> + <element name="store_id" type="xsd:int" minOccurs="0" /> + <element name="group_id" type="xsd:int" minOccurs="0" /> + </all> + </complexType> + <complexType name="customerCustomerEntity"> + <all> + <element name="customer_id" type="xsd:int" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="store_id" type="xsd:int" minOccurs="0" /> + <element name="website_id" type="xsd:int" minOccurs="0" /> + <element name="created_in" type="xsd:string" minOccurs="0" /> + <element name="email" type="xsd:string" minOccurs="0" /> + <element name="firstname" type="xsd:string" minOccurs="0" /> + <element name="middlename" type="xsd:string" minOccurs="0" /> + <element name="lastname" type="xsd:string" minOccurs="0" /> + <element name="group_id" type="xsd:int" minOccurs="0" /> + <element name="prefix" type="xsd:string" minOccurs="0" /> + <element name="suffix" type="xsd:string" minOccurs="0" /> + <element name="dob" type="xsd:string" minOccurs="0" /> + <element name="taxvat" type="xsd:string" minOccurs="0" /> + <element name="confirmation" type="xsd:boolean" minOccurs="0" /> + <element name="password_hash" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="customerCustomerEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:customerCustomerEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="customerGroupEntity"> + <all> + <element name="customer_group_id" type="xsd:int" /> + <element name="customer_group_code" type="xsd:string" /> + </all> + </complexType> + <complexType name="customerGroupEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:customerGroupEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="customerAddressEntityCreate"> + <all> + <element name="city" type="xsd:string" minOccurs="0" /> + <element name="company" type="xsd:string" minOccurs="0" /> + <element name="country_id" type="xsd:string" minOccurs="0" /> + <element name="fax" type="xsd:string" minOccurs="0" /> + <element name="firstname" type="xsd:string" minOccurs="0" /> + <element name="lastname" type="xsd:string" minOccurs="0" /> + <element name="middlename" type="xsd:string" minOccurs="0" /> + <element name="postcode" type="xsd:string" minOccurs="0" /> + <element name="prefix" type="xsd:string" minOccurs="0" /> + <element name="region_id" type="xsd:int" minOccurs="0" /> + <element name="region" type="xsd:string" minOccurs="0" /> + <element name="street" type="typens:ArrayOfString" minOccurs="0" /> + <element name="suffix" type="xsd:string" minOccurs="0" /> + <element name="telephone" type="xsd:string" minOccurs="0" /> + <element name="is_default_billing" type="xsd:boolean" minOccurs="0" /> + <element name="is_default_shipping" type="xsd:boolean" minOccurs="0" /> + </all> + </complexType> + <complexType name="customerAddressEntityItem"> + <all> + <element name="customer_address_id" type="xsd:int" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="city" type="xsd:string" minOccurs="0" /> + <element name="company" type="xsd:string" minOccurs="0" /> + <element name="country_id" type="xsd:string" minOccurs="0" /> + <element name="fax" type="xsd:string" minOccurs="0" /> + <element name="firstname" type="xsd:string" minOccurs="0" /> + <element name="lastname" type="xsd:string" minOccurs="0" /> + <element name="middlename" type="xsd:string" minOccurs="0" /> + <element name="postcode" type="xsd:string" minOccurs="0" /> + <element name="prefix" type="xsd:string" minOccurs="0" /> + <element name="region" type="xsd:string" minOccurs="0" /> + <element name="region_id" type="xsd:int" minOccurs="0" /> + <element name="street" type="xsd:string" minOccurs="0" /> + <element name="suffix" type="xsd:string" minOccurs="0" /> + <element name="telephone" type="xsd:string" minOccurs="0" /> + <element name="is_default_billing" type="xsd:boolean" minOccurs="0" /> + <element name="is_default_shipping" type="xsd:boolean" minOccurs="0" /> + </all> + </complexType> + <complexType name="customerAddressEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:customerAddressEntityItem[]" /> + </restriction> + </complexContent> + </complexType> + </schema> + </types> + <message name="customerCustomerListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="filters" type="typens:filters" /> + </message> + <message name="customerCustomerListResponse"> + <part name="storeView" type="typens:customerCustomerEntityArray" /> + </message> + <message name="customerCustomerCreateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="customerData" type="typens:customerCustomerEntityToCreate" /> + </message> + <message name="customerCustomerCreateResponse"> + <part name="result" type="xsd:int" /> + </message> + <message name="customerCustomerInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="customerId" type="xsd:int" /> + <part name="attributes" type="typens:ArrayOfString" /> + </message> + <message name="customerCustomerInfoResponse"> + <part name="customerInfo" type="typens:customerCustomerEntity" /> + </message> + <message name="customerCustomerUpdateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="customerId" type="xsd:int" /> + <part name="customerData" type="typens:customerCustomerEntityToCreate" /> + </message> + <message name="customerCustomerUpdateResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="customerCustomerDeleteRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="customerId" type="xsd:int" /> + </message> + <message name="customerCustomerDeleteResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="customerGroupListRequest"> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="customerGroupListResponse"> + <part name="result" type="typens:customerGroupEntityArray" /> + </message> + <message name="customerAddressListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="customerId" type="xsd:int" /> + </message> + <message name="customerAddressListResponse"> + <part name="result" type="typens:customerAddressEntityArray" /> + </message> + <message name="customerAddressCreateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="customerId" type="xsd:int" /> + <part name="addressData" type="typens:customerAddressEntityCreate" /> + </message> + <message name="customerAddressCreateResponse"> + <part name="result" type="xsd:int" /> + </message> + <message name="customerAddressInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="addressId" type="xsd:int" /> + </message> + <message name="customerAddressInfoResponse"> + <part name="info" type="typens:customerAddressEntityItem" /> + </message> + <message name="customerAddressUpdateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="addressId" type="xsd:int" /> + <part name="addressData" type="typens:customerAddressEntityCreate" /> + </message> + <message name="customerAddressUpdateResponse"> + <part name="info" type="xsd:boolean" /> + </message> + <message name="customerAddressDeleteRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="addressId" type="xsd:int" /> + </message> + <message name="customerAddressDeleteResponse"> + <part name="info" type="xsd:boolean" /> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="customerCustomerList"> + <documentation>Retrieve customers</documentation> + <input message="typens:customerCustomerListRequest" /> + <output message="typens:customerCustomerListResponse" /> + </operation> + <operation name="customerCustomerCreate"> + <documentation>Create customer</documentation> + <input message="typens:customerCustomerCreateRequest" /> + <output message="typens:customerCustomerCreateResponse" /> + </operation> + <operation name="customerCustomerInfo"> + <documentation>Retrieve customer data</documentation> + <input message="typens:customerCustomerInfoRequest" /> + <output message="typens:customerCustomerInfoResponse" /> + </operation> + <operation name="customerCustomerUpdate"> + <documentation>Update customer data</documentation> + <input message="typens:customerCustomerUpdateRequest" /> + <output message="typens:customerCustomerUpdateResponse" /> + </operation> + <operation name="customerCustomerDelete"> + <documentation>Delete customer</documentation> + <input message="typens:customerCustomerDeleteRequest" /> + <output message="typens:customerCustomerDeleteResponse" /> + </operation> + <operation name="customerGroupList"> + <documentation>Retrieve customer groups</documentation> + <input message="typens:customerGroupListRequest" /> + <output message="typens:customerGroupListResponse" /> + </operation> + <operation name="customerAddressList"> + <documentation>Retrieve customer addresses</documentation> + <input message="typens:customerAddressListRequest" /> + <output message="typens:customerAddressListResponse" /> + </operation> + <operation name="customerAddressCreate"> + <documentation>Create customer address</documentation> + <input message="typens:customerAddressCreateRequest" /> + <output message="typens:customerAddressCreateResponse" /> + </operation> + <operation name="customerAddressInfo"> + <documentation>Retrieve customer address data</documentation> + <input message="typens:customerAddressInfoRequest" /> + <output message="typens:customerAddressInfoResponse" /> + </operation> + <operation name="customerAddressUpdate"> + <documentation>Update customer address data</documentation> + <input message="typens:customerAddressUpdateRequest" /> + <output message="typens:customerAddressUpdateResponse" /> + </operation> + <operation name="customerAddressDelete"> + <documentation>Delete customer address</documentation> + <input message="typens:customerAddressDeleteRequest" /> + <output message="typens:customerAddressDeleteResponse" /> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="customerCustomerList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerCustomerCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerCustomerInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerCustomerUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerCustomerDelete"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerGroupList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerAddressList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerAddressCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerAddressInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerAddressUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="customerAddressDelete"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> +</definitions> diff --git a/app/code/core/Mage/Customer/etc/wsi.xml b/app/code/core/Mage/Customer/etc/wsi.xml new file mode 100644 index 00000000000..abef413cafc --- /dev/null +++ b/app/code/core/Mage/Customer/etc/wsi.xml @@ -0,0 +1,507 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="customerCustomerEntityToCreate"> + <xsd:sequence> + <xsd:element name="customer_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="email" type="xsd:string" minOccurs="0" /> + <xsd:element name="firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="password" type="xsd:string" minOccurs="0" /> + <xsd:element name="website_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="store_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="group_id" type="xsd:int" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="customerCustomerEntity"> + <xsd:sequence> + <xsd:element name="customer_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="website_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="created_in" type="xsd:string" minOccurs="0" /> + <xsd:element name="email" type="xsd:string" minOccurs="0" /> + <xsd:element name="firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="middlename" type="xsd:string" minOccurs="0" /> + <xsd:element name="lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="group_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="prefix" type="xsd:string" minOccurs="0" /> + <xsd:element name="suffix" type="xsd:string" minOccurs="0" /> + <xsd:element name="dob" type="xsd:string" minOccurs="0" /> + <xsd:element name="taxvat" type="xsd:string" minOccurs="0" /> + <xsd:element name="confirmation" type="xsd:boolean" minOccurs="0" /> + <xsd:element name="password_hash" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="customerCustomerEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:customerCustomerEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="customerGroupEntity"> + <xsd:sequence> + <xsd:element name="customer_group_id" type="xsd:int" /> + <xsd:element name="customer_group_code" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="customerGroupEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:customerGroupEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="customerAddressEntityCreate"> + <xsd:sequence> + <xsd:element name="city" type="xsd:string" minOccurs="0" /> + <xsd:element name="company" type="xsd:string" minOccurs="0" /> + <xsd:element name="country_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="fax" type="xsd:string" minOccurs="0" /> + <xsd:element name="firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="middlename" type="xsd:string" minOccurs="0" /> + <xsd:element name="postcode" type="xsd:string" minOccurs="0" /> + <xsd:element name="prefix" type="xsd:string" minOccurs="0" /> + <xsd:element name="region_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="region" type="xsd:string" minOccurs="0" /> + <xsd:element name="street" type="typens:ArrayOfString" minOccurs="0" /> + <xsd:element name="suffix" type="xsd:string" minOccurs="0" /> + <xsd:element name="telephone" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_default_billing" type="xsd:boolean" minOccurs="0" /> + <xsd:element name="is_default_shipping" type="xsd:boolean" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="customerAddressEntityItem"> + <xsd:sequence> + <xsd:element name="customer_address_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="city" type="xsd:string" minOccurs="0" /> + <xsd:element name="company" type="xsd:string" minOccurs="0" /> + <xsd:element name="country_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="fax" type="xsd:string" minOccurs="0" /> + <xsd:element name="firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="middlename" type="xsd:string" minOccurs="0" /> + <xsd:element name="postcode" type="xsd:string" minOccurs="0" /> + <xsd:element name="prefix" type="xsd:string" minOccurs="0" /> + <xsd:element name="region" type="xsd:string" minOccurs="0" /> + <xsd:element name="region_id" type="xsd:int" minOccurs="0" /> + <xsd:element name="street" type="xsd:string" minOccurs="0" /> + <xsd:element name="suffix" type="xsd:string" minOccurs="0" /> + <xsd:element name="telephone" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_default_billing" type="xsd:boolean" minOccurs="0" /> + <xsd:element name="is_default_shipping" type="xsd:boolean" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="customerAddressEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:customerAddressEntityItem" /> + </xsd:sequence> + </xsd:complexType> + + + <xsd:element name="customerCustomerListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="filters" type="typens:filters" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:customerCustomerEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerData" type="typens:customerCustomerEntityToCreate" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerId" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="attributes" type="typens:ArrayOfString" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:customerCustomerEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerData" type="typens:customerCustomerEntityToCreate" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerDeleteRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerId" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerCustomerDeleteResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerGroupListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerGroupListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:customerGroupEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerId" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:customerAddressEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="customerId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="addressData" type="typens:customerAddressEntityCreate" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="addressId" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:customerAddressEntityItem" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="addressId" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="addressData" type="typens:customerAddressEntityCreate" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressDeleteRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="addressId" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="customerAddressDeleteResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:boolean" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="customerCustomerListRequest"> + <wsdl:part name="parameters" element="typens:customerCustomerListRequestParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerListResponse"> + <wsdl:part name="parameters" element="typens:customerCustomerListResponseParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerCreateRequest"> + <wsdl:part name="parameters" element="typens:customerCustomerCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerCreateResponse"> + <wsdl:part name="parameters" element="typens:customerCustomerCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerInfoRequest"> + <wsdl:part name="parameters" element="typens:customerCustomerInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerInfoResponse"> + <wsdl:part name="parameters" element="typens:customerCustomerInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerUpdateRequest"> + <wsdl:part name="parameters" element="typens:customerCustomerUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerUpdateResponse"> + <wsdl:part name="parameters" element="typens:customerCustomerUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerDeleteRequest"> + <wsdl:part name="parameters" element="typens:customerCustomerDeleteRequestParam" /> + </wsdl:message> + <wsdl:message name="customerCustomerDeleteResponse"> + <wsdl:part name="parameters" element="typens:customerCustomerDeleteResponseParam" /> + </wsdl:message> + <wsdl:message name="customerGroupListRequest"> + <wsdl:part name="parameters" element="typens:customerGroupListRequestParam" /> + </wsdl:message> + <wsdl:message name="customerGroupListResponse"> + <wsdl:part name="parameters" element="typens:customerGroupListResponseParam" /> + </wsdl:message> + <wsdl:message name="customerAddressListRequest"> + <wsdl:part name="parameters" element="typens:customerAddressListRequestParam" /> + </wsdl:message> + <wsdl:message name="customerAddressListResponse"> + <wsdl:part name="parameters" element="typens:customerAddressListResponseParam" /> + </wsdl:message> + <wsdl:message name="customerAddressCreateRequest"> + <wsdl:part name="parameters" element="typens:customerAddressCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="customerAddressCreateResponse"> + <wsdl:part name="parameters" element="typens:customerAddressCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="customerAddressInfoRequest"> + <wsdl:part name="parameters" element="typens:customerAddressInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="customerAddressInfoResponse"> + <wsdl:part name="parameters" element="typens:customerAddressInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="customerAddressUpdateRequest"> + <wsdl:part name="parameters" element="typens:customerAddressUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="customerAddressUpdateResponse"> + <wsdl:part name="parameters" element="typens:customerAddressUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="customerAddressDeleteRequest"> + <wsdl:part name="parameters" element="typens:customerAddressDeleteRequestParam" /> + </wsdl:message> + <wsdl:message name="customerAddressDeleteResponse"> + <wsdl:part name="parameters" element="typens:customerAddressDeleteResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="customerCustomerList"> + <wsdl:documentation>Retrieve customers</wsdl:documentation> + <wsdl:input message="typens:customerCustomerListRequest" /> + <wsdl:output message="typens:customerCustomerListResponse" /> + </wsdl:operation> + <wsdl:operation name="customerCustomerCreate"> + <wsdl:documentation>Create customer</wsdl:documentation> + <wsdl:input message="typens:customerCustomerCreateRequest" /> + <wsdl:output message="typens:customerCustomerCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="customerCustomerInfo"> + <wsdl:documentation>Retrieve customer data</wsdl:documentation> + <wsdl:input message="typens:customerCustomerInfoRequest" /> + <wsdl:output message="typens:customerCustomerInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="customerCustomerUpdate"> + <wsdl:documentation>Update customer data</wsdl:documentation> + <wsdl:input message="typens:customerCustomerUpdateRequest" /> + <wsdl:output message="typens:customerCustomerUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="customerCustomerDelete"> + <wsdl:documentation>Delete customer</wsdl:documentation> + <wsdl:input message="typens:customerCustomerDeleteRequest" /> + <wsdl:output message="typens:customerCustomerDeleteResponse" /> + </wsdl:operation> + <wsdl:operation name="customerGroupList"> + <wsdl:documentation>Retrieve customer groups</wsdl:documentation> + <wsdl:input message="typens:customerGroupListRequest" /> + <wsdl:output message="typens:customerGroupListResponse" /> + </wsdl:operation> + <wsdl:operation name="customerAddressList"> + <wsdl:documentation>Retrieve customer addresses</wsdl:documentation> + <wsdl:input message="typens:customerAddressListRequest" /> + <wsdl:output message="typens:customerAddressListResponse" /> + </wsdl:operation> + <wsdl:operation name="customerAddressCreate"> + <wsdl:documentation>Create customer address</wsdl:documentation> + <wsdl:input message="typens:customerAddressCreateRequest" /> + <wsdl:output message="typens:customerAddressCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="customerAddressInfo"> + <wsdl:documentation>Retrieve customer address data</wsdl:documentation> + <wsdl:input message="typens:customerAddressInfoRequest" /> + <wsdl:output message="typens:customerAddressInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="customerAddressUpdate"> + <wsdl:documentation>Update customer address data</wsdl:documentation> + <wsdl:input message="typens:customerAddressUpdateRequest" /> + <wsdl:output message="typens:customerAddressUpdateResponse" /> + </wsdl:operation> + <wsdl:operation name="customerAddressDelete"> + <wsdl:documentation>Delete customer address</wsdl:documentation> + <wsdl:input message="typens:customerAddressDeleteRequest" /> + <wsdl:output message="typens:customerAddressDeleteResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="customerCustomerList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerCustomerCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerCustomerInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerCustomerUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerCustomerDelete"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerGroupList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerAddressList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerAddressCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerAddressInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerAddressUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="customerAddressDelete"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> +</wsdl:definitions> diff --git a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Editor/Toolbar/HandlesHierarchy.php b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Editor/Toolbar/HandlesHierarchy.php index 6bc9731cdb0..13a588e6677 100644 --- a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Editor/Toolbar/HandlesHierarchy.php +++ b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Editor/Toolbar/HandlesHierarchy.php @@ -61,6 +61,8 @@ class Mage_DesignEditor_Block_Adminhtml_Editor_Toolbar_HandlesHierarchy * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_DesignEditor_Model_Url_Handle $vdeUrlBuilder * @param array $data @@ -79,6 +81,8 @@ class Mage_DesignEditor_Block_Adminhtml_Editor_Toolbar_HandlesHierarchy Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_DesignEditor_Model_Url_Handle $vdeUrlBuilder, array $data = array() @@ -86,7 +90,8 @@ class Mage_DesignEditor_Block_Adminhtml_Editor_Toolbar_HandlesHierarchy $this->_vdeUrlBuilder = $vdeUrlBuilder; parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); } /** diff --git a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Abstract.php b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Abstract.php index 3d50b570c6f..a5ff2933c1b 100644 --- a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Abstract.php +++ b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Abstract.php @@ -28,12 +28,12 @@ * Abstract theme list * * @method Mage_Core_Model_Resource_Theme_Collection getCollection() - * @method Mage_Backend_Block_Abstract setCollection(Mage_Core_Model_Resource_Theme_Collection $collection) + * @method Mage_Core_Block_Template setCollection(Mage_Core_Model_Resource_Theme_Collection $collection) * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ abstract class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_List_Abstract - extends Mage_Backend_Block_Abstract + extends Mage_Core_Block_Template { /** * Application model @@ -54,6 +54,8 @@ abstract class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_List_Abstract * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $app * @param array $data @@ -72,13 +74,15 @@ abstract class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_List_Abstract Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_App $app, array $data = array() ) { $this->_app = $app; parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); } diff --git a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Available.php b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Available.php index aba1c01d1d6..26bead77691 100644 --- a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Available.php +++ b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/List/Available.php @@ -52,6 +52,8 @@ class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_List_Available * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $app * @param Mage_Core_Model_Theme_Service $serviceModel @@ -71,6 +73,8 @@ class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_List_Available Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_App $app, Mage_Core_Model_Theme_Service $serviceModel, @@ -79,7 +83,7 @@ class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_List_Available $this->_serviceModel = $serviceModel; parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $app, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $app, $data ); } diff --git a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/StoreView.php b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/StoreView.php index a7de4a69673..0aa20e7f09e 100644 --- a/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/StoreView.php +++ b/app/code/core/Mage/DesignEditor/Block/Adminhtml/Theme/Selector/StoreView.php @@ -55,6 +55,8 @@ class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_StoreView extends Mage_Ba * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_Resource_Website_Collection $websiteCollection * @param Mage_Core_Model_Theme_Service $serviceModel @@ -74,6 +76,8 @@ class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_StoreView extends Mage_Ba Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_Resource_Website_Collection $websiteCollection, Mage_Core_Model_Theme_Service $serviceModel, @@ -83,7 +87,8 @@ class Mage_DesignEditor_Block_Adminhtml_Theme_Selector_StoreView extends Mage_Ba $this->_serviceModel = $serviceModel; parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); } /** diff --git a/app/code/core/Mage/DesignEditor/Controller/Varien/Router/Standard.php b/app/code/core/Mage/DesignEditor/Controller/Varien/Router/Standard.php index af2bacc37bb..f402c76a074 100644 --- a/app/code/core/Mage/DesignEditor/Controller/Varien/Router/Standard.php +++ b/app/code/core/Mage/DesignEditor/Controller/Varien/Router/Standard.php @@ -27,14 +27,9 @@ class Mage_DesignEditor_Controller_Varien_Router_Standard extends Mage_Core_Controller_Varien_Router_Base { /** - * @var Mage_Backend_Model_Auth_Session + * @var Magento_ObjectManager */ - protected $_backendSession; - - /** - * @var Mage_DesignEditor_Helper_Data - */ - protected $_helper; + protected $_objectManager; /** * Routers that must not been matched @@ -43,48 +38,25 @@ class Mage_DesignEditor_Controller_Varien_Router_Standard extends Mage_Core_Cont */ protected $_excludedRouters = array('admin', 'vde'); - /** - * Layout factory - * - * @var Mage_DesignEditor_Model_State - */ - protected $_editorState; - - /** - * Configuration model - * - * @var Mage_Core_Model_Config - */ - protected $_configuration; - /** * @param Mage_Core_Controller_Varien_Action_Factory $controllerFactory + * @param Magento_ObjectManager $objectManager * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_App $app * @param string $areaCode * @param string $baseController - * @param Mage_Backend_Model_Auth_Session $backendSession - * @param Mage_DesignEditor_Helper_Data $helper - * @param Mage_DesignEditor_Model_State $editorState - * @param Mage_Core_Model_Config $configuration + * @throws InvalidArgumentException */ public function __construct( Mage_Core_Controller_Varien_Action_Factory $controllerFactory, + Magento_ObjectManager $objectManager, Magento_Filesystem $filesystem, Mage_Core_Model_App $app, $areaCode, - $baseController, - Mage_Backend_Model_Auth_Session $backendSession, - Mage_DesignEditor_Helper_Data $helper, - Mage_DesignEditor_Model_State $editorState, - Mage_Core_Model_Config $configuration + $baseController ) { parent::__construct($controllerFactory, $filesystem, $app, $areaCode, $baseController); - - $this->_backendSession = $backendSession; - $this->_helper = $helper; - $this->_editorState = $editorState; - $this->_configuration = $configuration; + $this->_objectManager = $objectManager; } /** @@ -101,7 +73,7 @@ class Mage_DesignEditor_Controller_Varien_Router_Standard extends Mage_Core_Cont } // user must be logged in admin area - if (!$this->_backendSession->isLoggedIn()) { + if (!$this->_objectManager->get('Mage_Backend_Model_Auth_Session')->isLoggedIn()) { return null; } @@ -122,7 +94,8 @@ class Mage_DesignEditor_Controller_Varien_Router_Standard extends Mage_Core_Cont /** @var $controller Mage_Core_Controller_Varien_ActionAbstract */ $controller = $router->match($request); if ($controller) { - $this->_editorState->update($this->_areaCode, $request, $controller); + $this->_objectManager->get('Mage_DesignEditor_Model_State') + ->update($this->_areaCode, $request, $controller); break; } } @@ -139,7 +112,7 @@ class Mage_DesignEditor_Controller_Varien_Router_Standard extends Mage_Core_Cont protected function _isVdeRequest(Mage_Core_Controller_Request_Http $request) { $url = trim($request->getOriginalPathInfo(), '/'); - $vdeFrontName = $this->_helper->getFrontName(); + $vdeFrontName = $this->_objectManager->get('Mage_DesignEditor_Helper_Data')->getFrontName(); return $url == $vdeFrontName || strpos($url, $vdeFrontName . '/') === 0; } @@ -151,7 +124,7 @@ class Mage_DesignEditor_Controller_Varien_Router_Standard extends Mage_Core_Cont */ protected function _prepareVdeRequest(Mage_Core_Controller_Request_Http $request) { - $vdeFrontName = $this->_helper->getFrontName(); + $vdeFrontName = $this->_objectManager->get('Mage_DesignEditor_Helper_Data')->getFrontName(); $noVdePath = substr($request->getPathInfo(), strlen($vdeFrontName) + 1) ?: '/'; $request->setPathInfo($noVdePath); return $this; @@ -178,9 +151,10 @@ class Mage_DesignEditor_Controller_Varien_Router_Standard extends Mage_Core_Cont */ protected function _overrideConfiguration() { - $vdeNode = $this->_configuration->getNode(Mage_DesignEditor_Model_Area::AREA_VDE); + $vdeNode = $this->_objectManager->get('Mage_Core_Model_Config') + ->getNode(Mage_DesignEditor_Model_Area::AREA_VDE); if ($vdeNode) { - $this->_configuration->getNode(Mage_Core_Model_App_Area::AREA_FRONTEND) + $this->_objectManager->get('Mage_Core_Model_Config')->getNode(Mage_Core_Model_App_Area::AREA_FRONTEND) ->extend($vdeNode, true); } } diff --git a/app/code/core/Mage/DesignEditor/Model/State.php b/app/code/core/Mage/DesignEditor/Model/State.php index 1a5807cfc3d..e8e43fbaf45 100644 --- a/app/code/core/Mage/DesignEditor/Model/State.php +++ b/app/code/core/Mage/DesignEditor/Model/State.php @@ -235,8 +235,7 @@ class Mage_DesignEditor_Model_State { $themeId = $this->_backendSession->getData('theme_id'); if ($themeId !== null) { - $path = $this->_designPackage->getConfigPathByArea(Mage_Core_Model_App_Area::AREA_FRONTEND); - $this->_application->getStore()->setConfig($path, $themeId); + $this->_application->getStore()->setConfig(Mage_Core_Model_Design_Package::XML_PATH_THEME_ID, $themeId); } } diff --git a/app/code/core/Mage/Directory/Model/Country/Api.php b/app/code/core/Mage/Directory/Model/Country/Api.php new file mode 100644 index 00000000000..6c8181f7f39 --- /dev/null +++ b/app/code/core/Mage/Directory/Model/Country/Api.php @@ -0,0 +1,54 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Directory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Directory Country Api + * + * @category Mage + * @package Mage_Directory + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Directory_Model_Country_Api extends Mage_Api_Model_Resource_Abstract +{ + /** + * Retrieve countries list + * + * @return array + */ + public function items() + { + $collection = Mage::getModel('Mage_Directory_Model_Country')->getCollection(); + + $result = array(); + foreach ($collection as $country) { + /* @var $country Mage_Directory_Model_Country */ + $country->getName(); // Loading name in default locale + $result[] = $country->toArray(array('country_id', 'iso2_code', 'iso3_code', 'name')); + } + + return $result; + } +} // Class Mage_Directory_Model_Country_Api End diff --git a/app/code/core/Mage/Directory/Model/Country/Api/V2.php b/app/code/core/Mage/Directory/Model/Country/Api/V2.php new file mode 100644 index 00000000000..fa4330adadf --- /dev/null +++ b/app/code/core/Mage/Directory/Model/Country/Api/V2.php @@ -0,0 +1,36 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Directory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Directory Country Api V2 + * + * @category Mage + * @package Mage_Directory + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Directory_Model_Country_Api_V2 extends Mage_Directory_Model_Country_Api +{ +} diff --git a/app/code/core/Mage/Directory/Model/Region/Api.php b/app/code/core/Mage/Directory/Model/Region/Api.php new file mode 100644 index 00000000000..9a27b552081 --- /dev/null +++ b/app/code/core/Mage/Directory/Model/Region/Api.php @@ -0,0 +1,62 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Directory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Directory Region Api + * + * @category Mage + * @package Mage_Directory + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Directory_Model_Region_Api extends Mage_Api_Model_Resource_Abstract +{ + /** + * Retrieve regions list + * + * @param string $country + * @return array + */ + public function items($country) + { + try { + $country = Mage::getModel('Mage_Directory_Model_Country')->loadByCode($country); + } catch (Mage_Core_Exception $e) { + $this->_fault('country_not_exists', $e->getMessage()); + } + + if (!$country->getId()) { + $this->_fault('country_not_exists'); + } + + $result = array(); + foreach ($country->getRegions() as $region) { + $region->getName(); + $result[] = $region->toArray(array('region_id', 'code', 'name')); + } + + return $result; + } +} // Class Mage_Directory_Model_Region_Api End diff --git a/app/code/core/Mage/Directory/Model/Region/Api/V2.php b/app/code/core/Mage/Directory/Model/Region/Api/V2.php new file mode 100644 index 00000000000..21cb7e3750b --- /dev/null +++ b/app/code/core/Mage/Directory/Model/Region/Api/V2.php @@ -0,0 +1,36 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Directory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Directory Region Api V2 + * + * @category Mage + * @package Mage_Directory + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Directory_Model_Region_Api_V2 extends Mage_Directory_Model_Region_Api +{ +} diff --git a/app/code/core/Mage/Directory/etc/api.xml b/app/code/core/Mage/Directory/etc/api.xml new file mode 100644 index 00000000000..a51475857cb --- /dev/null +++ b/app/code/core/Mage/Directory/etc/api.xml @@ -0,0 +1,85 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Directory + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <directory_country translate="title" module="Mage_Directory"> + <model>Mage_Directory_Model_Country_Api</model> + <title>Country API</title> + <acl>directory/country</acl> + <methods> + <list translate="title" module="Mage_Directory"> + <title>List of countries</title> + <method>items</method> + </list> + </methods> + </directory_country> + <directory_region translate="title" module="Mage_Directory"> + <model>Mage_Directory_Model_Region_Api</model> + <title>Region API</title> + <acl>directory/region</acl> + <methods> + <list translate="title" module="Mage_Directory"> + <title>List of regions in specified country</title> + <method>items</method> + </list> + </methods> + <faults module="Mage_Directory"> + <country_not_exists> + <code>101</code> + <message>Country does not exist.</message> + </country_not_exists> + </faults> + </directory_region> + </resources> + <resources_alias> + <country>directory_country</country> + <region>directory_region</region> + </resources_alias> + <v2> + <resources_function_prefix> + <country>directoryCountry</country> + <region>directoryRegion</region> + </resources_function_prefix> + </v2> + <acl> + <resources> + <directory translate="title" module="Mage_Directory"> + <title>Directory</title> + <sort_order>5</sort_order> + <country translate="title" module="Mage_Directory"> + <title>Country</title> + </country> + <region translate="title" module="Mage_Directory"> + <title>Region</title> + </region> + </directory> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/Directory/etc/wsdl.xml b/app/code/core/Mage/Directory/etc/wsdl.xml new file mode 100644 index 00000000000..5ace2242939 --- /dev/null +++ b/app/code/core/Mage/Directory/etc/wsdl.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="directoryCountryEntity"> + <all> + <element name="country_id" type="xsd:string" /> + <element name="iso2_code" type="xsd:string" /> + <element name="iso3_code" type="xsd:string" /> + <element name="name" type="xsd:string" /> + </all> + </complexType> + <complexType name="directoryCountryEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:directoryCountryEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="directoryRegionEntity"> + <all> + <element name="region_id" type="xsd:string" /> + <element name="code" type="xsd:string" /> + <element name="name" type="xsd:string" /> + </all> + </complexType> + <complexType name="directoryRegionEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:directoryRegionEntity[]" /> + </restriction> + </complexContent> + </complexType> + </schema> + </types> + <message name="directoryCountryListRequest"> + <part name="sessionId" type="xsd:string" /> + </message> + <message name="directoryCountryListResponse"> + <part name="countries" type="typens:directoryCountryEntityArray" /> + </message> + <message name="directoryRegionListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="country" type="xsd:string" /> + </message> + <message name="directoryRegionListResponse"> + <part name="countries" type="typens:directoryRegionEntityArray" /> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="directoryCountryList"> + <documentation>List of countries</documentation> + <input message="typens:directoryCountryListRequest" /> + <output message="typens:directoryCountryListResponse" /> + </operation> + <operation name="directoryRegionList"> + <documentation>List of regions in specified country</documentation> + <input message="typens:directoryRegionListRequest" /> + <output message="typens:directoryRegionListResponse" /> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="directoryCountryList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="directoryRegionList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/Directory/etc/wsi.xml b/app/code/core/Mage/Directory/etc/wsi.xml new file mode 100644 index 00000000000..eca62b5d0cb --- /dev/null +++ b/app/code/core/Mage/Directory/etc/wsi.xml @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="directoryCountryEntity"> + <xsd:sequence> + <xsd:element name="country_id" type="xsd:string" /> + <xsd:element name="iso2_code" type="xsd:string" /> + <xsd:element name="iso3_code" type="xsd:string" /> + <xsd:element name="name" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="directoryCountryEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:directoryCountryEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="directoryRegionEntity"> + <xsd:sequence> + <xsd:element name="region_id" type="xsd:string" /> + <xsd:element name="code" type="xsd:string" /> + <xsd:element name="name" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="directoryRegionEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:directoryRegionEntity" /> + </xsd:sequence> + </xsd:complexType> + + + <xsd:element name="directoryCountryListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="directoryCountryListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:directoryCountryEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="directoryRegionListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="country" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="directoryRegionListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:directoryRegionEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="directoryCountryListRequest"> + <wsdl:part name="parameters" element="typens:directoryCountryListRequestParam" /> + </wsdl:message> + <wsdl:message name="directoryCountryListResponse"> + <wsdl:part name="parameters" element="typens:directoryCountryListResponseParam" /> + </wsdl:message> + <wsdl:message name="directoryRegionListRequest"> + <wsdl:part name="parameters" element="typens:directoryRegionListRequestParam" /> + </wsdl:message> + <wsdl:message name="directoryRegionListResponse"> + <wsdl:part name="parameters" element="typens:directoryRegionListResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="directoryCountryList"> + <wsdl:documentation>List of countries</wsdl:documentation> + <wsdl:input message="typens:directoryCountryListRequest" /> + <wsdl:output message="typens:directoryCountryListResponse" /> + </wsdl:operation> + <wsdl:operation name="directoryRegionList"> + <wsdl:documentation>List of regions in specified country</wsdl:documentation> + <wsdl:input message="typens:directoryRegionListRequest" /> + <wsdl:output message="typens:directoryRegionListResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="directoryCountryList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="directoryRegionList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="{{var wsdl.name}}Service"> + <wsdl:port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php b/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php index 2b69a9385e4..d9ebf8ef190 100644 --- a/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php +++ b/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Links.php @@ -96,7 +96,7 @@ class Mage_Downloadable_Block_Adminhtml_Catalog_Product_Edit_Tab_Downloadable_Li */ public function getPurchasedSeparatelySelect() { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setName('product[links_purchased_separately]') ->setId('downloadable_link_purchase_type') ->setOptions(Mage::getSingleton('Mage_Backend_Model_Config_Source_Yesno')->toOptionArray()) diff --git a/app/code/core/Mage/Downloadable/Model/Link/Api.php b/app/code/core/Mage/Downloadable/Model/Link/Api.php new file mode 100644 index 00000000000..69d713b961e --- /dev/null +++ b/app/code/core/Mage/Downloadable/Model/Link/Api.php @@ -0,0 +1,277 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Downloadable + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Downloadable links API model + * + * @category Mage + * @package Mage_Downloadable + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Downloadable_Model_Link_Api extends Mage_Catalog_Model_Api_Resource +{ + /** + * Return validator instance + * + * @return Mage_Downloadable_Model_Link_Api_Validator + */ + protected function _getValidator() + { + return Mage::getSingleton('Mage_Downloadable_Model_Link_Api_Validator'); + } + + /** + * Decode file from base64 and upload it to donwloadable 'tmp' folder + * + * @param array $fileInfo + * @param string $type + * @return string + */ + protected function _uploadFile($fileInfo, $type) + { + $tmpPath = ''; + if ($type == 'sample') { + $tmpPath = Mage_Downloadable_Model_Sample::getBaseTmpPath(); + } elseif ($type == 'link') { + $tmpPath = Mage_Downloadable_Model_Link::getBaseTmpPath(); + } elseif ($type == 'link_samples') { + $tmpPath = Mage_Downloadable_Model_Link::getBaseSampleTmpPath(); + } + + $result = array(); + try { + $uploader = Mage::getModel('Mage_Downloadable_Model_Link_Api_Uploader', array('file' => $fileInfo)); + $uploader->setAllowRenameFiles(true); + $uploader->setFilesDispersion(true); + $result = $uploader->save($tmpPath); + + if (isset($result['file'])) { + $fullPath = rtrim($tmpPath, DS) . DS . ltrim($result['file'], DS); + Mage::helper('Mage_Core_Helper_File_Storage_Database')->saveFile($fullPath); + } + } catch (Exception $e) { + if ($e->getMessage() != '') { + $this->_fault('upload_failed', $e->getMessage()); + } else { + $this->_fault($e->getCode()); + } + } + + $result['status'] = 'new'; + $result['name'] = substr($result['file'], strrpos($result['file'], '/')+1); + return Mage::helper('Mage_Core_Helper_Data')->jsonEncode(array($result)); + } + + /** + * Add downloadable content to product + * + * @param int|string $productId + * @param array $resource + * @param string $resourceType + * @param string|int|null $store + * @param string|null $identifierType ('sku'|'id') + * @return boolean + */ + public function add($productId, $resource, $resourceType, $store = null, $identifierType = null) + { + try { + $this->_getValidator()->validateType($resourceType); + $this->_getValidator()->validateAttributes($resource, $resourceType); + } catch (Exception $e) { + $this->_fault('validation_error', $e->getMessage()); + } + + $resource['is_delete'] = 0; + if ($resourceType == 'link') { + $resource['link_id'] = 0; + } elseif ($resourceType == 'sample') { + $resource['sample_id'] = 0; + } + + if ($resource['type'] == 'file') { + if (isset($resource['file'])) { + $resource['file'] = $this->_uploadFile($resource['file'], $resourceType); + } + unset($resource[$resourceType.'_url']); + } elseif ($resource['type'] == 'url') { + unset($resource['file']); + } + + if ($resourceType == 'link' && $resource['sample']['type'] == 'file') { + if (isset($resource['sample']['file'])) { + $resource['sample']['file'] = $this->_uploadFile($resource['sample']['file'], 'link_samples'); + } + unset($resource['sample']['url']); + } elseif ($resourceType == 'link' && $resource['sample']['type'] == 'url') { + $resource['sample']['file'] = null; + } + + $product = $this->_getProduct($productId, $store, $identifierType); + try { + $downloadable = array($resourceType => array($resource)); + $product->setDownloadableData($downloadable); + $product->save(); + } catch (Exception $e) { + $this->_fault('save_error', $e->getMessage()); + } + + return true; + } + + /** + * Retrieve downloadable product links + * + * @param int|string $productId + * @param string|int $store + * @param string $identifierType ('sku'|'id') + * @return array + */ + public function items($productId, $store = null, $identifierType = null) + { + $product = $this->_getProduct($productId, $store, $identifierType); + + $linkArr = array(); + $links = $product->getTypeInstance()->getLinks($product); + $fileHelper = Mage::helper('Mage_Downloadable_Helper_File'); + foreach ($links as $item) { + $tmpLinkItem = array( + 'link_id' => $item->getId(), + 'title' => $item->getTitle(), + 'price' => $item->getPrice(), + 'number_of_downloads' => $item->getNumberOfDownloads(), + 'is_shareable' => $item->getIsShareable(), + 'link_url' => $item->getLinkUrl(), + 'link_type' => $item->getLinkType(), + 'sample_file' => $item->getSampleFile(), + 'sample_url' => $item->getSampleUrl(), + 'sample_type' => $item->getSampleType(), + 'sort_order' => $item->getSortOrder() + ); + $file = $fileHelper->getFilePath( + Mage_Downloadable_Model_Link::getBasePath(), $item->getLinkFile() + ); + + if ($item->getLinkFile() && !is_file($file)) { + Mage::helper('Mage_Core_Helper_File_Storage_Database')->saveFileToFilesystem($file); + } + + if ($item->getLinkFile() && is_file($file)) { + $name = $fileHelper->getFileFromPathFile($item->getLinkFile()); + $tmpLinkItem['file_save'] = array( + array( + 'file' => $item->getLinkFile(), + 'name' => $name, + 'size' => filesize($file), + 'status' => 'old' + )); + } + $sampleFile = $fileHelper->getFilePath( + Mage_Downloadable_Model_Link::getBaseSamplePath(), $item->getSampleFile() + ); + if ($item->getSampleFile() && is_file($sampleFile)) { + $tmpLinkItem['sample_file_save'] = array( + array( + 'file' => $item->getSampleFile(), + 'name' => $fileHelper->getFileFromPathFile($item->getSampleFile()), + 'size' => filesize($sampleFile), + 'status' => 'old' + )); + } + if ($item->getNumberOfDownloads() == '0') { + $tmpLinkItem['is_unlimited'] = 1; + } + if ($product->getStoreId() && $item->getStoreTitle()) { + $tmpLinkItem['store_title'] = $item->getStoreTitle(); + } + if ($product->getStoreId() && Mage::helper('Mage_Downloadable_Helper_Data')->getIsPriceWebsiteScope()) { + $tmpLinkItem['website_price'] = $item->getWebsitePrice(); + } + $linkArr[] = $tmpLinkItem; + } + unset($item); + unset($tmpLinkItem); + unset($links); + + $samples = $product->getTypeInstance()->getSamples($product)->getData(); + return array('links' => $linkArr, 'samples' => $samples); + } + + /** + * Remove downloadable product link + * @param string $linkId + * @param string $resourceType + * @return bool + */ + public function remove($linkId, $resourceType) + { + try { + $this->_getValidator()->validateType($resourceType); + } catch (Exception $e) { + $this->_fault('validation_error', $e->getMessage()); + } + + switch($resourceType) { + case 'link': + $downloadableModel = Mage::getSingleton('Mage_Downloadable_Model_Link'); + break; + case 'sample': + $downloadableModel = Mage::getSingleton('Mage_Downloadable_Model_Sample'); + break; + } + + $downloadableModel->load($linkId); + if (is_null($downloadableModel->getId())) { + $this->_fault('link_was_not_found'); + } + + try { + $downloadableModel->delete(); + } catch (Exception $e) { + $this->_fault('remove_error', $e->getMessage()); + } + + return true; + } + + /** + * Return loaded downloadable product instance + * + * @param int|string $productId (SKU or ID) + * @param int|string $store + * @param string $identifierType + * @return Mage_Catalog_Model_Product + */ + protected function _getProduct($productId, $store = null, $identifierType = null) + { + $product = parent::_getProduct($productId, $store, $identifierType); + + if ($product->getTypeId() !== Mage_Downloadable_Model_Product_Type::TYPE_DOWNLOADABLE) { + $this->_fault('product_not_downloadable'); + } + + return $product; + } +} diff --git a/app/code/core/Mage/Downloadable/Model/Link/Api/Uploader.php b/app/code/core/Mage/Downloadable/Model/Link/Api/Uploader.php new file mode 100644 index 00000000000..037577bfb4e --- /dev/null +++ b/app/code/core/Mage/Downloadable/Model/Link/Api/Uploader.php @@ -0,0 +1,129 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Downloadable + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * File uploader for API + * + * @category Mage + * @package Mage_Downloadable + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Downloadable_Model_Link_Api_Uploader extends Mage_Core_Model_File_Uploader +{ + /** + * Filename prefix + * + * @var string + */ + protected $_filePrefix = 'Api'; + + /** + * Default file type + */ + const DEFAULT_FILE_TYPE = 'application/octet-stream'; + + /** + * Check if the uploaded file exists + * + * @throws Exception + * @param array $file + */ + public function __construct($file) + { + $this->_setUploadFile($file); + if( !file_exists($this->_file['tmp_name']) ) { + throw new Exception('', 'file_not_uploaded'); + } else { + $this->_fileExists = true; + } + } + + /** + * Sets uploaded file info and decodes the file + * + * @throws Exception + * @param array $fileInfo + * @return void + */ + private function _setUploadFile($fileInfo) + { + if (!is_array($fileInfo)) { + throw new Exception('', 'file_data_not_correct'); + } + + $this->_file = $this->_decodeFile($fileInfo); + $this->_uploadType = self::SINGLE_STYLE; + } + + /** + * Decode uploaded file base64 encoded content + * + * @param array $fileInfo + * @return array + */ + private function _decodeFile($fileInfo) + { + $tmpFileName = $this->_getTmpFilePath(); + + $file = new Varien_Io_File(); + $file->open(array('path' => sys_get_temp_dir())); + $file->streamOpen($tmpFileName); + $file->streamWrite(base64_decode($fileInfo['base64_content'])); + $file->streamClose(); + + return array( + 'name' => $fileInfo['name'], + 'type' => isset($fileInfo['type'])? $fileInfo['type'] : self::DEFAULT_FILE_TYPE, + 'tmp_name' => $tmpFileName, + 'error' => 0, + 'size' => filesize($tmpFileName) + ); + } + + /** + * Generate temporary file name + * + * @return string + */ + private function _getTmpFilePath() + { + return tempnam(sys_get_temp_dir(), $this->_filePrefix); + + } + + /** + * Moves a file + * + * @param string $sourceFile + * @param string $destinationFile + * @return bool + */ + protected function _moveFile($sourceFile, $destinationFile) + { + return rename($sourceFile, $destinationFile); + } + +} diff --git a/app/code/core/Mage/Downloadable/Model/Link/Api/V2.php b/app/code/core/Mage/Downloadable/Model/Link/Api/V2.php new file mode 100644 index 00000000000..d4ae42cc520 --- /dev/null +++ b/app/code/core/Mage/Downloadable/Model/Link/Api/V2.php @@ -0,0 +1,67 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Downloadable + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Downloadable links API model + * + * @category Mage + * @package Mage_Downloadable + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Downloadable_Model_Link_Api_V2 extends Mage_Downloadable_Model_Link_Api +{ + /** + * Clean the object, leave only property values + * + * @param object $var + * @return void + */ + protected function _prepareData(&$var) + { + if (is_object($var)) { + $var = get_object_vars($var); + foreach ($var as $key => &$value) { + $this->_prepareData($value); + } + } + } + + /** + * Add downloadable content to product + * + * @param int|string $productId + * @param object $resource + * @param string $resourceType + * @param string|int $store + * @param string $identifierType ('sku'|'id') + * @return type + */ + public function add($productId, $resource, $resourceType, $store = null, $identifierType = null) + { + $this->_prepareData($resource); + return parent::add($productId, $resource, $resourceType, $store, $identifierType); + } +} diff --git a/app/code/core/Mage/Downloadable/Model/Link/Api/Validator.php b/app/code/core/Mage/Downloadable/Model/Link/Api/Validator.php new file mode 100644 index 00000000000..5ee342e6d17 --- /dev/null +++ b/app/code/core/Mage/Downloadable/Model/Link/Api/Validator.php @@ -0,0 +1,286 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Downloadable + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Downloadable links validator + * + * @category Mage + * @package Mage_Downloadable + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Downloadable_Model_Link_Api_Validator //extends Mage_Api_Model_Resource_Abstract +{ + /** + * Acceptable resourceTypes array + * @var array + */ + protected $_types = array('link', 'sample'); + + /** + * Acceptable upload types array + * @var array + */ + protected $_uploadTypes = array('file', 'url'); + + /** + * List of all attributes and names endings of validation functions + * + * @var array + */ + protected $_defaultAttributes = array( + 'link' => array( + 'title' => 'Title', // $1 + 'price' => 'Price', // $2 + 'number_of_downloads' => 'NumOfDownloads', // if no set is_unlimited to 1 $3 + 'is_unlimited' => 'Unlimited', // 1|0 $4 + 'is_shareable' => 'Shareable', // 1|0|2 (2) $5 + 'type' => 'UploadType', // file|url (file) $6 + 'file' => 'File', // array(name, base64_content) $7 + 'link_url' => 'Url', // URL $8 + 'sort_order' => 'Order', // int (0) $9 + 'sample' => array( + 'type' => 'UploadType', // file|url (file) $6 + 'file' => 'File', // array(name, base64_content) $7 + 'url' => 'Url' // URL $8 + ) + ), + 'sample' => array( + 'title' => 'Title', // $1 + 'type' => 'UploadType', // file|url (file) $6 + 'file' => 'File', // array(name, base64_content) $7 + 'sample_url' => 'Url', // URL $8 + 'sort_order' => 'Order' // int (0) $9 + ) + ); + + /** + * Get resource types + * + * @return array + */ + public function getResourceTypes() + { + return $this->_types; + } + + /** + * Validate resourceType, it should be one of (links|samples|link_samples) + * + * @param string $type + * @return boolean + */ + public function validateType($type) + { + if (!in_array($type, $this->getResourceTypes())) { + throw new Exception('unknown_resource_type'); + } + return true; + } + + /** + * Validate all parameters and loads default values for omitted parameters. + * + * @param array $resource + * @param string $resourceType + */ + public function validateAttributes(&$resource, $resourceType) + { + $fields = $this->_defaultAttributes[$resourceType]; + $this->_dispatch($resource, $fields); + + $this->completeCheck($resource, $resourceType); + } + + /** + * Final check + * + * @param array $resource + * @param string $resourceType + */ + public function completeCheck(&$resource, $resourceType) + { + if ($resourceType == 'link') { + if ($resource['type'] == 'file') { + $this->validateFileDetails($resource['file']); + } + if ($resource['type'] == 'url' && empty($resource['link_url'])) { + throw new Exception('empty_url'); + } + // sample + if ($resource['sample']['type'] == 'file') { + $this->validateFileDetails($resource['sample']['file']); + } + if ($resource['sample']['type'] == 'url' && empty($resource['sample']['url'])) { + throw new Exception('empty_url'); + } + } + if ($resourceType == 'sample') { + if ($resource['type'] == 'file') { + $this->validateFileDetails($resource['file']); + } + if ($resource['type'] == 'url' && empty($resource['sample_url'])) { + throw new Exception('empty_url'); + } + } + } + + /** + * Validate variable, in case of fault throw exception + * + * @param mixed $var + */ + public function validateFileDetails(&$var) + { + if (!isset ($var['name']) || !is_string($var['name']) || strlen($var['name']) === 0) { + throw new Exception('no_filename'); + } + if (!isset ($var['base64_content']) + || !is_string($var['base64_content']) + || strlen($var['base64_content']) === 0 + ) { + throw new Exception('no_file_base64_content'); + } + } + + /** + * Runs all checks. + * + * @param array $resource + * @param array $fields + */ + protected function _dispatch(&$resource, $fields) + { + foreach ($fields as $name => $validator) { + if (is_string($validator) && strlen($validator) > 0 && array_key_exists($name, $resource)) { + $call = 'validate' . $validator; + $this->$call($resource[$name]); + } + if (is_array($validator)) { + $this->_dispatch($resource[$name], $validator); + } + } + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param string $var + */ + public function validateTitle(&$var) + { + if (!is_string($var) || strlen($var) === 0) { + throw new Exception('no_title'); + } + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param float $var + */ + public function validatePrice(&$var) + { + $var = is_numeric($var)? floatval($var) : floatval(0); + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param int $var + */ + public function validateNumOfDownloads(&$var) + { + $var = is_numeric($var)? intval($var) : 0; + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param int|boolean $var + */ + public function validateUnlimited(&$var) + { + $var = ((is_numeric($var) && $var >= 0 && $var <= 1) || (is_bool($var)))? intval($var) : 0; + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param int $var + */ + public function validateShareable(&$var) + { + $var = (is_numeric($var) && $var >= 0 && $var <= 2)? intval($var) : 2; + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param array $var + */ + public function validateFile(&$var) + { + $var = is_array($var)? $var : null; + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param string $var + */ + public function validateUrl(&$var) + { + + if (is_string($var) && strlen($var) > 0) { + $urlregex = "/^(https?|ftp)\:\/\/([a-z0-9+\!\*\(\)\,\;\?\&\=\$\_\.\-]+(\:[a-z0-9+\!\*\(\)\,\;\?\&\=\$\_\.\-]+)?@)?[a-z0-9\+\$\_\-]+(\.[a-z0-9+\$\_\-]+)*(\:[0-9]{2,5})?(\/([a-z0-9+\$\_\-]\.?)+)*\/?(\?[a-z\+\&\$\_\.\-][a-z0-9\;\:\@\/\&\%\=\+\$\_\.\-]*)?(#[a-z\_\.\-][a-z0-9\+\$\_\.\-]*)?$/i"; + if (!preg_match($urlregex, $var)) { + throw new Exception('url_not_valid'); + } + } else { + $var = ''; + } + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param int $var + */ + public function validateOrder(&$var) + { + $var = is_numeric($var)? intval($var) : 0; + } + + /** + * Validate variable, in case of fault loads default entity. + * + * @param string $var + */ + public function validateUploadType(&$var) + { + $var = in_array($var, $this->_uploadTypes)? $var : 'file'; + } +} diff --git a/app/code/core/Mage/Downloadable/etc/api.xml b/app/code/core/Mage/Downloadable/etc/api.xml new file mode 100644 index 00000000000..7b9d2fe8d8a --- /dev/null +++ b/app/code/core/Mage/Downloadable/etc/api.xml @@ -0,0 +1,156 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Downloadable + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <catalog_product_downloadable_link translate="title" module="Mage_Downloadable"> + <model>Mage_Downloadable_Model_Link_Api</model> + <title>Category API</title> + <acl>downloadable/link</acl> + <methods> + <add translate="title" module="Mage_Downloadable"> + <title>Add links and samples to downloadable product</title> + <method>add</method> + <acl>downloadable/link/add</acl> + </add> + <list translate="title" module="Mage_Downloadable"> + <title>Retrieve links and samples list from downloadable product</title> + <method>items</method> + <acl>downloadable/link/list</acl> + </list> + <remove translate="title" module="Mage_Downloadable"> + <title>Remove links and samples from downloadable product</title> + <acl>downloadable/link/remove</acl> + </remove> + </methods> + <faults module="Mage_Downloadable"> + <store_not_exists> + <code>100</code> + <message>Store with requested code or ID does not exist.</message> + </store_not_exists> + <product_not_exists> + <code>101</code> + <message>Product with requested ID does not exist.</message> + </product_not_exists> + <links_and_samples_allowed> + <code>401</code> + <message>The resourceType value is invalid, only "links" and "samples" are allowed.</message> + </links_and_samples_allowed> + <empty_url> + <code>402</code> + <message>URL cannot be empty.</message> + </empty_url> + <no_filename> + <code>403</code> + <message>Filename is omitted or contains not allowed characters.</message> + </no_filename> + <no_file_base64_content> + <code>404</code> + <message>File content should be passed as base64 string. For details, please see http://en.wikipedia.org/wiki/Base64</message> + </no_file_base64_content> + <no_title> + <code>405</code> + <message>Title cannot be empty.</message> + </no_title> + <unknown_resource_type> + <code>406</code> + <message>Content type is invalid, only "link", "link_samples", and "sample" are allowed.</message> + </unknown_resource_type> + <product_not_downloadable> + <code>408</code> + <message>Product type is invalid. Downloadable content can be added only to "downloadable" products.</message> + </product_not_downloadable> + <incorect_file_extension> + <code>409</code> + <message>Filename extension is invalid.</message> + </incorect_file_extension> + <file_size_is_to_big> + <code>410</code> + <message>Uploaded file is too big.</message> + </file_size_is_to_big> + <tmp_dir_is_not_writeable> + <code>411</code> + <message>There are no permissions for writing to temporary folder.</message> + </tmp_dir_is_not_writeable> + <can_not_create_sub_tmp_folder> + <code>411</code> + <message>Cannot create sub folder in temporary folder.</message> + </can_not_create_sub_tmp_folder> + <link_was_not_found> + <code>412</code> + <message>Link or sample with specified ID was not found.</message> + </link_was_not_found> + <incorrect_resource_type> + <code>413</code> + <message>Allowed resource type values for remove method are "links" and "samples".</message> + </incorrect_resource_type> + <save_error> + <code>414</code> + <message>Unable to save action. Details are in error message.</message> + </save_error> + <validation_error> + <code>415</code> + <message>Validation error has occurred.</message> + </validation_error> + <remove_error> + <code>416</code> + <message>Unable to remove link. Details are in error message.</message> + </remove_error> + </faults> + </catalog_product_downloadable_link> + </resources> + <resources_alias> + <product_downloadable_link>catalog_product_downloadable_link</product_downloadable_link> + </resources_alias> + <v2> + <resources_function_prefix> + <product_downloadable_link>catalogProductDownloadableLink</product_downloadable_link> + </resources_function_prefix> + </v2> + <acl> + <resources> + <catalog> + <product> + <downloadable_link translate="title" module="Mage_Downloadable"> + <title>Product downloadable links</title> + <add translate="title" module="Mage_Downloadable"> + <title>Add</title> + </add> + <list translate="title" module="Mage_Downloadable"> + <title>List</title> + </list> + <remove translate="title" module="Mage_Downloadable"> + <title>Remove</title> + </remove> + </downloadable_link> + </product> + </catalog> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/Downloadable/etc/wsdl.xml b/app/code/core/Mage/Downloadable/etc/wsdl.xml new file mode 100644 index 00000000000..b463be954b2 --- /dev/null +++ b/app/code/core/Mage/Downloadable/etc/wsdl.xml @@ -0,0 +1,193 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" + schemaLocation="http://schemas.xmlsoap.org/soap/encoding/"/> + <complexType name="catalogProductDownloadableLinkFileEntity"> + <all> + <element name="name" type="xsd:string" minOccurs="0" /> + <element name="base64_content" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogProductDownloadableLinkAddSampleEntity"> + <all> + <element name="type" type="xsd:string" minOccurs="0" /> + <element name="file" type="typens:catalogProductDownloadableLinkFileEntity" minOccurs="0" /> + <element name="url" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogProductDownloadableLinkAddEntity"> + <all> + <element name="title" type="xsd:string" minOccurs="1" /> + <element name="price" type="xsd:string" minOccurs="0" /> + <element name="is_unlimited" type="xsd:int" minOccurs="0" /> + <element name="number_of_downloads" type="xsd:int" minOccurs="0" /> + <element name="is_shareable" type="xsd:int" minOccurs="0" /> + <element name="sample" type="typens:catalogProductDownloadableLinkAddSampleEntity" minOccurs="0" /> + <element name="type" type="xsd:string" minOccurs="0" /> + <element name="file" type="typens:catalogProductDownloadableLinkFileEntity" minOccurs="0" /> + <element name="link_url" type="xsd:string" minOccurs="0" /> + <element name="sample_url" type="xsd:string" minOccurs="0" /> + <element name="sort_order" type="xsd:int" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogProductDownloadableLinkFileInfoEntity"> + <all> + <element name="file" type="xsd:string" /> + <element name="name" type="xsd:string" /> + <element name="size" type="xsd:int" /> + <element name="status" type="xsd:string" /> + </all> + </complexType> + <complexType name="catalogProductDownloadableLinkFileInfoEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductDownloadableLinkFileInfoEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductDownloadableLinkEntity"> + <all> + <element name="link_id" type="xsd:string" /> + <element name="title" type="xsd:string" /> + <element name="price" type="xsd:string" /> + <element name="number_of_downloads" type="xsd:int" minOccurs="0" /> + <element name="is_unlimited" type="xsd:int" minOccurs="0" /> + <element name="is_shareable" type="xsd:int" /> + <element name="link_url" type="xsd:string" /> + <element name="link_type" type="xsd:string" /> + <element name="sample_file" type="xsd:string" minOccurs="0" /> + <element name="sample_url" type="xsd:string" minOccurs="0" /> + <element name="sample_type" type="xsd:string" /> + <element name="sort_order" type="xsd:int" /> + <element name="file_save" type="typens:catalogProductDownloadableLinkFileInfoEntityArray" minOccurs="0" /> + <element name="sample_file_save" type="typens:catalogProductDownloadableLinkFileInfoEntityArray" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogProductDownloadableLinkEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductDownloadableLinkEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductDownloadableLinkSampleEntity"> + <all> + <element name="sample_id" type="xsd:string" /> + <element name="product_id" type="xsd:string" /> + <element name="sample_file" type="xsd:string" minOccurs="0" /> + <element name="sample_url" type="xsd:string" minOccurs="0" /> + <element name="sample_type" type="xsd:string" /> + <element name="sort_order" type="xsd:string" /> + <element name="default_title" type="xsd:string" /> + <element name="store_title" type="xsd:string" /> + <element name="title" type="xsd:string" /> + </all> + </complexType> + <complexType name="catalogProductDownloadableLinkSampleEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductDownloadableLinkSampleEntity[]"/> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductDownloadableLinkInfoEntity"> + <all> + <element name="links" type="typens:catalogProductDownloadableLinkEntityArray" /> + <element name="samples" type="typens:catalogProductDownloadableLinkSampleEntityArray" /> + </all> + </complexType> + </schema> + </types> + <message name="catalogProductDownloadableLinkAddRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="productId" type="xsd:string"/> + <part name="resource" type="typens:catalogProductDownloadableLinkAddEntity"/> + <part name="resourceType" type="xsd:string"/> + <part name="store" type="xsd:string"/> + <part name="identifierType" type="xsd:string"/> + </message> + <message name="catalogProductDownloadableLinkAddResponse"> + <part name="respons" type="xsd:int"/> + </message> + <message name="catalogProductDownloadableLinkListRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="productId" type="xsd:string"/> + <part name="store" type="xsd:string"/> + <part name="identifierType" type="xsd:string"/> + </message> + <message name="catalogProductDownloadableLinkListResponse"> + <part name="respons" type="typens:catalogProductDownloadableLinkInfoEntity"/> + </message> + <message name="catalogProductDownloadableLinkRemoveRequest"> + <part name="sessionId" type="xsd:string"/> + <part name="linkId" type="xsd:string"/> + <part name="resourceType" type="xsd:string"/> + </message> + <message name="catalogProductDownloadableLinkRemoveResponse"> + <part name="respons" type="xsd:boolean"/> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogProductDownloadableLinkAdd"> + <documentation>Add links to downloadable product</documentation> + <input message="typens:catalogProductDownloadableLinkAddRequest"/> + <output message="typens:catalogProductDownloadableLinkAddResponse"/> + </operation> + <operation name="catalogProductDownloadableLinkList"> + <documentation>Retrieve list of links and samples for downloadable product</documentation> + <input message="typens:catalogProductDownloadableLinkListRequest"/> + <output message="typens:catalogProductDownloadableLinkListResponse"/> + </operation> + <operation name="catalogProductDownloadableLinkRemove"> + <documentation>Remove links and samples from downloadable product</documentation> + <input message="typens:catalogProductDownloadableLinkRemoveRequest"/> + <output message="typens:catalogProductDownloadableLinkRemoveResponse"/> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + <operation name="catalogProductDownloadableLinkAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductDownloadableLinkList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + <operation name="catalogProductDownloadableLinkRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action"/> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" + encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}"/> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/Downloadable/etc/wsi.xml b/app/code/core/Mage/Downloadable/etc/wsi.xml new file mode 100644 index 00000000000..498eb427f3c --- /dev/null +++ b/app/code/core/Mage/Downloadable/etc/wsi.xml @@ -0,0 +1,220 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="catalogProductDownloadableLinkFileEntity"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="base64_content" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkAddSampleEntity"> + <xsd:sequence> + <xsd:element name="type" type="xsd:string" minOccurs="0" /> + <xsd:element name="file" type="typens:catalogProductDownloadableLinkFileEntity" minOccurs="0" /> + <xsd:element name="url" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkAddEntity"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_unlimited" type="xsd:int" minOccurs="0" /> + <xsd:element name="number_of_downloads" type="xsd:int" minOccurs="0" /> + <xsd:element name="is_shareable" type="xsd:int" minOccurs="0" /> + <xsd:element name="sample" type="typens:catalogProductDownloadableLinkAddSampleEntity" minOccurs="0" /> + <xsd:element name="type" type="xsd:string" minOccurs="0" /> + <xsd:element name="file" type="typens:catalogProductDownloadableLinkFileEntity" minOccurs="0" /> + <xsd:element name="link_url" type="xsd:string" minOccurs="0" /> + <xsd:element name="sample_url" type="xsd:string" minOccurs="0" /> + <xsd:element name="sort_order" type="xsd:int" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkFileInfoEntity"> + <xsd:sequence> + <xsd:element name="file" type="xsd:string" /> + <xsd:element name="name" type="xsd:string" /> + <xsd:element name="size" type="xsd:int" /> + <xsd:element name="status" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkFileInfoEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductDownloadableLinkFileInfoEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkEntity"> + <xsd:sequence> + <xsd:element name="link_id" type="xsd:string" /> + <xsd:element name="title" type="xsd:string" /> + <xsd:element name="price" type="xsd:string" /> + <xsd:element name="number_of_downloads" type="xsd:int" minOccurs="0" /> + <xsd:element name="is_unlimited" type="xsd:int" minOccurs="0" /> + <xsd:element name="is_shareable" type="xsd:int" /> + <xsd:element name="link_url" type="xsd:string" /> + <xsd:element name="link_type" type="xsd:string" /> + <xsd:element name="sample_file" type="xsd:string" minOccurs="0" /> + <xsd:element name="sample_url" type="xsd:string" minOccurs="0" /> + <xsd:element name="sample_type" type="xsd:string" /> + <xsd:element name="sort_order" type="xsd:int" /> + <xsd:element name="file_save" type="typens:catalogProductDownloadableLinkFileInfoEntityArray" minOccurs="0" /> + <xsd:element name="sample_file_save" type="typens:catalogProductDownloadableLinkFileInfoEntityArray" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductDownloadableLinkEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkSampleEntity"> + <xsd:sequence> + <xsd:element name="sample_id" type="xsd:string" /> + <xsd:element name="product_id" type="xsd:string" /> + <xsd:element name="sample_file" type="xsd:string" minOccurs="0" /> + <xsd:element name="sample_url" type="xsd:string" minOccurs="0" /> + <xsd:element name="sample_type" type="xsd:string" /> + <xsd:element name="sort_order" type="xsd:string" /> + <xsd:element name="default_title" type="xsd:string" /> + <xsd:element name="store_title" type="xsd:string" /> + <xsd:element name="title" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkSampleEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductDownloadableLinkSampleEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductDownloadableLinkListEntity"> + <xsd:sequence> + <xsd:element name="links" type="typens:catalogProductDownloadableLinkEntityArray" /> + <xsd:element name="samples" type="typens:catalogProductDownloadableLinkSampleEntityArray" /> + </xsd:sequence> + </xsd:complexType> + + + <xsd:element name="catalogProductDownloadableLinkAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="resource" type="typens:catalogProductDownloadableLinkAddEntity" /> + <xsd:element minOccurs="1" maxOccurs="1" name="resourceType" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductDownloadableLinkAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductDownloadableLinkListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="identifierType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductDownloadableLinkListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:catalogProductDownloadableLinkListEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductDownloadableLinkRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="linkId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="resourceType" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductDownloadableLinkRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="catalogProductDownloadableLinkAddRequest"> + <wsdl:part name="parameters" element="typens:catalogProductDownloadableLinkAddRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductDownloadableLinkAddResponse"> + <wsdl:part name="parameters" element="typens:catalogProductDownloadableLinkAddResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductDownloadableLinkListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductDownloadableLinkListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductDownloadableLinkListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductDownloadableLinkListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductDownloadableLinkRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductDownloadableLinkRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductDownloadableLinkRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductDownloadableLinkRemoveResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogProductDownloadableLinkAdd"> + <wsdl:documentation>Add links to downloadable product</wsdl:documentation> + <wsdl:input message="typens:catalogProductDownloadableLinkAddRequest" /> + <wsdl:output message="typens:catalogProductDownloadableLinkAddResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductDownloadableLinkList"> + <wsdl:documentation>Retrieve list of links and samples for downloadable product</wsdl:documentation> + <wsdl:input message="typens:catalogProductDownloadableLinkListRequest" /> + <wsdl:output message="typens:catalogProductDownloadableLinkListResponse" /> + </wsdl:operation> + <wsdl:operation name="catalogProductDownloadableLinkRemove"> + <wsdl:documentation>Remove links and samples from downloadable product</wsdl:documentation> + <wsdl:input message="typens:catalogProductDownloadableLinkRemoveRequest" /> + <wsdl:output message="typens:catalogProductDownloadableLinkRemoveResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogProductDownloadableLinkAdd"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductDownloadableLinkList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="catalogProductDownloadableLinkRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> +</wsdl:definitions> diff --git a/app/code/core/Mage/GiftMessage/Model/Api.php b/app/code/core/Mage/GiftMessage/Model/Api.php new file mode 100644 index 00000000000..776dc6f7c12 --- /dev/null +++ b/app/code/core/Mage/GiftMessage/Model/Api.php @@ -0,0 +1,187 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_GiftMessage + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * GiftMessage api + * + * @category Mage + * @package Mage_GiftMessage + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_GiftMessage_Model_Api extends Mage_Checkout_Model_Api_Resource_Product +{ + /** + * Return an Array of attributes. + * + * @param Array $obj + * @return Array + */ + protected function _prepareData($arr) + { + if (is_array($arr)) { + return $arr; + } + return array(); + } + + /** + * Raise event for setting a giftMessage. + * + * @param String $entityId + * @param Mage_Core_Controller_Request_Http $request + * @param Mage_Sales_Model_Quote $quote + * @return AssociativeArray + */ + protected function _setGiftMessage($entityId, $request, $quote) + { + + /** + * Below code will catch exceptions only in DeveloperMode + * @see Mage_Core_Model_App::_callObserverMethod($object, $method, $observer) + * And result of Mage::dispatchEvent will always return an Object of Mage_Core_Model_App. + */ + try { + /** Frontend area events must be loaded as we emulate frontend behavior. */ + Mage::app()->loadAreaPart(Mage_Core_Model_App_Area::AREA_FRONTEND, Mage_Core_Model_App_Area::PART_EVENTS); + Mage::dispatchEvent( + 'checkout_controller_onepage_save_shipping_method', + array('request' => $request, 'quote' => $quote) + ); + return array('entityId' => $entityId, 'result' => true, 'error' => ''); + } catch (Exception $e) { + return array('entityId' => $entityId, 'result' => false, 'error' => $e->getMessage()); + } + } + + /** + * Set GiftMessage for a Quote. + * + * @param String $quoteId + * @param AssociativeArray $giftMessage + * @param String $store + * @return AssociativeArray + */ + public function setForQuote($quoteId, $giftMessage, $store = null) + { + /** @var $quote Mage_Sales_Model_Quote */ + $quote = $this->_getQuote($quoteId, $store); + + $giftMessage = $this->_prepareData($giftMessage); + if (empty($giftMessage)) { + $this->_fault('giftmessage_invalid_data'); + } + + $giftMessage['type'] = 'quote'; + $giftMessages = array($quoteId => $giftMessage); + $request = new Mage_Core_Controller_Request_Http(); + $request->setParam("giftmessage", $giftMessages); + + return $this->_setGiftMessage($quote->getId(), $request, $quote); + } + + /** + * Set a GiftMessage to QuoteItem by product + * + * @param String $quoteId + * @param Array $productsAndMessages + * @param String $store + * @return array + */ + public function setForQuoteProduct($quoteId, $productsAndMessages, $store = null) + { + /** @var $quote Mage_Sales_Model_Quote */ + $quote = $this->_getQuote($quoteId, $store); + + $productsAndMessages = $this->_prepareData($productsAndMessages); + if (empty($productsAndMessages)) { + $this->_fault('invalid_data'); + } + + if (count($productsAndMessages) == 2 + && isset($productsAndMessages['product']) + && isset($productsAndMessages['message'])) { + $productsAndMessages = array($productsAndMessages); + } + + $results = array(); + foreach ($productsAndMessages as $productAndMessage) { + if (isset($productAndMessage['product']) && isset($productAndMessage['message'])) { + $product = $this->_prepareData($productAndMessage['product']); + if (empty($product)) { + $this->_fault('product_invalid_data'); + } + $message = $this->_prepareData($productAndMessage['message']); + if (empty($message)) { + $this->_fault('giftmessage_invalid_data'); + } + + if (isset($product['product_id'])) { + $productByItem = $this->_getProduct($product['product_id'], $store, "id"); + } elseif (isset($product['sku'])) { + $productByItem = $this->_getProduct($product['sku'], $store, "sku"); + } else { + continue; + } + + $productObj = $this->_getProductRequest($product); + $quoteItem = $this->_getQuoteItemByProduct($quote, $productByItem, $productObj); + $results[] = $this->setForQuoteItem($quoteItem->getId(), $message, $store); + } + } + + return $results; + } + + /** + * Set GiftMessage for a QuoteItem by its Id. + * + * @param String $quoteItemId + * @param AssociativeArray $giftMessage + * @param String $store + * @return AssociativeArray + */ + public function setForQuoteItem($quoteItemId, $giftMessage, $store = null) + { + /** @var $quote Mage_Sales_Model_Quote_Item */ + $quoteItem = Mage::getModel('Mage_Sales_Model_Quote_Item')->load($quoteItemId); + if (is_null($quoteItem->getId())) { + $this->_fault("quote_item_not_exists"); + } + + /** @var $quote Mage_Sales_Model_Quote */ + $quote = $this->_getQuote($quoteItem->getQuoteId(), $store); + + $giftMessage = $this->_prepareData($giftMessage); + $giftMessage['type'] = 'quote_item'; + + $giftMessages = array($quoteItem->getId() => $giftMessage); + + $request = new Mage_Core_Controller_Request_Http(); + $request->setParam("giftmessage", $giftMessages); + + return $this->_setGiftMessage($quoteItemId, $request, $quote); + } +} diff --git a/app/code/core/Mage/GiftMessage/Model/Api/V2.php b/app/code/core/Mage/GiftMessage/Model/Api/V2.php new file mode 100644 index 00000000000..16fb55058c6 --- /dev/null +++ b/app/code/core/Mage/GiftMessage/Model/Api/V2.php @@ -0,0 +1,113 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_GiftMessage + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * GiftMessage api + * + * @category Mage + * @package Mage_GiftMessage + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_GiftMessage_Model_Api_V2 extends Mage_GiftMessage_Model_Api +{ + + /** + * Return an Array of Object attributes. + * + * @param Mixed $data + * @return Array + */ + protected function _prepareData($data) + { + if (is_object($data)) { + $arr = get_object_vars($data); + foreach ($arr as $key => $value) { + $assocArr = array(); + if (is_array($value)) { + foreach ($value as $v) { + if (is_object($v) && count(get_object_vars($v)) == 2 + && isset($v->key) && isset($v->value) + ) { + $assocArr[$v->key] = $v->value; + } + } + } + if (!empty($assocArr)) { + $arr[$key] = $assocArr; + } + } + $arr = $this->_prepareData($arr); + return parent::_prepareData($arr); + } + if (is_array($data)) { + foreach ($data as $key => $value) { + if (is_object($value) || is_array($value)) { + $data[$key] = $this->_prepareData($value); + } else { + $data[$key] = $value; + } + } + return parent::_prepareData($data); + } + return $data; + } + + /** + * Raise event for setting a giftMessage. + * + * @param String $entityId + * @param Mage_Core_Controller_Request_Http $request + * @param Mage_Sales_Model_Quote $quote + * @return stdClass + */ + protected function _setGiftMessage($entityId, $request, $quote) + { + $response = new stdClass(); + $response->entityId = $entityId; + + /** + * Below code will catch exceptions only in DeveloperMode + * + * @see Mage_Core_Model_App::_callObserverMethod($object, $method, $observer) + * And result of Mage::dispatchEvent will always return an Object of Mage_Core_Model_App. + */ + try { + /** Frontend area events must be loaded as we emulate frontend behavior. */ + Mage::app()->loadAreaPart(Mage_Core_Model_App_Area::AREA_FRONTEND, Mage_Core_Model_App_Area::PART_EVENTS); + Mage::dispatchEvent( + 'checkout_controller_onepage_save_shipping_method', + array('request' => $request, 'quote' => $quote) + ); + $response->result = true; + $response->error = ''; + } catch (Exception $e) { + $response->result = false; + $response->error = $e->getMessage(); + } + return $response; + } + +} diff --git a/app/code/core/Mage/GiftMessage/etc/api.xml b/app/code/core/Mage/GiftMessage/etc/api.xml new file mode 100644 index 00000000000..fe1225eaca9 --- /dev/null +++ b/app/code/core/Mage/GiftMessage/etc/api.xml @@ -0,0 +1,92 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_GiftMessage + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <giftmessage translate="title" module="Mage_GiftMessage"> + <model>Mage_GiftMessage_Model_Api</model> + <title>Gift Message API</title> + <acl>giftmessage/set</acl> + <methods> + <setForQuote translate="title" module="Mage_GiftMessage"> + <title>Add gift message for shopping cart</title> + <method>setForQuote</method> + <acl>giftmessage/set</acl> + </setForQuote> + <setForQuoteItem translate="title" module="Mage_GiftMessage"> + <title>Add gift messages for quote item of shopping cart</title> + <method>setForQuoteItem</method> + <acl>giftmessage/set</acl> + </setForQuoteItem> + <setForQuoteProduct translate="title" module="Mage_GiftMessage"> + <title>Add gift messages to products of shopping cart</title> + <method>setForQuoteProduct</method> + <acl>giftmessage/set</acl> + </setForQuoteProduct> + </methods> + <faults module="Mage_GiftMessage"> + <store_not_exists> + <code>1001</code> + <message>Cannot perform operation because store does not exist.</message> + </store_not_exists> + <quote_not_exists> + <code>1002</code> + <message>Cannot perform operation because quote does not exist.</message> + </quote_not_exists> + <giftmessage_invalid_data> + <code>1101</code> + <message>Gift message data is not valid.</message> + </giftmessage_invalid_data> + <product_invalid_data> + <code>1102</code> + <message>Product data is not valid.</message> + </product_invalid_data> + <quote_item_not_exists> + <code>1103</code> + <message>Quote item does not exist.</message> + </quote_item_not_exists> + </faults> + </giftmessage> + </resources> + <acl> + <resources> + <giftmessage translate="title" module="Mage_Checkout"> + <title>Gift Message</title> + <set translate="title" module="Mage_Checkout"> + <title>Add gift messages to shopping cart</title> + </set> + </giftmessage> + </resources> + </acl> + <v2> + <resources_function_prefix> + <giftmessage>giftMessage</giftmessage> + </resources_function_prefix> + </v2> + </api> +</config> diff --git a/app/code/core/Mage/GiftMessage/etc/wsdl.xml b/app/code/core/Mage/GiftMessage/etc/wsdl.xml new file mode 100644 index 00000000000..9fd677d2cac --- /dev/null +++ b/app/code/core/Mage/GiftMessage/etc/wsdl.xml @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="giftMessageEntity"> + <sequence> + <element name="from" type="xsd:string" minOccurs="0" /> + <element name="to" type="xsd:string" minOccurs="0" /> + <element name="message" type="xsd:string" minOccurs="0" /> + </sequence> + </complexType> + <complexType name="giftMessageResponse"> + <sequence> + <element name="entityId" type="xsd:string" minOccurs="0" /> + <element name="result" type="xsd:boolean" minOccurs="0" /> + <element name="error" type="xsd:string" minOccurs="0" /> + </sequence> + </complexType> + <complexType name="giftMessageResponseArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:giftMessageResponse[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="giftMessageAssociativeProductsEntity"> + <sequence> + <element name="product" type="typens:shoppingCartProductEntity" /> + <element name="message" type="typens:giftMessageEntity" /> + </sequence> + </complexType> + <complexType name="giftMessageAssociativeProductsEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:giftMessageAssociativeProductsEntity[]" /> + </restriction> + </complexContent> + </complexType> + </schema> + </types> + <message name="giftMessageForQuoteRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="quoteId" type="xsd:string" /> + <part name="giftMessage" type="typens:giftMessageEntity" /> + <part name="storeId" type="xsd:string" /> + </message> + <message name="giftMessageForQuoteResponse"> + <part name="result" type="typens:giftMessageResponse" /> + </message> + <message name="giftMessageForQuoteItemRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="quoteItemId" type="xsd:string" /> + <part name="giftMessage" type="typens:giftMessageEntity" /> + <part name="storeId" type="xsd:string" /> + </message> + <message name="giftMessageForQuoteItemResponse"> + <part name="result" type="typens:giftMessageResponse" /> + </message> + <message name="giftMessageForQuoteProductRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="quoteId" type="xsd:string" /> + <part name="productsAndMessages" type="typens:giftMessageAssociativeProductsEntityArray" /> + <part name="storeId" type="xsd:string" /> + </message> + <message name="giftMessageForQuoteProductResponse"> + <part name="result" type="typens:giftMessageResponseArray" /> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="giftMessageSetForQuote"> + <documentation>Set a gift message to the cart</documentation> + <input message="typens:giftMessageForQuoteRequest" /> + <output message="typens:giftMessageForQuoteResponse" /> + </operation> + <operation name="giftMessageSetForQuoteItem"> + <documentation>Setting a gift messages to the quote item</documentation> + <input message="typens:giftMessageForQuoteItemRequest" /> + <output message="typens:giftMessageForQuoteItemResponse" /> + </operation> + <operation name="giftMessageSetForQuoteProduct"> + <documentation>Setting a gift messages to the quote items by products</documentation> + <input message="typens:giftMessageForQuoteProductRequest" /> + <output message="typens:giftMessageForQuoteProductResponse" /> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="giftMessageSetForQuote"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="giftMessageSetForQuoteItem"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="giftMessageSetForQuoteProduct"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/GiftMessage/etc/wsi.xml b/app/code/core/Mage/GiftMessage/etc/wsi.xml new file mode 100644 index 00000000000..155d52646b5 --- /dev/null +++ b/app/code/core/Mage/GiftMessage/etc/wsi.xml @@ -0,0 +1,161 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="giftMessageEntity"> + <xsd:sequence> + <xsd:element name="from" type="xsd:string" minOccurs="0" /> + <xsd:element name="to" type="xsd:string" minOccurs="0" /> + <xsd:element name="message" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="giftMessageResponse"> + <xsd:sequence> + <xsd:element name="entityId" type="xsd:string" minOccurs="0" /> + <xsd:element name="result" type="xsd:boolean" minOccurs="0" /> + <xsd:element name="error" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="giftMessageResponseArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:giftMessageResponse" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="giftMessageAssociativeProductsEntity"> + <xsd:sequence> + <xsd:element name="product" type="typens:shoppingCartProductEntity" /> + <xsd:element name="message" type="typens:giftMessageEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="giftMessageAssociativeProductsEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:giftMessageAssociativeProductsEntity" /> + </xsd:sequence> + </xsd:complexType> + + + <xsd:element name="giftMessageForQuoteRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="giftMessage" type="typens:giftMessageEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="giftMessageForQuoteResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:giftMessageResponse" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="giftMessageForQuoteItemRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteItemId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="giftMessage" type="typens:giftMessageEntity" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="giftMessageForQuoteItemResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:giftMessageResponse" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="giftMessageForQuoteProductRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="quoteId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="productsAndMessages" type="typens:giftMessageAssociativeProductsEntityArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="store" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="giftMessageForQuoteProductResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:giftMessageResponseArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="giftMessageForQuoteRequest"> + <wsdl:part name="parameters" element="typens:giftMessageForQuoteRequestParam" /> + </wsdl:message> + <wsdl:message name="giftMessageForQuoteResponse"> + <wsdl:part name="parameters" element="typens:giftMessageForQuoteResponseParam" /> + </wsdl:message> + <wsdl:message name="giftMessageForQuoteItemRequest"> + <wsdl:part name="parameters" element="typens:giftMessageForQuoteItemRequestParam" /> + </wsdl:message> + <wsdl:message name="giftMessageForQuoteItemResponse"> + <wsdl:part name="parameters" element="typens:giftMessageForQuoteItemResponseParam" /> + </wsdl:message> + <wsdl:message name="giftMessageForQuoteProductRequest"> + <wsdl:part name="parameters" element="typens:giftMessageForQuoteProductRequestParam" /> + </wsdl:message> + <wsdl:message name="giftMessageForQuoteProductResponse"> + <wsdl:part name="parameters" element="typens:giftMessageForQuoteProductResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="giftMessageSetForQuote"> + <wsdl:documentation>Set a gift message to the cart</wsdl:documentation> + <wsdl:input message="typens:giftMessageForQuoteRequest" /> + <wsdl:output message="typens:giftMessageForQuoteResponse" /> + </wsdl:operation> + <wsdl:operation name="giftMessageSetForQuoteItem"> + <wsdl:documentation>Setting a gift messages to the quote item</wsdl:documentation> + <wsdl:input message="typens:giftMessageForQuoteItemRequest" /> + <wsdl:output message="typens:giftMessageForQuoteItemResponse" /> + </wsdl:operation> + <wsdl:operation name="giftMessageSetForQuoteProduct"> + <wsdl:documentation>Setting a gift messages to the quote items by products</wsdl:documentation> + <wsdl:input message="typens:giftMessageForQuoteProductRequest" /> + <wsdl:output message="typens:giftMessageForQuoteProductResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="giftMessageSetForQuote"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="giftMessageSetForQuoteItem"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="giftMessageSetForQuoteProduct"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> +</wsdl:definitions> diff --git a/app/code/core/Mage/GoogleShopping/Block/Adminhtml/Types/Edit/Attributes.php b/app/code/core/Mage/GoogleShopping/Block/Adminhtml/Types/Edit/Attributes.php index 88033575fa8..ead66fc53bf 100644 --- a/app/code/core/Mage/GoogleShopping/Block/Adminhtml/Types/Edit/Attributes.php +++ b/app/code/core/Mage/GoogleShopping/Block/Adminhtml/Types/Edit/Attributes.php @@ -124,7 +124,7 @@ class Mage_GoogleShopping_Block_Adminhtml_Types_Edit_Attributes */ public function getAttributesSelectHtml($escapeJsQuotes = false) { - $select = $this->getLayout()->createBlock('Mage_Adminhtml_Block_Html_Select') + $select = $this->getLayout()->createBlock('Mage_Core_Block_Html_Select') ->setId($this->getFieldId().'_{{index}}_attribute') ->setName($this->getFieldName().'[{{index}}][attribute_id]') ->setOptions($this->_getAttributes($this->getAttributeSetId(), $escapeJsQuotes)); diff --git a/app/code/core/Mage/ImportExport/Block/Adminhtml/Import/Edit/Before.php b/app/code/core/Mage/ImportExport/Block/Adminhtml/Import/Edit/Before.php index 7226ecf9506..c7f565c4189 100644 --- a/app/code/core/Mage/ImportExport/Block/Adminhtml/Import/Edit/Before.php +++ b/app/code/core/Mage/ImportExport/Block/Adminhtml/Import/Edit/Before.php @@ -48,6 +48,8 @@ class Mage_ImportExport_Block_Adminhtml_Import_Edit_Before extends Mage_Backend_ protected $_importModel; /** + * Constructor + * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout * @param Mage_Core_Model_Event_Manager $eventManager @@ -59,6 +61,8 @@ class Mage_ImportExport_Block_Adminhtml_Import_Edit_Before extends Mage_Backend_ * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Helper_Data $coreHelper * @param Mage_ImportExport_Model_Import $importModel @@ -77,13 +81,15 @@ class Mage_ImportExport_Block_Adminhtml_Import_Edit_Before extends Mage_Backend_ Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Helper_Data $coreHelper, Mage_ImportExport_Model_Import $importModel, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); $this->_coreHelper = $coreHelper; $this->_importModel = $importModel; diff --git a/app/code/core/Mage/ImportExport/Model/Import/Entity/Product.php b/app/code/core/Mage/ImportExport/Model/Import/Entity/Product.php index dc5a07c6b9d..9cf9de8f593 100644 --- a/app/code/core/Mage/ImportExport/Model/Import/Entity/Product.php +++ b/app/code/core/Mage/ImportExport/Model/Import/Entity/Product.php @@ -1195,14 +1195,18 @@ class Mage_ImportExport_Model_Import_Entity_Product extends Mage_ImportExport_Mo $this->_fileUploader->init(); - $tmpDir = Mage::getConfig()->getOptions()->getMediaDir() . '/import'; - $destDir = Mage::getConfig()->getOptions()->getMediaDir() . '/catalog/product'; - if (!is_writable($destDir)) { - @mkdir($destDir, 0777, true); + $mediaDir = Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA); + if (!$mediaDir) { + throw new Magento_Exception('Media directory is unavailable.'); } + $tmpDir = "{$mediaDir}/import"; if (!$this->_fileUploader->setTmpDir($tmpDir)) { Mage::throwException("File directory '{$tmpDir}' is not readable."); } + $destDir = "{$mediaDir}/catalog/product"; + if (!is_dir($destDir)) { + mkdir($destDir, 0777, true); + } if (!$this->_fileUploader->setDestDir($destDir)) { Mage::throwException("File directory '{$destDir}' is not writable."); } diff --git a/app/code/core/Mage/Index/Model/Lock/Storage.php b/app/code/core/Mage/Index/Model/Lock/Storage.php index 66e9ee2a9c6..9df3af7dccf 100644 --- a/app/code/core/Mage/Index/Model/Lock/Storage.php +++ b/app/code/core/Mage/Index/Model/Lock/Storage.php @@ -30,9 +30,9 @@ class Mage_Index_Model_Lock_Storage { /** - * @var Mage_Core_Model_Config + * @var Mage_Core_Model_Dir */ - protected $_configuration; + protected $_dirs; /** * @var Mage_Index_Model_Process_FileFactory @@ -47,14 +47,14 @@ class Mage_Index_Model_Lock_Storage protected $_fileHandlers = array(); /** - * @param Mage_Core_Model_Config $configuration + * @param Mage_Core_Model_Dir $dirs * @param Mage_Index_Model_Process_FileFactory $fileFactory */ public function __construct( - Mage_Core_Model_Config $configuration, + Mage_Core_Model_Dir $dirs, Mage_Index_Model_Process_FileFactory $fileFactory ) { - $this->_configuration = $configuration; + $this->_dirs = $dirs; $this->_fileFactory = $fileFactory; } @@ -68,8 +68,9 @@ class Mage_Index_Model_Lock_Storage { if (!isset($this->_fileHandlers[$processId])) { $file = $this->_fileFactory->createFromArray(); - $varDirectory = $this->_configuration->getVarDir('locks'); + $varDirectory = $this->_dirs->getDir(Mage_Core_Model_Dir::VAR_DIR) . DIRECTORY_SEPARATOR . 'locks'; $file->setAllowCreateFolders(true); + $file->open(array('path' => $varDirectory)); $fileName = 'index_process_' . $processId . '.lock'; $file->streamOpen($fileName); diff --git a/app/code/core/Mage/Install/Helper/Data.php b/app/code/core/Mage/Install/Helper/Data.php index f90aef95120..d73c915e021 100644 --- a/app/code/core/Mage/Install/Helper/Data.php +++ b/app/code/core/Mage/Install/Helper/Data.php @@ -29,65 +29,4 @@ */ class Mage_Install_Helper_Data extends Mage_Core_Helper_Abstract { - /** - * The list of var children directories that have to be cleaned before the install - * - * @var array - */ - protected $_varSubFolders; - - /** - * @var Magento_Filesystem - */ - protected $_filesystem; - - public function __construct(Magento_Filesystem $filesystem) - { - $this->_filesystem = $filesystem; - } - - /** - * Delete all service folders from var directory - */ - public function cleanVarFolder() - { - foreach ($this->getVarSubFolders() as $folder) { - try { - $this->_filesystem->delete($folder); - } catch (Magento_Filesystem_Exception $e) { - } - } - } - - /** - * Retrieve the list of service directories located in var folder - * - * @return array - */ - public function getVarSubFolders() - { - if ($this->_varSubFolders == null) { - $this->_varSubFolders = array( - Mage::getConfig()->getTempVarDir() . DS . 'session', - Mage::getConfig()->getTempVarDir() . DS . 'cache', - Mage::getConfig()->getTempVarDir() . DS . 'locks', - Mage::getConfig()->getTempVarDir() . DS . 'log', - Mage::getConfig()->getTempVarDir() . DS . 'report', - Mage::getConfig()->getTempVarDir() . DS . 'maps' - ); - } - return $this->_varSubFolders; - } - - /** - * Set the list of service directories located in var folder - * - * @param array $varSubFolders - * @return Mage_Install_Helper_Data - */ - public function setVarSubFolders(array $varSubFolders) - { - $this->_varSubFolders = $varSubFolders; - return $this; - } } diff --git a/app/code/core/Mage/Install/Model/Config.php b/app/code/core/Mage/Install/Model/Config.php index 00cd5f4a3e0..6ed540a871b 100644 --- a/app/code/core/Mage/Install/Model/Config.php +++ b/app/code/core/Mage/Install/Model/Config.php @@ -39,12 +39,6 @@ class Mage_Install_Model_Config extends Varien_Simplexml_Config const XML_PATH_CHECK_WRITEABLE = 'check/filesystem/writeable'; const XML_PATH_CHECK_EXTENSIONS = 'check/php/extensions'; - protected $_optionsMapping = array(self::XML_PATH_CHECK_WRITEABLE => array( - 'app_etc' => 'etc_dir', - 'var' => 'var_dir', - 'media' => 'media_dir', - )); - public function __construct() { parent::__construct(); @@ -110,12 +104,7 @@ class Mage_Install_Model_Config extends Varien_Simplexml_Config $items = (array) $this->getNode(self::XML_PATH_CHECK_WRITEABLE); foreach ($items as $nodeKey => $item) { $value = (array)$item; - if (isset($this->_optionsMapping[self::XML_PATH_CHECK_WRITEABLE][$nodeKey])) { - $configKey = $this->_optionsMapping[self::XML_PATH_CHECK_WRITEABLE][$nodeKey]; - $value['path'] = Mage::app()->getConfig()->getOptions()->getData($configKey); - } else { - $value['path'] = dirname(Mage::getRoot()) . $value['path']; - } + $value['path'] = Mage::getBaseDir($nodeKey); $paths[$nodeKey] = $value; } diff --git a/app/code/core/Mage/Install/Model/Installer.php b/app/code/core/Mage/Install/Model/Installer.php index 2e24f56799f..3a39c9e8eb8 100644 --- a/app/code/core/Mage/Install/Model/Installer.php +++ b/app/code/core/Mage/Install/Model/Installer.php @@ -35,12 +35,6 @@ class Mage_Install_Model_Installer extends Varien_Object { - /** - * Installer host response used to check urls - * - */ - const INSTALLER_HOST_RESPONSE = 'MAGENTO'; - /** * Installer data model used to store data between installation steps * @@ -61,7 +55,7 @@ class Mage_Install_Model_Installer extends Varien_Object /** * Get data model * - * @return Varien_Object + * @return Mage_Install_Model_Session */ public function getDataModel() { diff --git a/app/code/core/Mage/Install/Model/Installer/Config.php b/app/code/core/Mage/Install/Model/Installer/Config.php index fabfa65fb3c..5287116ac35 100644 --- a/app/code/core/Mage/Install/Model/Installer/Config.php +++ b/app/code/core/Mage/Install/Model/Installer/Config.php @@ -42,20 +42,39 @@ class Mage_Install_Model_Installer_Config extends Mage_Install_Model_Installer_A */ protected $_localConfigFile; - protected $_configData = array(); + /** + * @var Mage_Core_Model_Config + */ + protected $_config; /** - * @var Magento_Filesystem + * @var Mage_Core_Model_Dir */ + protected $_dirs; + + protected $_configData = array(); + + /** + * @var Magento_Filesystem + */ protected $_filesystem; /** + * Inject dependencies on config and directories + * + * @param Mage_Core_Model_Config $config + * @param Mage_Core_Model_Dir $dirs * @param Magento_Filesystem $filesystem */ - public function __construct(Magento_Filesystem $filesystem) - { + public function __construct( + Mage_Core_Model_Config $config, + Mage_Core_Model_Dir $dirs, + Magento_Filesystem $filesystem + ) { + $this->_localConfigFile = $dirs->getDir(Mage_Core_Model_Dir::CONFIG) . DIRECTORY_SEPARATOR . 'local.xml'; + $this->_config = $config; + $this->_dirs = $dirs; $this->_filesystem = $filesystem; - $this->_localConfigFile = Mage::getBaseDir('etc') . DS . 'local.xml'; } public function setConfigData($data) @@ -71,10 +90,20 @@ class Mage_Install_Model_Installer_Config extends Mage_Install_Model_Installer_A return $this->_configData; } + /** + * Generate installation data and record them into local.xml using local.xml.template + */ public function install() { $data = $this->getConfigData(); - foreach (Mage::getModel('Mage_Core_Model_Config')->getDistroServerVars() as $index=>$value) { + + $defaults = array( + 'root_dir' => $this->_dirs->getDir(Mage_Core_Model_Dir::ROOT), + 'app_dir' => $this->_dirs->getDir(Mage_Core_Model_Dir::APP), + 'var_dir' => $this->_dirs->getDir(Mage_Core_Model_Dir::VAR_DIR), + 'base_url' => $this->_config->getDistroBaseUrl(), + ); + foreach ($defaults as $index => $value) { if (!isset($data[$index])) { $data[$index] = $value; } @@ -109,11 +138,13 @@ class Mage_Install_Model_Installer_Config extends Mage_Install_Model_Installer_A $this->_getInstaller()->getDataModel()->setConfigData($data); - $template = $this->_filesystem->read(Mage::getBaseDir('etc') . DS . 'local.xml.template'); + $path = $this->_dirs->getDir(Mage_Core_Model_Dir::CONFIG) . DIRECTORY_SEPARATOR . 'local.xml.template'; + $contents = $this->_filesystem->read($path); foreach ($data as $index => $value) { - $template = str_replace('{{' . $index . '}}', '<![CDATA[' . $value . ']]>', $template); + $contents = str_replace('{{' . $index . '}}', '<![CDATA[' . $value . ']]>', $contents); } - $this->_filesystem->write($this->_localConfigFile, $template); + + $this->_filesystem->write($this->_localConfigFile, $contents); $this->_filesystem->changePermissions($this->_localConfigFile, 0777); } @@ -129,7 +160,7 @@ class Mage_Install_Model_Installer_Config extends Mage_Install_Model_Installer_A $baseSecureUrl = $uri->getUri(); } - $connectDefault = Mage::getConfig() + $connectDefault = $this->_config ->getResourceConnectionConfig(Mage_Core_Model_Resource::DEFAULT_SETUP_RESOURCE); $data = new Varien_Object(); @@ -146,39 +177,65 @@ class Mage_Install_Model_Installer_Config extends Mage_Install_Model_Installer_A return $data; } - protected function _checkHostsInfo($data) - { - $url = $data['protocol'] . '://' . $data['host'] . ':' . $data['port'] . $data['base_path']; - $surl = $data['secure_protocol'] . '://' . $data['secure_host'] . ':' . $data['secure_port'] - . $data['secure_base_path']; - - $this->_checkUrl($url); - $this->_checkUrl($surl, true); - - return $this; - } - - protected function _checkUrl($url, $secure = false) + /** + * Check validity of a base URL + * + * @param string $baseUrl + * @throws Exception + */ + protected function _checkUrl($baseUrl) { - $prefix = $secure ? 'install/wizard/checkSecureHost/' : 'install/wizard/checkHost/'; try { - $client = new Varien_Http_Client($url . 'index.php/' . $prefix); + $pubLibDir = $this->_dirs->getDir(Mage_Core_Model_Dir::PUB_LIB); + $staticFile = $this->_findFirstFileRelativePath($pubLibDir, '/.+\.(html?|js|css|gif|jpe?g|png)$/'); + $staticUrl = $baseUrl . $this->_dirs->getUri(Mage_Core_Model_Dir::PUB_LIB) . '/' . $staticFile; + $client = new Varien_Http_Client($staticUrl); $response = $client->request('GET'); - /* @var $responce Zend_Http_Response */ - $body = $response->getBody(); } catch (Exception $e){ - $this->_getInstaller()->getDataModel() - ->addError(Mage::helper('Mage_Install_Helper_Data')->__('The URL "%s" is not accessible.', $url)); + $this->_getInstaller()->getDataModel()->addError( + Mage::helper('Mage_Install_Helper_Data')->__('The URL "%s" is not accessible.', $baseUrl) + ); throw $e; } + if ($response->getStatus() != 200) { + $this->_getInstaller()->getDataModel()->addError( + Mage::helper('Mage_Install_Helper_Data')->__('The URL "%s" is invalid.', $baseUrl) + ); + Mage::throwException(Mage::helper('Mage_Install_Helper_Data')->__('Response from the server is invalid.')); + } + } - if ($body != Mage_Install_Model_Installer::INSTALLER_HOST_RESPONSE) { - $this->_getInstaller()->getDataModel() - ->addError(Mage::helper('Mage_Install_Helper_Data')->__('The URL "%s" is invalid.', $url)); - Mage::throwException(Mage::helper('Mage_Install_Helper_Data')->__('Response from server isn\'t valid.')); + /** + * Find a relative path to a first file located in a directory or its descendants + * + * @param string $dir Directory to search for a file within + * @param string $pattern PCRE pattern a file name has to match + * @return string|null + */ + protected function _findFirstFileRelativePath($dir, $pattern = '/.*/') + { + $childDirs = array(); + foreach (scandir($dir) as $itemName) { + if ($itemName == '.' || $itemName == '..') { + continue; + } + $itemPath = $dir . DIRECTORY_SEPARATOR . $itemName; + if (is_file($itemPath)) { + if (preg_match($pattern, $itemName)) { + return $itemName; + } + } else { + $childDirs[$itemName] = $itemPath; + } } - return $this; + foreach ($childDirs as $dirName => $dirPath) { + $filePath = $this->_findFirstFileRelativePath($dirPath, $pattern); + if ($filePath) { + return $dirName . '/' . $filePath; + } + } + return null; } public function replaceTmpInstallDate($date = null) diff --git a/app/code/core/Mage/Install/Model/Installer/Console.php b/app/code/core/Mage/Install/Model/Installer/Console.php index 914195803d1..d8de080187c 100644 --- a/app/code/core/Mage/Install/Model/Installer/Console.php +++ b/app/code/core/Mage/Install/Model/Installer/Console.php @@ -29,6 +29,13 @@ */ class Mage_Install_Model_Installer_Console extends Mage_Install_Model_Installer_Abstract { + /**#@+ + * Installation options for application initialization + */ + const OPTION_URIS = 'install_option_uris'; + const OPTION_DIRS = 'install_option_dirs'; + /**#@- */ + /** * Available installation options * @@ -65,6 +72,11 @@ class Mage_Install_Model_Installer_Console extends Mage_Install_Model_Installer_ 'cleanup_database' => array('required' => 0), ); + /** + * @var Magento_Filesystem + */ + protected $_filesystem; + /** * Installer data model to store data between installations steps * @@ -73,22 +85,37 @@ class Mage_Install_Model_Installer_Console extends Mage_Install_Model_Installer_ protected $_dataModel; /** - * @var Magento_Filesystem - */ - protected $_filesystem; - - /** - * Constructor + * Initialize application and "data model" * * @param Magento_Filesystem $filesystem + * @param array $installArgs */ - public function __construct(Magento_Filesystem $filesystem) + public function __construct(Magento_Filesystem $filesystem, array $installArgs) { - Mage::app(); $this->_filesystem = $filesystem; + $params = $this->_buildInitParams($installArgs); + Mage::app($params); $this->_getInstaller()->setDataModel($this->_getDataModel()); } + /** + * Customize application init parameters + * + * @param array $args + * @return array + */ + protected function _buildInitParams(array $args) + { + $result = array(); + if (!empty($args[self::OPTION_URIS])) { + $result[Mage_Core_Model_App::INIT_OPTION_URIS] = unserialize(base64_decode($args[self::OPTION_URIS])); + } + if (!empty($args[self::OPTION_DIRS])) { + $result[Mage_Core_Model_App::INIT_OPTION_DIRS] = unserialize(base64_decode($args[self::OPTION_DIRS])); + } + return $result; + } + /** * Retrieve validated installation options * @@ -388,21 +415,11 @@ class Mage_Install_Model_Installer_Console extends Mage_Install_Model_Installer_ $this->_cleanUpDatabase(); - /* Remove temporary directories */ - $configOptions = Mage::app()->getConfig()->getOptions(); - $dirsToRemove = array( - $configOptions->getCacheDir(), - $configOptions->getSessionDir(), - $configOptions->getExportDir(), - $configOptions->getLogDir(), - $configOptions->getVarDir() . '/report', - ); - foreach ($dirsToRemove as $dir) { + /* Remove temporary directories and local.xml */ + foreach (glob(Mage::getBaseDir(Mage_Core_Model_Dir::VAR_DIR) . '/*', GLOB_ONLYDIR) as $dir) { $this->_filesystem->delete($dir); } - - /* Remove local configuration */ - $this->_filesystem->delete($configOptions->getEtcDir() . '/local.xml'); + $this->_filesystem->delete(Mage::getBaseDir(Mage_Core_Model_Dir::CONFIG) . DIRECTORY_SEPARATOR . '/local.xml'); return true; } diff --git a/app/code/core/Mage/Install/controllers/IndexController.php b/app/code/core/Mage/Install/controllers/IndexController.php index 9d908286988..6ed3afd47d2 100644 --- a/app/code/core/Mage/Install/controllers/IndexController.php +++ b/app/code/core/Mage/Install/controllers/IndexController.php @@ -44,7 +44,9 @@ class Mage_Install_IndexController extends Mage_Install_Controller_Action { $this->setFlag('', self::FLAG_NO_CHECK_INSTALLATION, true); if (!Mage::isInstalled()) { - Mage::helper('Mage_Install_Helper_Data')->cleanVarFolder(); + foreach (glob(Mage::getBaseDir(Mage_Core_Model_Dir::VAR_DIR) . '/*', GLOB_ONLYDIR) as $dir) { + Varien_Io_File::rmdirRecursive($dir); + } } return parent::preDispatch(); } diff --git a/app/code/core/Mage/Install/controllers/WizardController.php b/app/code/core/Mage/Install/controllers/WizardController.php index c37edd15ce2..6b030c247e0 100644 --- a/app/code/core/Mage/Install/controllers/WizardController.php +++ b/app/code/core/Mage/Install/controllers/WizardController.php @@ -466,22 +466,4 @@ class Mage_Install_WizardController extends Mage_Install_Controller_Action $this->renderLayout(); Mage::getSingleton('Mage_Install_Model_Session')->clear(); } - - /** - * Host validation response - */ - public function checkHostAction() - { - $this->getResponse()->setHeader('Transfer-encoding', '', true); - $this->getResponse()->setBody(Mage_Install_Model_Installer::INSTALLER_HOST_RESPONSE); - } - - /** - * Host validation response - */ - public function checkSecureHostAction() - { - $this->getResponse()->setHeader('Transfer-encoding', '', true); - $this->getResponse()->setBody(Mage_Install_Model_Installer::INSTALLER_HOST_RESPONSE); - } } diff --git a/app/code/core/Mage/Install/etc/install.xml b/app/code/core/Mage/Install/etc/install.xml index d00dadf8abf..214572d9dcb 100644 --- a/app/code/core/Mage/Install/etc/install.xml +++ b/app/code/core/Mage/Install/etc/install.xml @@ -58,26 +58,18 @@ <check> <filesystem> <writeable> - <app_etc> - <path>/app/etc</path> + <etc> <existence>1</existence> <recursive>0</recursive> - </app_etc> + </etc> <var> - <path>/var</path> <existence>1</existence> <recursive>1</recursive> </var> <media> - <path>/pub/media</path> <existence>1</existence> <recursive>1</recursive> </media> - <theme> - <path>/pub/media/theme</path> - <existence>0</existence> - <recursive>0</recursive> - </theme> </writeable> </filesystem> <php> diff --git a/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/Admin/TokenController.php b/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/Admin/TokenController.php index 4ed93a7bdbd..708c1d33b02 100644 --- a/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/Admin/TokenController.php +++ b/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/Admin/TokenController.php @@ -43,7 +43,7 @@ class Mage_Oauth_Adminhtml_Oauth_Admin_TokenController extends Mage_Adminhtml_Co protected function _initAction() { $this->loadLayout() - ->_setActiveMenu('Mage_Oauth::system_api_oauth_admin_token'); + ->_setActiveMenu('Mage_Oauth::system_legacy_api_oauth_admin_token'); return $this; } diff --git a/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizedTokensController.php b/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizedTokensController.php index f3969e89c1a..695971337b8 100644 --- a/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizedTokensController.php +++ b/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizedTokensController.php @@ -52,7 +52,7 @@ class Mage_Oauth_Adminhtml_Oauth_AuthorizedTokensController extends Mage_Adminht */ public function indexAction() { - $this->loadLayout()->_setActiveMenu('Mage_Oauth::system_api_oauth_authorized_tokens'); + $this->loadLayout()->_setActiveMenu('Mage_Oauth::system_legacy_api_oauth_authorized_tokens'); $this->renderLayout(); } diff --git a/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/ConsumerController.php b/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/ConsumerController.php index 00dc3bf625e..05d5871fc53 100644 --- a/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/ConsumerController.php +++ b/app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/ConsumerController.php @@ -41,7 +41,7 @@ class Mage_Oauth_Adminhtml_Oauth_ConsumerController extends Mage_Adminhtml_Contr protected function _initAction() { $this->loadLayout() - ->_setActiveMenu('Mage_Oauth::system_api_oauth_consumer'); + ->_setActiveMenu('Mage_Oauth::system_legacy_api_oauth_consumer'); return $this; } /** diff --git a/app/code/core/Mage/Oauth/etc/adminhtml/menu.xml b/app/code/core/Mage/Oauth/etc/adminhtml/menu.xml index 8e21aa0cda0..36e3543c40a 100644 --- a/app/code/core/Mage/Oauth/etc/adminhtml/menu.xml +++ b/app/code/core/Mage/Oauth/etc/adminhtml/menu.xml @@ -28,8 +28,14 @@ <config> <menu> <!-- Menu elements has been disabled untill 3-legged oAuth functionality is needed. --> - <!--<add id="Mage_Oauth::system_api_oauth_consumer" title="REST - OAuth Consumers" module="Mage_Oauth" sortOrder="50" parent="Mage_Api::system_api" action="adminhtml/oauth_consumer" resource="Mage_Oauth::consumer"/>--> - <!--<add id="Mage_Oauth::system_api_oauth_authorized_tokens" title="REST - OAuth Authorized Tokens" module="Mage_Oauth" sortOrder="60" parent="Mage_Api::system_api" action="adminhtml/oauth_authorizedTokens" resource="Mage_Oauth::authorizedTokens"/>--> - <!--<add id="Mage_Oauth::system_api_oauth_admin_token" title="REST - My Apps" module="Mage_Oauth" sortOrder="70" parent="Mage_Api::system_api" action="adminhtml/oauth_admin_token" resource="Mage_Oauth::oauth_admin_token"/>--> + <!--<add id="Mage_Oauth::system_legacy_api_oauth_consumer" title="REST - OAuth Consumers"--> + <!--module="Mage_Oauth" sortOrder="50" parent="Mage_Api::system_legacy_api"--> + <!--action="adminhtml/oauth_consumer" resource="Mage_Oauth::consumer"/>--> + <!--<add id="Mage_Oauth::system_legacy_api_oauth_authorized_tokens" title="REST - OAuth Authorized Tokens"--> + <!--module="Mage_Oauth" sortOrder="60" parent="Mage_Api::system_legacy_api"--> + <!--action="adminhtml/oauth_authorizedTokens" resource="Mage_Oauth::authorizedTokens"/>--> + <!--<add id="Mage_Oauth::system_legacy_api_oauth_admin_token" title="REST - My Apps" module="Mage_Oauth"--> + <!--sortOrder="70" parent="Mage_Api::system_legacy_api" action="adminhtml/oauth_admin_token"--> + <!--resource="Mage_Oauth::oauth_admin_token"/>--> </menu> </config> diff --git a/app/code/core/Mage/Page/Block/Html.php b/app/code/core/Mage/Page/Block/Html.php index 169ab5552bb..a81d1ee4f89 100644 --- a/app/code/core/Mage/Page/Block/Html.php +++ b/app/code/core/Mage/Page/Block/Html.php @@ -72,7 +72,7 @@ class Mage_Page_Block_Html extends Mage_Core_Block_Template /** * Print Logo URL (Conf -> Sales -> Invoice and Packing Slip Design) * - * @return string + * @return string */ public function getPrintLogoUrl () { @@ -98,7 +98,7 @@ class Mage_Page_Block_Html extends Mage_Core_Block_Template // buld url if (!empty($logo)) { - $logo = $this->_storeConfig->getConfig('web/unsecure/base_media_url') . $logo; + $logo = $this->_urlBuilder->getBaseUrl(array('_type' => Mage_Core_Model_Store::URL_TYPE_MEDIA)) . $logo; } else { $logo = ''; diff --git a/app/code/core/Mage/Page/Block/Html/Header.php b/app/code/core/Mage/Page/Block/Html/Header.php index a89d872ed6c..79da788a4f6 100644 --- a/app/code/core/Mage/Page/Block/Html/Header.php +++ b/app/code/core/Mage/Page/Block/Html/Header.php @@ -33,63 +33,6 @@ */ class Mage_Page_Block_Html_Header extends Mage_Core_Block_Template { - /** - * @var Mage_Core_Model_Config_Options - */ - protected $_configOptions; - - /** - * @param Mage_Core_Controller_Request_Http $request - * @param Mage_Core_Model_Layout $layout - * @param Mage_Core_Model_Event_Manager $eventManager - * @param Mage_Core_Model_Url $urlBuilder - * @param Mage_Core_Model_Translate $translator - * @param Mage_Core_Model_Cache $cache - * @param Mage_Core_Model_Design_Package $designPackage - * @param Mage_Core_Model_Session $session - * @param Mage_Core_Model_Store_Config $storeConfig - * @param Mage_Core_Controller_Varien_Front $frontController - * @param Mage_Core_Model_Factory_Helper $helperFactory - * @param Magento_Filesystem $filesystem - * @param Mage_Core_Model_Config_Options $configOptions - * @param array $data - * - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - */ - public function __construct( - Mage_Core_Controller_Request_Http $request, - Mage_Core_Model_Layout $layout, - Mage_Core_Model_Event_Manager $eventManager, - Mage_Core_Model_Url $urlBuilder, - Mage_Core_Model_Translate $translator, - Mage_Core_Model_Cache $cache, - Mage_Core_Model_Design_Package $designPackage, - Mage_Core_Model_Session $session, - Mage_Core_Model_Store_Config $storeConfig, - Mage_Core_Controller_Varien_Front $frontController, - Mage_Core_Model_Factory_Helper $helperFactory, - Magento_Filesystem $filesystem, - Mage_Core_Model_Config_Options $configOptions, - array $data = array() - ) { - parent::__construct( - $request, - $layout, - $eventManager, - $urlBuilder, - $translator, - $cache, - $designPackage, - $session, - $storeConfig, - $frontController, - $helperFactory, - $filesystem, - $data - ); - $this->_configOptions = $configOptions; - } - public function _construct() { $this->setTemplate('html/header.phtml'); @@ -157,7 +100,7 @@ class Mage_Page_Block_Html_Header extends Mage_Core_Block_Template $storeLogoPath = $this->_storeConfig->getConfig('design/header/logo_src'); $logoUrl = $this->_urlBuilder->getBaseUrl(array('_type' => Mage_Core_Model_Store::URL_TYPE_MEDIA)) . $folderName . '/' . $storeLogoPath; - $absolutePath = $this->_configOptions->getDir('media') . DIRECTORY_SEPARATOR + $absolutePath = $this->_dirs->getDir(Mage_Core_Model_Dir::MEDIA) . DIRECTORY_SEPARATOR . $folderName . DIRECTORY_SEPARATOR . $storeLogoPath; if (!is_null($storeLogoPath) && $this->_isFile($absolutePath)) { diff --git a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Global.php b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Global.php index 3e7bab145dd..f2ed6c4c2fb 100644 --- a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Global.php +++ b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Global.php @@ -29,7 +29,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Global - extends Mage_Adminhtml_Block_Abstract + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { /** diff --git a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Hint.php b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Hint.php index d028b185ce0..ce0ab92157d 100644 --- a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Hint.php +++ b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Hint.php @@ -30,7 +30,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Hint - extends Mage_Adminhtml_Block_Abstract + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { protected $_template = 'Mage_Paypal::system/config/fieldset/hint.phtml'; diff --git a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Store.php b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Store.php index 78d86906d7e..f2b861e70e3 100644 --- a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Store.php +++ b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Fieldset/Store.php @@ -30,7 +30,7 @@ * @author Magento Core Team <core@magentocommerce.com> */ class Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Store - extends Mage_Adminhtml_Block_Abstract + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { /** diff --git a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Payflowlink/Info.php b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Payflowlink/Info.php index 9655fcfe5dc..4bc68dc0f74 100644 --- a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Payflowlink/Info.php +++ b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/Payflowlink/Info.php @@ -31,8 +31,8 @@ * @package Mage_Paypal * @author Magento Core Team <core@magentocommerce.com> */ - class Mage_Paypal_Block_Adminhtml_System_Config_Payflowlink_Info - extends Mage_Adminhtml_Block_Abstract +class Mage_Paypal_Block_Adminhtml_System_Config_Payflowlink_Info + extends Mage_Core_Block_Template implements Varien_Data_Form_Element_Renderer_Interface { /** diff --git a/app/code/core/Mage/Paypal/Model/Observer.php b/app/code/core/Mage/Paypal/Model/Observer.php index f0dff830307..1ba306ce5d3 100644 --- a/app/code/core/Mage/Paypal/Model/Observer.php +++ b/app/code/core/Mage/Paypal/Model/Observer.php @@ -44,7 +44,7 @@ class Mage_Paypal_Model_Observer $credentials = $reports->getSftpCredentials(true); foreach ($credentials as $config) { try { - $reports->fetchAndSave($config); + $reports->fetchAndSave(Mage_Paypal_Model_Report_Settlement::createConnection($config)); } catch (Exception $e) { Mage::logException($e); } diff --git a/app/code/core/Mage/Paypal/Model/Report/Settlement.php b/app/code/core/Mage/Paypal/Model/Report/Settlement.php index 4a4fba8c499..37d94043d39 100644 --- a/app/code/core/Mage/Paypal/Model/Report/Settlement.php +++ b/app/code/core/Mage/Paypal/Model/Report/Settlement.php @@ -194,22 +194,15 @@ class Mage_Paypal_Model_Report_Settlement extends Mage_Core_Model_Abstract * Goes to specified host/path and fetches reports from there. * Save reports to database. * - * @param array $config SFTP credentials + * @param Varien_Io_Sftp $connection * @return int Number of report rows that were fetched and saved successfully */ - public function fetchAndSave($config) + public function fetchAndSave(Varien_Io_Sftp $connection) { - $connection = new Varien_Io_Sftp(); - $connection->open(array( - 'host' => $config['hostname'], - 'username' => $config['username'], - 'password' => $config['password'] - )); - $connection->cd($config['path']); $fetched = 0; $listing = $this->_filterReportsList($connection->rawls()); foreach ($listing as $filename => $attributes) { - $localCsv = tempnam(Mage::getConfig()->getOptions()->getTmpDir(), 'PayPal_STL'); + $localCsv = tempnam(Mage::getBaseDir(Mage_Core_Model_Dir::TMP), 'PayPal_STL'); if ($connection->read($filename, $localCsv)) { if (!is_writable($localCsv)) { Mage::throwException(Mage::helper('Mage_Paypal_Helper_Data')->__('Cannot create target file for reading reports.')); @@ -248,6 +241,30 @@ class Mage_Paypal_Model_Report_Settlement extends Mage_Core_Model_Abstract return $fetched; } + /** + * Connect to an SFTP server using specified configuration + * + * @param array $config + * @return Varien_Io_Sftp + * @throws InvalidArgumentException + */ + public static function createConnection(array $config) + { + if (!isset($config['hostname']) || !isset($config['username']) + || !isset($config['password']) || !isset($config['path']) + ) { + throw new InvalidArgumentException('Required config elements: hostname, username, password, path'); + } + $connection = new Varien_Io_Sftp(); + $connection->open(array( + 'host' => $config['hostname'], + 'username' => $config['username'], + 'password' => $config['password'] + )); + $connection->cd($config['path']); + return $connection; + } + /** * Parse CSV file and collect report rows * diff --git a/app/code/core/Mage/Paypal/controllers/Adminhtml/Paypal/ReportsController.php b/app/code/core/Mage/Paypal/controllers/Adminhtml/Paypal/ReportsController.php index 781eb544955..188f8eec750 100644 --- a/app/code/core/Mage/Paypal/controllers/Adminhtml/Paypal/ReportsController.php +++ b/app/code/core/Mage/Paypal/controllers/Adminhtml/Paypal/ReportsController.php @@ -88,7 +88,7 @@ class Mage_Paypal_Adminhtml_Paypal_ReportsController extends Mage_Adminhtml_Cont } foreach ($credentials as $config) { try { - $fetched = $reports->fetchAndSave($config); + $fetched = $reports->fetchAndSave(Mage_Paypal_Model_Report_Settlement::createConnection($config)); $this->_getSession()->addSuccess( Mage::helper('Mage_Paypal_Helper_Data')->__("Fetched %s report rows from '%s@%s'.", $fetched, $config['username'], $config['hostname']) ); diff --git a/app/code/core/Mage/Sales/Block/Adminhtml/Billing/Agreement/View/Tab/Info.php b/app/code/core/Mage/Sales/Block/Adminhtml/Billing/Agreement/View/Tab/Info.php index 3088de94da1..bb35772e503 100644 --- a/app/code/core/Mage/Sales/Block/Adminhtml/Billing/Agreement/View/Tab/Info.php +++ b/app/code/core/Mage/Sales/Block/Adminhtml/Billing/Agreement/View/Tab/Info.php @@ -29,7 +29,7 @@ * * @author Magento Core Team <core@magentocommerce.com> */ -class Mage_Sales_Block_Adminhtml_Billing_Agreement_View_Tab_Info extends Mage_Backend_Block_Abstract +class Mage_Sales_Block_Adminhtml_Billing_Agreement_View_Tab_Info extends Mage_Core_Block_Template implements Mage_Backend_Block_Widget_Tab_Interface { protected $_template = 'billing/agreement/view/tab/info.phtml'; diff --git a/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/Edit/Form.php b/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/Edit/Form.php index 5c6bda09b29..9647d2b8a60 100644 --- a/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/Edit/Form.php +++ b/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/Edit/Form.php @@ -28,7 +28,7 @@ * Recurring profile editing form * Can work in scope of product edit form */ -class Mage_Sales_Block_Adminhtml_Recurring_Profile_Edit_Form extends Mage_Adminhtml_Block_Abstract +class Mage_Sales_Block_Adminhtml_Recurring_Profile_Edit_Form extends Mage_Core_Block_Template { /** * Reference to the parent element (optional) diff --git a/app/code/core/Mage/Sales/Model/Api/Resource.php b/app/code/core/Mage/Sales/Model/Api/Resource.php new file mode 100644 index 00000000000..179e32f8352 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Api/Resource.php @@ -0,0 +1,122 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Sale api resource abstract + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Api_Resource extends Mage_Api_Model_Resource_Abstract +{ + /** + * Default ignored attribute codes per entity type + * + * @var array + */ + protected $_ignoredAttributeCodes = array( + 'global' => array('entity_id', 'attribute_set_id', 'entity_type_id') + ); + + /** + * Attributes map array per entity type + * + * @var google + */ + protected $_attributesMap = array( + 'global' => array() + ); + + /** @var Mage_Api_Helper_Data */ + protected $_apiHelper; + + /** + * Initialize dependencies. + * + * @param Mage_Api_Helper_Data $apiHelper + */ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + $this->_apiHelper = $apiHelper; + } + + /** + * Update attributes for entity + * + * @param array $data + * @param Mage_Core_Model_Abstract $object + * @param array $attributes + * @return Mage_Sales_Model_Api_Resource + */ + protected function _updateAttributes($data, $object, $type, array $attributes = null) + { + + foreach ($data as $attribute=>$value) { + if ($this->_apiHelper->isAttributeAllowed($attribute, $type, $this->_ignoredAttributeCodes, $attributes)) { + $object->setData($attribute, $value); + } + } + + return $this; + } + + /** + * Retrieve entity attributes values + * + * @param Mage_Core_Model_Abstract $object + * @param array $attributes + * @return Mage_Sales_Model_Api_Resource + */ + protected function _getAttributes($object, $type, array $attributes = null) + { + $result = array(); + + if (!is_object($object)) { + return $result; + } + + foreach ($object->getData() as $attribute=>$value) { + if ($this->_apiHelper->isAttributeAllowed($attribute, $type, $this->_ignoredAttributeCodes, $attributes)) { + $result[$attribute] = $value; + } + } + + if (isset($this->_attributesMap['global'])) { + foreach ($this->_attributesMap['global'] as $alias=>$attributeCode) { + $result[$alias] = $object->getData($attributeCode); + } + } + + if (isset($this->_attributesMap[$type])) { + foreach ($this->_attributesMap[$type] as $alias=>$attributeCode) { + $result[$alias] = $object->getData($attributeCode); + } + } + + return $result; + } +} // Class Mage_Sales_Model_Api_Resource End diff --git a/app/code/core/Mage/Sales/Model/Order.php b/app/code/core/Mage/Sales/Model/Order.php index 6867c42c4c5..a06cf603819 100644 --- a/app/code/core/Mage/Sales/Model/Order.php +++ b/app/code/core/Mage/Sales/Model/Order.php @@ -1833,7 +1833,7 @@ class Mage_Sales_Model_Order extends Mage_Sales_Model_Abstract /** * Retrieve order invoices collection * - * @return unknown + * @return Mage_Sales_Model_Resource_Order_Invoice_Collection */ public function getInvoiceCollection() { @@ -1850,10 +1850,10 @@ class Mage_Sales_Model_Order extends Mage_Sales_Model_Abstract return $this->_invoices; } - /** + /** * Retrieve order shipments collection * - * @return unknown + * @return Mage_Sales_Model_Resource_Order_Shipment_Collection|bool */ public function getShipmentsCollection() { @@ -1872,7 +1872,7 @@ class Mage_Sales_Model_Order extends Mage_Sales_Model_Abstract /** * Retrieve order creditmemos collection * - * @return unknown + * @return Mage_Sales_Model_Resource_Order_Creditmemo_Collection|bool */ public function getCreditmemosCollection() { @@ -1891,7 +1891,7 @@ class Mage_Sales_Model_Order extends Mage_Sales_Model_Abstract /** * Retrieve order tracking numbers collection * - * @return unknown + * @return Mage_Sales_Model_Resource_Order_Shipment_Track_Collection */ public function getTracksCollection() { diff --git a/app/code/core/Mage/Sales/Model/Order/Api.php b/app/code/core/Mage/Sales/Model/Order/Api.php new file mode 100644 index 00000000000..318a0f94ce1 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Api.php @@ -0,0 +1,267 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Order API + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Api extends Mage_Sales_Model_Api_Resource +{ + /** + * Initialize attributes map + */ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + parent::__construct($apiHelper); + $this->_attributesMap = array( + 'order' => array('order_id' => 'entity_id'), + 'order_address' => array('address_id' => 'entity_id'), + 'order_payment' => array('payment_id' => 'entity_id') + ); + } + + /** + * Initialize basic order model + * + * @param mixed $orderIncrementId + * @return Mage_Sales_Model_Order + */ + protected function _initOrder($orderIncrementId) + { + $order = Mage::getModel('Mage_Sales_Model_Order'); + + /* @var $order Mage_Sales_Model_Order */ + + $order->loadByIncrementId($orderIncrementId); + + if (!$order->getId()) { + $this->_fault('not_exists'); + } + + return $order; + } + + /** + * Retrieve list of orders. Filtration could be applied + * + * @param null|object|array $filters + * @return array + */ + public function items($filters = null) + { + $orders = array(); + + //TODO: add full name logic + $billingAliasName = 'billing_o_a'; + $shippingAliasName = 'shipping_o_a'; + + /** @var $orderCollection Mage_Sales_Model_Resource_Order_Collection */ + $orderCollection = Mage::getModel('Mage_Sales_Model_Order')->getCollection(); + $billingFirstnameField = "$billingAliasName.firstname"; + $billingLastnameField = "$billingAliasName.lastname"; + $shippingFirstnameField = "$shippingAliasName.firstname"; + $shippingLastnameField = "$shippingAliasName.lastname"; + $billingNameExpr = "CONCAT({{billing_firstname}}, CONCAT(' ', {{billing_lastname}}))"; + $shippingNameExpr = "CONCAT({{shipping_firstname}}, CONCAT(' ', {{shipping_lastname}}))"; + $orderCollection->addAttributeToSelect('*') + ->addAddressFields() + ->addExpressionFieldToSelect('billing_firstname', "{{billing_firstname}}", + array('billing_firstname' => $billingFirstnameField)) + ->addExpressionFieldToSelect('billing_lastname', "{{billing_lastname}}", + array('billing_lastname' => $billingLastnameField)) + ->addExpressionFieldToSelect('shipping_firstname', "{{shipping_firstname}}", + array('shipping_firstname' => $shippingFirstnameField)) + ->addExpressionFieldToSelect('shipping_lastname', "{{shipping_lastname}}", + array('shipping_lastname' => $shippingLastnameField)) + ->addExpressionFieldToSelect('billing_name', $billingNameExpr, + array('billing_firstname' => $billingFirstnameField, 'billing_lastname' => $billingLastnameField)) + ->addExpressionFieldToSelect('shipping_name', $shippingNameExpr, + array('shipping_firstname' => $shippingFirstnameField, 'shipping_lastname' => $shippingLastnameField) + ); + + /** @var $apiHelper Mage_Api_Helper_Data */ + $apiHelper = Mage::helper('Mage_Api_Helper_Data'); + $filters = $apiHelper->parseFilters($filters, $this->_attributesMap['order']); + try { + foreach ($filters as $field => $value) { + $orderCollection->addFieldToFilter($field, $value); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('filters_invalid', $e->getMessage()); + } + foreach ($orderCollection as $order) { + $orders[] = $this->_getAttributes($order, 'order'); + } + return $orders; + } + + /** + * Retrieve full order information + * + * @param string $orderIncrementId + * @return array + */ + public function info($orderIncrementId) + { + $order = $this->_initOrder($orderIncrementId); + + if ($order->getGiftMessageId() > 0) { + $order->setGiftMessage( + Mage::getSingleton('Mage_GiftMessage_Model_Message')->load($order->getGiftMessageId())->getMessage() + ); + } + + $result = $this->_getAttributes($order, 'order'); + + $result['shipping_address'] = $this->_getAttributes($order->getShippingAddress(), 'order_address'); + $result['billing_address'] = $this->_getAttributes($order->getBillingAddress(), 'order_address'); + $result['items'] = array(); + + foreach ($order->getAllItems() as $item) { + if ($item->getGiftMessageId() > 0) { + $item->setGiftMessage( + Mage::getSingleton('Mage_GiftMessage_Model_Message')->load($item->getGiftMessageId())->getMessage() + ); + } + + $result['items'][] = $this->_getAttributes($item, 'order_item'); + } + + $result['payment'] = $this->_getAttributes($order->getPayment(), 'order_payment'); + + $result['status_history'] = array(); + + foreach ($order->getAllStatusHistory() as $history) { + $result['status_history'][] = $this->_getAttributes($history, 'order_status_history'); + } + + return $result; + } + + /** + * Change order status and optionally log status change with comment. + * + * @param string $orderIncrementId + * @param string $status New order status + * @param string $comment Comment to order status change + * @param boolean $notify Should customer be notified about status change + * @return boolean Is method executed successfully + */ + public function addComment($orderIncrementId, $status, $comment = null, $notify = false) + { + $order = $this->_initOrder($orderIncrementId); + + $order->addStatusToHistory($status, $comment, $notify); + + + try { + if ($notify && $comment) { + $oldArea = Mage::getDesign()->getArea(); + Mage::getDesign()->setArea('frontend'); + } + + $order->save(); + $order->sendOrderUpdateEmail($notify, $comment); + if ($notify && $comment) { + Mage::getDesign()->setArea($oldArea); + } + + } catch (Mage_Core_Exception $e) { + $this->_fault('status_not_changed', $e->getMessage()); + } + + return true; + } + + /** + * Hold order + * + * @param string $orderIncrementId + * @return boolean + */ + public function hold($orderIncrementId) + { + $order = $this->_initOrder($orderIncrementId); + + try { + $order->hold(); + $order->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('status_not_changed', $e->getMessage()); + } + + return true; + } + + /** + * Unhold order + * + * @param string $orderIncrementId + * @return boolean + */ + public function unhold($orderIncrementId) + { + $order = $this->_initOrder($orderIncrementId); + + try { + $order->unhold(); + $order->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('status_not_changed', $e->getMessage()); + } + + return true; + } + + /** + * Cancel order + * + * @param string $orderIncrementId + * @return boolean + */ + public function cancel($orderIncrementId) + { + $order = $this->_initOrder($orderIncrementId); + + if (Mage_Sales_Model_Order::STATE_CANCELED == $order->getState()) { + $this->_fault('status_not_changed'); + } + try { + $order->cancel(); + $order->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('status_not_changed', $e->getMessage()); + } + if (Mage_Sales_Model_Order::STATE_CANCELED != $order->getState()) { + $this->_fault('status_not_changed'); + } + return true; + } + +} // Class Mage_Sales_Model_Order_Api End diff --git a/app/code/core/Mage/Sales/Model/Order/Api/V2.php b/app/code/core/Mage/Sales/Model/Order/Api/V2.php new file mode 100644 index 00000000000..d3d84294cb4 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Api/V2.php @@ -0,0 +1,36 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Order API V2 + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Api_V2 extends Mage_Sales_Model_Order_Api +{ +} diff --git a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Api.php b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Api.php new file mode 100644 index 00000000000..f79941ae388 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Api.php @@ -0,0 +1,258 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Credit memo API + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Creditmemo_Api extends Mage_Sales_Model_Api_Resource +{ + + /** + * Initialize attributes mapping + */ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + parent::__construct($apiHelper); + $this->_attributesMap = array( + 'creditmemo' => array('creditmemo_id' => 'entity_id'), + 'creditmemo_item' => array('item_id' => 'entity_id'), + 'creditmemo_comment' => array('comment_id' => 'entity_id') + ); + } + + /** + * Retrieve credit memos list. Filtration could be applied + * + * @param null|object|array $filters + * @return array + */ + public function items($filters = null) + { + $creditmemos = array(); + /** @var $apiHelper Mage_Api_Helper_Data */ + $apiHelper = Mage::helper('Mage_Api_Helper_Data'); + $filters = $apiHelper->parseFilters($filters, $this->_attributesMap['creditmemo']); + /** @var $creditmemoModel Mage_Sales_Model_Order_Creditmemo */ + $creditmemoModel = Mage::getModel('Mage_Sales_Model_Order_Creditmemo'); + try { + $creditMemoCollection = $creditmemoModel->getFilteredCollectionItems($filters); + foreach ($creditMemoCollection as $creditmemo) { + $creditmemos[] = $this->_getAttributes($creditmemo, 'creditmemo'); + } + } catch (Exception $e) { + $this->_fault('invalid_filter', $e->getMessage()); + } + return $creditmemos; + } + + /** + * Retrieve credit memo information + * + * @param string $creditmemoIncrementId + * @return array + */ + public function info($creditmemoIncrementId) + { + $creditmemo = $this->_getCreditmemo($creditmemoIncrementId); + // get credit memo attributes with entity_id' => 'creditmemo_id' mapping + $result = $this->_getAttributes($creditmemo, 'creditmemo'); + $result['order_increment_id'] = $creditmemo->getOrder()->load($creditmemo->getOrderId())->getIncrementId(); + // items refunded + $result['items'] = array(); + foreach ($creditmemo->getAllItems() as $item) { + $result['items'][] = $this->_getAttributes($item, 'creditmemo_item'); + } + // credit memo comments + $result['comments'] = array(); + foreach ($creditmemo->getCommentsCollection() as $comment) { + $result['comments'][] = $this->_getAttributes($comment, 'creditmemo_comment'); + } + + return $result; + } + + /** + * Create new credit memo for order + * + * @param string $orderIncrementId + * @param array $creditmemoData array('qtys' => array('sku1' => qty1, ... , 'skuN' => qtyN), + * 'shipping_amount' => value, 'adjustment_positive' => value, 'adjustment_negative' => value) + * @param string|null $comment + * @param bool $notifyCustomer + * @param bool $includeComment + * @param string $refundToStoreCreditAmount + * @return string $creditmemoIncrementId + */ + public function create($orderIncrementId, $creditmemoData = null, $comment = null, $notifyCustomer = false, + $includeComment = false, $refundToStoreCreditAmount = null) + { + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::getModel('Mage_Sales_Model_Order')->load($orderIncrementId, 'increment_id'); + if (!$order->getId()) { + $this->_fault('order_not_exists'); + } + if (!$order->canCreditmemo()) { + $this->_fault('cannot_create_creditmemo'); + } + $creditmemoData = $this->_prepareCreateData($creditmemoData); + + /** @var $service Mage_Sales_Model_Service_Order */ + $service = Mage::getModel('Mage_Sales_Model_Service_Order', $order); + /** @var $creditmemo Mage_Sales_Model_Order_Creditmemo */ + $creditmemo = $service->prepareCreditmemo($creditmemoData); + + // refund to Store Credit + if ($refundToStoreCreditAmount) { + // check if refund to Store Credit is available + if ($order->getCustomerIsGuest()) { + $this->_fault('cannot_refund_to_storecredit'); + } + $refundToStoreCreditAmount = max( + 0, + min($creditmemo->getBaseCustomerBalanceReturnMax(), $refundToStoreCreditAmount) + ); + if ($refundToStoreCreditAmount) { + $refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice($refundToStoreCreditAmount); + $creditmemo->setBaseCustomerBalanceTotalRefunded($refundToStoreCreditAmount); + $refundToStoreCreditAmount = $creditmemo->getStore()->roundPrice( + $refundToStoreCreditAmount*$order->getBaseToOrderRate() + ); + // this field can be used by customer balance observer + $creditmemo->setBsCustomerBalTotalRefunded($refundToStoreCreditAmount); + // setting flag to make actual refund to customer balance after credit memo save + $creditmemo->setCustomerBalanceRefundFlag(true); + } + } + $creditmemo->setPaymentRefundDisallowed(true)->register(); + // add comment to creditmemo + if (!empty($comment)) { + $creditmemo->addComment($comment, $notifyCustomer); + } + try { + Mage::getModel('Mage_Core_Model_Resource_Transaction') + ->addObject($creditmemo) + ->addObject($order) + ->save(); + // send email notification + $creditmemo->sendEmail($notifyCustomer, ($includeComment ? $comment : '')); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + return $creditmemo->getIncrementId(); + } + + /** + * Add comment to credit memo + * + * @param string $creditmemoIncrementId + * @param string $comment + * @param boolean $notifyCustomer + * @param boolean $includeComment + * @return boolean + */ + public function addComment($creditmemoIncrementId, $comment, $notifyCustomer = false, $includeComment = false) + { + $creditmemo = $this->_getCreditmemo($creditmemoIncrementId); + try { + $creditmemo->addComment($comment, $notifyCustomer)->save(); + $creditmemo->sendUpdateEmail($notifyCustomer, ($includeComment ? $comment : '')); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Cancel credit memo + * + * @param string $creditmemoIncrementId + * @return boolean + */ + public function cancel($creditmemoIncrementId) + { + $creditmemo = $this->_getCreditmemo($creditmemoIncrementId); + + if (!$creditmemo->canCancel()) { + $this->_fault('status_not_changed', Mage::helper('Mage_Sales_Helper_Data')->__('Credit memo cannot be canceled.')); + } + try { + $creditmemo->cancel()->save(); + } catch (Exception $e) { + $this->_fault('status_not_changed', Mage::helper('Mage_Sales_Helper_Data')->__('Credit memo canceling problem.')); + } + + return true; + } + + /** + * Hook method, could be replaced in derived classes + * + * @param array $data + * @return array + */ + protected function _prepareCreateData($data) + { + $data = isset($data) ? $data : array(); + + if (isset($data['qtys']) && count($data['qtys'])) { + $qtysArray = array(); + foreach ($data['qtys'] as $qKey => $qVal) { + // Save backward compatibility + if (is_array($qVal)) { + if (isset($qVal['order_item_id']) && isset($qVal['qty'])) { + $qtysArray[$qVal['order_item_id']] = $qVal['qty']; + } + } else { + $qtysArray[$qKey] = $qVal; + } + } + $data['qtys'] = $qtysArray; + } + return $data; + } + + /** + * Load CreditMemo by IncrementId + * + * @param mixed $incrementId + * @return Mage_Core_Model_Abstract|Mage_Sales_Model_Order_Creditmemo + */ + protected function _getCreditmemo($incrementId) + { + /** @var $creditmemo Mage_Sales_Model_Order_Creditmemo */ + $creditmemo = Mage::getModel('Mage_Sales_Model_Order_Creditmemo')->load($incrementId, 'increment_id'); + if (!$creditmemo->getId()) { + $this->_fault('not_exists'); + } + return $creditmemo; + } + +} diff --git a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Api/V2.php b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Api/V2.php new file mode 100644 index 00000000000..c8fc4fc6df3 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Api/V2.php @@ -0,0 +1,58 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Credit memo API + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Creditmemo_Api_V2 extends Mage_Sales_Model_Order_Creditmemo_Api +{ + /** + * Prepare data + * + * @param null|object $data + * @return array + */ + protected function _prepareCreateData($data) + { + // convert data object to array, if it's null turn it into empty array + $data = (isset($data) and is_object($data)) ? get_object_vars($data) : array(); + // convert qtys object to array + if (isset($data['qtys']) && count($data['qtys'])) { + $qtysArray = array(); + foreach ($data['qtys'] as &$item) { + if (isset($item->order_item_id) && isset($item->qty)) { + $qtysArray[$item->order_item_id] = $item->qty; + } + } + $data['qtys'] = $qtysArray; + } + return $data; + } +} diff --git a/app/code/core/Mage/Sales/Model/Order/Invoice/Api.php b/app/code/core/Mage/Sales/Model/Order/Invoice/Api.php new file mode 100644 index 00000000000..8f2a97d5722 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Invoice/Api.php @@ -0,0 +1,326 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Invoice API + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Invoice_Api extends Mage_Sales_Model_Api_Resource +{ + /** + * Initialize attributes map + */ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + parent::__construct($apiHelper); + $this->_attributesMap = array( + 'invoice' => array('invoice_id' => 'entity_id'), + 'invoice_item' => array('item_id' => 'entity_id'), + 'invoice_comment' => array('comment_id' => 'entity_id') + ); + } + + /** + * Retrive invoices list. Filtration could be applied + * + * @param null|object|array $filters + * @return array + */ + public function items($filters = null) + { + $invoices = array(); + /** @var $invoiceCollection Mage_Sales_Model_Resource_Order_Invoice_Collection */ + $invoiceCollection = Mage::getResourceModel('Mage_Sales_Model_Resource_Order_Invoice_Collection'); + $invoiceCollection->addAttributeToSelect('entity_id') + ->addAttributeToSelect('order_id') + ->addAttributeToSelect('increment_id') + ->addAttributeToSelect('created_at') + ->addAttributeToSelect('state') + ->addAttributeToSelect('grand_total') + ->addAttributeToSelect('order_currency_code'); + + /** @var $apiHelper Mage_Api_Helper_Data */ + $apiHelper = Mage::helper('Mage_Api_Helper_Data'); + try { + $filters = $apiHelper->parseFilters($filters, $this->_attributesMap['invoice']); + foreach ($filters as $field => $value) { + $invoiceCollection->addFieldToFilter($field, $value); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('filters_invalid', $e->getMessage()); + } + foreach ($invoiceCollection as $invoice) { + $invoices[] = $this->_getAttributes($invoice, 'invoice'); + } + return $invoices; + } + + /** + * Retrieve invoice information + * + * @param string $invoiceIncrementId + * @return array + */ + public function info($invoiceIncrementId) + { + $invoice = Mage::getModel('Mage_Sales_Model_Order_Invoice')->loadByIncrementId($invoiceIncrementId); + + /* @var Mage_Sales_Model_Order_Invoice $invoice */ + + if (!$invoice->getId()) { + $this->_fault('not_exists'); + } + + $result = $this->_getAttributes($invoice, 'invoice'); + $result['order_increment_id'] = $invoice->getOrderIncrementId(); + + $result['items'] = array(); + foreach ($invoice->getAllItems() as $item) { + $result['items'][] = $this->_getAttributes($item, 'invoice_item'); + } + + $result['comments'] = array(); + foreach ($invoice->getCommentsCollection() as $comment) { + $result['comments'][] = $this->_getAttributes($comment, 'invoice_comment'); + } + + return $result; + } + + /** + * Create new invoice for order + * + * @param string $orderIncrementId + * @param array $itemsQty + * @param string $comment + * @param boolean $email + * @param boolean $includeComment + * @return string + */ + public function create($orderIncrementId, $itemsQty, $comment = null, $email = false, $includeComment = false) + { + $order = Mage::getModel('Mage_Sales_Model_Order')->loadByIncrementId($orderIncrementId); + + /* @var $order Mage_Sales_Model_Order */ + /** + * Check order existing + */ + if (!$order->getId()) { + $this->_fault('order_not_exists'); + } + + /** + * Check invoice create availability + */ + if (!$order->canInvoice()) { + $this->_fault('data_invalid', Mage::helper('Mage_Sales_Helper_Data')->__('Cannot do invoice for order.')); + } + + $invoice = $order->prepareInvoice($itemsQty); + + $invoice->register(); + + if ($comment !== null) { + $invoice->addComment($comment, $email); + } + + if ($email) { + $invoice->setEmailSent(true); + } + + $invoice->getOrder()->setIsInProcess(true); + + try { + $transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction') + ->addObject($invoice) + ->addObject($invoice->getOrder()) + ->save(); + + $invoice->sendEmail($email, ($includeComment ? $comment : '')); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $invoice->getIncrementId(); + } + + /** + * Add comment to invoice + * + * @param string $invoiceIncrementId + * @param string $comment + * @param boolean $email + * @param boolean $includeComment + * @return boolean + */ + public function addComment($invoiceIncrementId, $comment, $email = false, $includeComment = false) + { + $invoice = Mage::getModel('Mage_Sales_Model_Order_Invoice')->loadByIncrementId($invoiceIncrementId); + + /* @var $invoice Mage_Sales_Model_Order_Invoice */ + + if (!$invoice->getId()) { + $this->_fault('not_exists'); + } + + + try { + $invoice->addComment($comment, $email); + $invoice->sendUpdateEmail($email, ($includeComment ? $comment : '')); + $invoice->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Capture invoice + * + * @param string $invoiceIncrementId + * @return boolean + */ + public function capture($invoiceIncrementId) + { + $invoice = Mage::getModel('Mage_Sales_Model_Order_Invoice')->loadByIncrementId($invoiceIncrementId); + + /* @var $invoice Mage_Sales_Model_Order_Invoice */ + + if (!$invoice->getId()) { + $this->_fault('not_exists'); + } + + if (!$invoice->canCapture()) { + $this->_fault( + 'status_not_changed', + Mage::helper('Mage_Sales_Helper_Data')->__('Invoice cannot be captured.') + ); + } + + try { + $invoice->capture(); + $invoice->getOrder()->setIsInProcess(true); + $transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction') + ->addObject($invoice) + ->addObject($invoice->getOrder()) + ->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('status_not_changed', $e->getMessage()); + } catch (Exception $e) { + $this->_fault( + 'status_not_changed', + Mage::helper('Mage_Sales_Helper_Data')->__('Invoice capturing problem.') + ); + } + + return true; + } + + /** + * Void invoice + * + * @param unknown_type $invoiceIncrementId + * @return unknown + */ + public function void($invoiceIncrementId) + { + $invoice = Mage::getModel('Mage_Sales_Model_Order_Invoice')->loadByIncrementId($invoiceIncrementId); + + /* @var $invoice Mage_Sales_Model_Order_Invoice */ + + if (!$invoice->getId()) { + $this->_fault('not_exists'); + } + + if (!$invoice->canVoid()) { + $this->_fault( + 'status_not_changed', + Mage::helper('Mage_Sales_Helper_Data')->__('Invoice cannot be voided.') + ); + } + + try { + $invoice->void(); + $invoice->getOrder()->setIsInProcess(true); + $transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction') + ->addObject($invoice) + ->addObject($invoice->getOrder()) + ->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('status_not_changed', $e->getMessage()); + } catch (Exception $e) { + $this->_fault('status_not_changed', Mage::helper('Mage_Sales_Helper_Data')->__('Invoice void problem')); + } + + return true; + } + + /** + * Cancel invoice + * + * @param string $invoiceIncrementId + * @return boolean + */ + public function cancel($invoiceIncrementId) + { + $invoice = Mage::getModel('Mage_Sales_Model_Order_Invoice')->loadByIncrementId($invoiceIncrementId); + + /* @var $invoice Mage_Sales_Model_Order_Invoice */ + + if (!$invoice->getId()) { + $this->_fault('not_exists'); + } + + if (!$invoice->canCancel()) { + $this->_fault( + 'status_not_changed', + Mage::helper('Mage_Sales_Helper_Data')->__('Invoice cannot be canceled.') + ); + } + + try { + $invoice->cancel(); + $invoice->getOrder()->setIsInProcess(true); + $transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction') + ->addObject($invoice) + ->addObject($invoice->getOrder()) + ->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('status_not_changed', $e->getMessage()); + } catch (Exception $e) { + $this->_fault( + 'status_not_changed', + Mage::helper('Mage_Sales_Helper_Data')->__('Invoice canceling problem.') + ); + } + + return true; + } +} diff --git a/app/code/core/Mage/Sales/Model/Order/Invoice/Api/V2.php b/app/code/core/Mage/Sales/Model/Order/Invoice/Api/V2.php new file mode 100644 index 00000000000..3694674b661 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Invoice/Api/V2.php @@ -0,0 +1,106 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Invoice API V2 + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Invoice_Api_V2 extends Mage_Sales_Model_Order_Invoice_Api +{ + /** + * Create new invoice for order + * + * @param string $orderIncrementId + * @param array $itemsQty + * @param string $comment + * @param bool $email + * @param bool $includeComment + * @return string + */ + public function create($orderIncrementId, $itemsQty, $comment = null, $email = false, $includeComment = false) + { + $order = Mage::getModel('Mage_Sales_Model_Order')->loadByIncrementId($orderIncrementId); + $itemsQty = $this->_prepareItemQtyData($itemsQty); + /* @var $order Mage_Sales_Model_Order */ + /** + * Check order existing + */ + if (!$order->getId()) { + $this->_fault('order_not_exists'); + } + + /** + * Check invoice create availability + */ + if (!$order->canInvoice()) { + $this->_fault('data_invalid', Mage::helper('Mage_Sales_Helper_Data')->__('Cannot do invoice for order.')); + } + + $invoice = $order->prepareInvoice($itemsQty); + + $invoice->register(); + + if ($comment !== null) { + $invoice->addComment($comment, $email); + } + + if ($email) { + $invoice->setEmailSent(true); + } + + $invoice->getOrder()->setIsInProcess(true); + + try { + Mage::getModel('Mage_Core_Model_Resource_Transaction')->addObject($invoice)->addObject($invoice->getOrder()) + ->save(); + $invoice->sendEmail($email, ($includeComment ? $comment : '')); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $invoice->getIncrementId(); + } + + /** + * Prepare items quantity data + * + * @param array $data + * @return array + */ + protected function _prepareItemQtyData($data) + { + $quantity = array(); + foreach ($data as $item) { + if (isset($item->order_item_id) && isset($item->qty)) { + $quantity[$item->order_item_id] = $item->qty; + } + } + return $quantity; + } +} diff --git a/app/code/core/Mage/Sales/Model/Order/Shipment.php b/app/code/core/Mage/Sales/Model/Order/Shipment.php index a7a0aaa8d10..46e8b5bbb8f 100644 --- a/app/code/core/Mage/Sales/Model/Order/Shipment.php +++ b/app/code/core/Mage/Sales/Model/Order/Shipment.php @@ -259,6 +259,11 @@ class Mage_Sales_Model_Order_Shipment extends Mage_Sales_Model_Abstract } + /** + * Retrieve tracks collection. + * + * @return Mage_Sales_Model_Resource_Order_Shipment_Track_Collection + */ public function getTracksCollection() { if (empty($this->_tracks)) { @@ -341,6 +346,12 @@ class Mage_Sales_Model_Order_Shipment extends Mage_Sales_Model_Abstract return $this; } + /** + * Retrieve comments collection. + * + * @param bool $reload + * @return Mage_Sales_Model_Resource_Order_Shipment_Comment_Collection + */ public function getCommentsCollection($reload=false) { if (is_null($this->_comments) || $reload) { diff --git a/app/code/core/Mage/Sales/Model/Order/Shipment/Api.php b/app/code/core/Mage/Sales/Model/Order/Shipment/Api.php new file mode 100644 index 00000000000..a7598a7de65 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Shipment/Api.php @@ -0,0 +1,352 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Sales order shippment API + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Shipment_Api extends Mage_Sales_Model_Api_Resource +{ + public function __construct(Mage_Api_Helper_Data $apiHelper) + { + parent::__construct($apiHelper); + $this->_attributesMap['shipment'] = array('shipment_id' => 'entity_id'); + + $this->_attributesMap['shipment_item'] = array('item_id' => 'entity_id'); + + $this->_attributesMap['shipment_comment'] = array('comment_id' => 'entity_id'); + + $this->_attributesMap['shipment_track'] = array('track_id' => 'entity_id'); + } + + /** + * Retrieve shipments by filters + * + * @param null|object|array $filters + * @return array + */ + public function items($filters = null) + { + $shipments = array(); + //TODO: add full name logic + $shipmentCollection = Mage::getResourceModel('Mage_Sales_Model_Resource_Order_Shipment_Collection') + ->addAttributeToSelect('increment_id') + ->addAttributeToSelect('created_at') + ->addAttributeToSelect('total_qty') + ->addAttributeToSelect('entity_id') + ->joinAttribute('shipping_firstname', 'order_address/firstname', 'shipping_address_id', null, 'left') + ->joinAttribute('shipping_lastname', 'order_address/lastname', 'shipping_address_id', null, 'left') + ->joinAttribute('order_increment_id', 'order/increment_id', 'order_id', null, 'left') + ->joinAttribute('order_created_at', 'order/created_at', 'order_id', null, 'left'); + + /** @var $apiHelper Mage_Api_Helper_Data */ + $apiHelper = Mage::helper('Mage_Api_Helper_Data'); + try { + $filters = $apiHelper->parseFilters($filters, $this->_attributesMap['shipment']); + foreach ($filters as $field => $value) { + $shipmentCollection->addFieldToFilter($field, $value); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('filters_invalid', $e->getMessage()); + } + foreach ($shipmentCollection as $shipment) { + $shipments[] = $this->_getAttributes($shipment, 'shipment'); + } + + return $shipments; + } + + /** + * Retrieve shipment information + * + * @param string $shipmentIncrementId + * @return array + */ + public function info($shipmentIncrementId) + { + $shipment = Mage::getModel('Mage_Sales_Model_Order_Shipment')->loadByIncrementId($shipmentIncrementId); + + /* @var $shipment Mage_Sales_Model_Order_Shipment */ + + if (!$shipment->getId()) { + $this->_fault('not_exists'); + } + + $result = $this->_getAttributes($shipment, 'shipment'); + + $result['items'] = array(); + foreach ($shipment->getAllItems() as $item) { + $result['items'][] = $this->_getAttributes($item, 'shipment_item'); + } + + $result['tracks'] = array(); + foreach ($shipment->getAllTracks() as $track) { + $result['tracks'][] = $this->_getAttributes($track, 'shipment_track'); + } + + $result['comments'] = array(); + foreach ($shipment->getCommentsCollection() as $comment) { + $result['comments'][] = $this->_getAttributes($comment, 'shipment_comment'); + } + + return $result; + } + + /** + * Create new shipment for order + * + * @param string $orderIncrementId + * @param array $itemsQty + * @param string $comment + * @param booleam $email + * @param boolean $includeComment + * @return string + */ + public function create($orderIncrementId, $itemsQty = array(), $comment = null, $email = false, + $includeComment = false + ) { + $order = Mage::getModel('Mage_Sales_Model_Order')->loadByIncrementId($orderIncrementId); + + /** + * Check order existing + */ + if (!$order->getId()) { + $this->_fault('order_not_exists'); + } + + /** + * Check shipment create availability + */ + if (!$order->canShip()) { + $this->_fault('data_invalid', Mage::helper('Mage_Sales_Helper_Data')->__('Cannot do shipment for order.')); + } + + /* @var $shipment Mage_Sales_Model_Order_Shipment */ + $shipment = $order->prepareShipment($itemsQty); + if ($shipment) { + $shipment->register(); + $shipment->addComment($comment, $email && $includeComment); + if ($email) { + $shipment->setEmailSent(true); + } + $shipment->getOrder()->setIsInProcess(true); + try { + $transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction') + ->addObject($shipment) + ->addObject($shipment->getOrder()) + ->save(); + $shipment->sendEmail($email, ($includeComment ? $comment : '')); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + return $shipment->getIncrementId(); + } + return null; + } + + /** + * Add tracking number to order + * + * @param string $shipmentIncrementId + * @param string $carrier + * @param string $title + * @param string $trackNumber + * @return int + */ + public function addTrack($shipmentIncrementId, $carrier, $title, $trackNumber) + { + $shipment = Mage::getModel('Mage_Sales_Model_Order_Shipment')->loadByIncrementId($shipmentIncrementId); + + /* @var $shipment Mage_Sales_Model_Order_Shipment */ + + if (!$shipment->getId()) { + $this->_fault('not_exists'); + } + + $carriers = $this->_getCarriers($shipment); + + if (!isset($carriers[$carrier])) { + $this->_fault('data_invalid', Mage::helper('Mage_Sales_Helper_Data')->__('Invalid carrier specified.')); + } + + $track = Mage::getModel('Mage_Sales_Model_Order_Shipment_Track') + ->setNumber($trackNumber) + ->setCarrierCode($carrier) + ->setTitle($title); + + $shipment->addTrack($track); + + try { + $shipment->save(); + $track->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return $track->getId(); + } + + /** + * Remove tracking number + * + * @param string $shipmentIncrementId + * @param int $trackId + * @return boolean + */ + public function removeTrack($shipmentIncrementId, $trackId) + { + $shipment = Mage::getModel('Mage_Sales_Model_Order_Shipment')->loadByIncrementId($shipmentIncrementId); + + /* @var $shipment Mage_Sales_Model_Order_Shipment */ + + if (!$shipment->getId()) { + $this->_fault('not_exists'); + } + + if(!$track = $shipment->getTrackById($trackId)) { + $this->_fault('track_not_exists'); + } + + try { + $track->delete(); + } catch (Mage_Core_Exception $e) { + $this->_fault('track_not_deleted', $e->getMessage()); + } + + return true; + } + + /** + * Send email with shipment data to customer + * + * @param string $shipmentIncrementId + * @param string $comment + * @return bool + */ + public function sendInfo($shipmentIncrementId, $comment = '') + { + /* @var $shipment Mage_Sales_Model_Order_Shipment */ + $shipment = Mage::getModel('Mage_Sales_Model_Order_Shipment')->loadByIncrementId($shipmentIncrementId); + + if (!$shipment->getId()) { + $this->_fault('not_exists'); + } + + try { + $shipment->sendEmail(true, $comment) + ->setEmailSent(true) + ->save(); + $historyItem = Mage::getResourceModel('Mage_Sales_Model_Resource_Order_Status_History_Collection') + ->getUnnotifiedForInstance($shipment, Mage_Sales_Model_Order_Shipment::HISTORY_ENTITY_NAME); + if ($historyItem) { + $historyItem->setIsCustomerNotified(1); + $historyItem->save(); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Add comment to shipment + * + * @param string $shipmentIncrementId + * @param string $comment + * @param boolean $email + * @param boolean $includeInEmail + * @return boolean + */ + public function addComment($shipmentIncrementId, $comment, $email = false, $includeInEmail = false) + { + $shipment = Mage::getModel('Mage_Sales_Model_Order_Shipment')->loadByIncrementId($shipmentIncrementId); + + /* @var $shipment Mage_Sales_Model_Order_Shipment */ + + if (!$shipment->getId()) { + $this->_fault('not_exists'); + } + + + try { + $shipment->addComment($comment, $email); + $shipment->sendUpdateEmail($email, ($includeInEmail ? $comment : '')); + $shipment->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + + return true; + } + + /** + * Retrieve allowed shipping carriers for specified order + * + * @param string $orderIncrementId + * @return array + */ + public function getCarriers($orderIncrementId) + { + $order = Mage::getModel('Mage_Sales_Model_Order')->loadByIncrementId($orderIncrementId); + + /** + * Check order existing + */ + if (!$order->getId()) { + $this->_fault('order_not_exists'); + } + + return $this->_getCarriers($order); + } + + /** + * Retrieve shipping carriers for specified order + * + * @param Mage_Eav_Model_Entity_Abstract $object + * @return array + */ + protected function _getCarriers($object) + { + $carriers = array(); + $carrierInstances = Mage::getSingleton('Mage_Shipping_Model_Config')->getAllCarriers( + $object->getStoreId() + ); + + $carriers['custom'] = Mage::helper('Mage_Sales_Helper_Data')->__('Custom Value'); + foreach ($carrierInstances as $code => $carrier) { + if ($carrier->isTrackingAvailable()) { + $carriers[$code] = $carrier->getConfigData('title'); + } + } + + return $carriers; + } + +} // Class Mage_Sales_Model_Order_Shipment_Api End diff --git a/app/code/core/Mage/Sales/Model/Order/Shipment/Api/V2.php b/app/code/core/Mage/Sales/Model/Order/Shipment/Api/V2.php new file mode 100644 index 00000000000..dc6767e50a6 --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Order/Shipment/Api/V2.php @@ -0,0 +1,122 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Sales order shippment API V2 + * + * @category Mage + * @package Mage_Sales + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Sales_Model_Order_Shipment_Api_V2 extends Mage_Sales_Model_Order_Shipment_Api +{ + protected function _prepareItemQtyData($data) + { + $_data = array(); + foreach ($data as $item) { + if (isset($item->order_item_id) && isset($item->qty)) { + $_data[$item->order_item_id] = $item->qty; + } + } + return $_data; + } + + /** + * Create new shipment for order + * + * @param string $orderIncrementId + * @param array $itemsQty + * @param string $comment + * @param boolean $email + * @param boolean $includeComment + * @return string + */ + public function create($orderIncrementId, $itemsQty = array(), $comment = null, $email = false, + $includeComment = false + ) { + $order = Mage::getModel('Mage_Sales_Model_Order')->loadByIncrementId($orderIncrementId); + $itemsQty = $this->_prepareItemQtyData($itemsQty); + /** + * Check order existing + */ + if (!$order->getId()) { + $this->_fault('order_not_exists'); + } + + /** + * Check shipment create availability + */ + if (!$order->canShip()) { + $this->_fault('data_invalid', Mage::helper('Mage_Sales_Helper_Data')->__('Cannot do shipment for order.')); + } + + /* @var $shipment Mage_Sales_Model_Order_Shipment */ + $shipment = $order->prepareShipment($itemsQty); + if ($shipment) { + $shipment->register(); + $shipment->addComment($comment, $email && $includeComment); + if ($email) { + $shipment->setEmailSent(true); + } + $shipment->getOrder()->setIsInProcess(true); + try { + $transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction') + ->addObject($shipment) + ->addObject($shipment->getOrder()) + ->save(); + $shipment->sendEmail($email, ($includeComment ? $comment : '')); + } catch (Mage_Core_Exception $e) { + $this->_fault('data_invalid', $e->getMessage()); + } + return $shipment->getIncrementId(); + } + return null; + } + + /** + * Retrieve allowed shipping carriers for specified order + * + * @param string $orderIncrementId + * @return array + */ + public function getCarriers($orderIncrementId) + { + $order = Mage::getModel('Mage_Sales_Model_Order')->loadByIncrementId($orderIncrementId); + + /** + * Check order existing + */ + if (!$order->getId()) { + $this->_fault('order_not_exists'); + } + $carriers = array(); + foreach ($this->_getCarriers($order) as $key => $value) { + $carriers[] = array('key' => $key, 'value' => $value); + } + + return $carriers; + } +} diff --git a/app/code/core/Mage/Sales/etc/api.xml b/app/code/core/Mage/Sales/etc/api.xml new file mode 100644 index 00000000000..24686784941 --- /dev/null +++ b/app/code/core/Mage/Sales/etc/api.xml @@ -0,0 +1,375 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Sales + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <sales_order translate="title" module="Mage_Sales"> + <model>Mage_Sales_Model_Order_Api</model> + <title>Order API</title> + <acl>sales/order</acl> + <methods> + <list translate="title" module="Mage_Sales"> + <title>Retrieve list of orders by filters</title> + <method>items</method> + <acl>sales/order/info</acl> + </list> + <info translate="title" module="Mage_Sales"> + <title>Retrieve order information</title> + <acl>sales/order/info</acl> + </info> + <addComment translate="title" module="Mage_Sales"> + <title>Add comment to order</title> + <acl>sales/order/change</acl> + </addComment> + <hold translate="title" module="Mage_Sales"> + <title>Hold order</title> + <acl>sales/order/change</acl> + </hold> + <unhold translate="title" module="Mage_Sales"> + <title>Unhold order</title> + <acl>sales/order/change</acl> + </unhold> + <cancel translate="title" module="Mage_Sales"> + <title>Cancel order</title> + <acl>sales/order/change</acl> + </cancel> + </methods> + <faults module="Mage_Sales"> + <not_exists> + <code>100</code> + <message>Requested order does not exist.</message> + </not_exists> + <filters_invalid> + <code>101</code> + <message>Provided filters are invalid. Details are in error message.</message> + </filters_invalid> + <data_invalid> + <code>102</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <status_not_changed> + <code>103</code> + <message>Order status is not changed. Details are in error message.</message> + </status_not_changed> + </faults> + </sales_order> + <sales_order_shipment> + <title>Shipment API</title> + <model>Mage_Sales_Model_Order_Shipment_Api</model> + <acl>sales/order/shipment</acl> + <methods> + <list translate="title" module="Mage_Sales"> + <title>Retrieve list of shipments by filters</title> + <method>items</method> + <acl>sales/order/shipment/info</acl> + </list> + <info translate="title" module="Mage_Sales"> + <title>Retrieve shipment information</title> + <acl>sales/order/shipment/info</acl> + </info> + <sendInfo translate="title" module="Mage_Sales"> + <title>Send shipment info</title> + <acl>sales/order/shipment/send</acl> + </sendInfo> + <create translate="title" module="Mage_Sales"> + <title>Create new shipment for order</title> + <acl>sales/order/shipment/create</acl> + </create> + <addComment translate="title" module="Mage_Sales"> + <title>Add new comment to shipment</title> + <acl>sales/order/shipment/comment</acl> + </addComment> + <addTrack translate="title" module="Mage_Sales"> + <title>Add new tracking number</title> + <acl>sales/order/shipment/track</acl> + </addTrack> + <removeTrack translate="title" module="Mage_Sales"> + <title>Remove tracking number</title> + <acl>sales/order/shipment/track</acl> + </removeTrack> + <getCarriers> + <title>Retrieve list of allowed carriers for order</title> + </getCarriers> + </methods> + <faults module="Mage_Sales"> + <not_exists> + <code>100</code> + <message>Requested shipment does not exist.</message> + </not_exists> + <filters_invalid> + <code>101</code> + <message>Provided filters are invalid. Details are in error message.</message> + </filters_invalid> + <data_invalid> + <code>102</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <order_not_exists> + <code>103</code> + <message>Requested order does not exist.</message> + </order_not_exists> + <track_not_exists> + <code>104</code> + <message>Requested tracking does not exist.</message> + </track_not_exists> + <track_not_deleted> + <code>105</code> + <message>Tracking is not deleted. Details are in error message.</message> + </track_not_deleted> + </faults> + </sales_order_shipment> + <sales_order_invoice> + <title>Invoice API</title> + <model>Mage_Sales_Model_Order_Invoice_Api</model> + <acl>sales/order/invoice</acl> + <methods> + <list translate="title" module="Mage_Sales"> + <title>Retrieve list of invoices by filters</title> + <method>items</method> + <acl>sales/order/invoice/info</acl> + </list> + <info translate="title" module="Mage_Sales"> + <title>Retrieve invoice information</title> + <acl>sales/order/invoice/info</acl> + </info> + <create translate="title" module="Mage_Sales"> + <title>Create new invoice for order</title> + <acl>sales/order/invoice/create</acl> + </create> + <addComment translate="title" module="Mage_Sales"> + <title>Add new comment to shipment</title> + <acl>sales/order/invoice/comment</acl> + </addComment> + <capture translate="title" module="Mage_Sales"> + <title>Capture invoice</title> + <acl>sales/order/invoice/capture</acl> + </capture> + <void translate="title" module="Mage_Sales"> + <title>Void invoice</title> + <acl>sales/order/invoice/void</acl> + </void> + <cancel translate="title" module="Mage_Sales"> + <title>Cancel invoice</title> + <acl>sales/order/invoice/cancel</acl> + </cancel> + </methods> + <faults module="Mage_Sales"> + <not_exists> + <code>100</code> + <message>Requested invoice does not exist.</message> + </not_exists> + <invalid_filter> + <code>101</code> + <message>Provided filter is invalid. Details are in error message.</message> + </invalid_filter> + <data_invalid> + <code>102</code> + <message>Provided data is invalid. Details are in error message.</message> + </data_invalid> + <order_not_exists> + <code>103</code> + <message>Requested order does not exist.</message> + </order_not_exists> + <status_not_changed> + <code>104</code> + <message>Invoice status is not changed</message> + </status_not_changed> + </faults> + </sales_order_invoice> + <sales_order_creditmemo> + <title>Credit memo API</title> + <model>Mage_Sales_Model_Order_Creditmemo_Api</model> + <acl>sales/order/creditmemo</acl> + <methods> + <list translate="title" module="Mage_Sales"> + <title>Retrieve list of credit memos by filters</title> + <method>items</method> + <acl>sales/order/creditmemo/list</acl> + </list> + <info translate="title" module="Mage_Sales"> + <title>Retrieve credit memo information</title> + <acl>sales/order/creditmemo/info</acl> + </info> + <create translate="title" module="Mage_Sales"> + <title>Create new credit memo for order</title> + <acl>sales/order/creditmemo/create</acl> + </create> + <addComment translate="title" module="Mage_Sales"> + <title>Add new comment to credit memo</title> + <acl>sales/order/creditmemo/comment</acl> + </addComment> + <cancel translate="title" module="Mage_Sales"> + <title>Cancel credit memo</title> + <acl>sales/order/creditmemo/cancel</acl> + </cancel> + </methods> + <faults module="Mage_Sales"> + <not_exists> + <code>100</code> + <message>Requested credit memo does not exist.</message> + </not_exists> + <invalid_filter> + <code>101</code> + <message>Provided filter is invalid. Details are in error message</message> + </invalid_filter> + <data_invalid> + <code>102</code> + <message>Provided data is invalid. Details are in error message</message> + </data_invalid> + <order_not_exists> + <code>103</code> + <message>Requested order does not exist.</message> + </order_not_exists> + <status_not_changed> + <code>104</code> + <message>Credit memo status is not changed.</message> + </status_not_changed> + <cannot_refund_to_storecredit> + <code>105</code> + <message>Money cannot be refunded to the store credit account as order was created by guest.</message> + </cannot_refund_to_storecredit> + <cannot_create_creditmemo> + <code>106</code> + <message>Credit memo for requested order cannot be created.</message> + </cannot_create_creditmemo> + </faults> + </sales_order_creditmemo> + </resources> + <resources_alias> + <order>sales_order</order> + <order_shipment>sales_order_shipment</order_shipment> + <order_invoice>sales_order_invoice</order_invoice> + <order_creditmemo>sales_order_creditmemo</order_creditmemo> + </resources_alias> + <v2> + <resources_function_prefix> + <order>salesOrder</order> + <order_shipment>salesOrderShipment</order_shipment> + <order_invoice>salesOrderInvoice</order_invoice> + <order_creditmemo>salesOrderCreditmemo</order_creditmemo> + </resources_function_prefix> + </v2> + <rest> + <mapping> + <sales_order> + <delete> + <method>cancel</method> + </delete> + <post> + <resource>cart</resource> + <method>order</method> + </post> + </sales_order> + <sales_order_invoice> + <delete> + <method>cancel</method> + </delete> + </sales_order_invoice> + <sales_order_creditmemo> + <delete> + <method>cancel</method> + </delete> + </sales_order_creditmemo> + </mapping> + </rest> + <acl> + <resources> + <sales translate="title" module="Mage_Sales"> + <title>Sales</title> + <sort_order>2</sort_order> + <order translate="title" module="Mage_Sales"> + <title>Order</title> + <change translate="title" module="Mage_Sales"> + <title>Change status, add comments</title> + </change> + <info translate="title" module="Mage_Sales"> + <title>Retrieve orders info</title> + </info> + <shipment translate="title" module="Mage_Sales"> + <title>Order shipments</title> + <create translate="title" module="Mage_Sales"> + <title>Create</title> + </create> + <comment translate="title" module="Mage_Sales"> + <title>Comments</title> + </comment> + <track translate="title" module="Mage_Sales"> + <title>Tracking</title> + </track> + <info translate="title" module="Mage_Sales"> + <title>Retrieve shipment info</title> + </info> + <send translate="title" module="Mage_Sales"> + <title>Send shipment info</title> + </send> + </shipment> + <invoice translate="title" module="Mage_Sales"> + <title>Order invoice</title> + <create translate="title" module="Mage_Sales"> + <title>Create</title> + </create> + <comment translate="title" module="Mage_Sales"> + <title>Comments</title> + </comment> + <capture translate="title" module="Mage_Sales"> + <title>Capture</title> + </capture> + <void translate="title" module="Mage_Sales"> + <title>Void</title> + </void> + <cancel translate="title" module="Mage_Sales"> + <title>Cancel</title> + </cancel> + <info translate="title" module="Mage_Sales"> + <title>Retrieve invoice info</title> + </info> + </invoice> + <creditmemo translate="title" module="Mage_Sales"> + <title>Order credit memo</title> + <create translate="title" module="Mage_Sales"> + <title>Create</title> + </create> + <comment translate="title" module="Mage_Sales"> + <title>Comments</title> + </comment> + <cancel translate="title" module="Mage_Sales"> + <title>Cancel</title> + </cancel> + <info translate="title" module="Mage_Sales"> + <title>Retrieve credit memo info</title> + </info> + <list translate="title" module="Mage_Sales"> + <title>Retrieve credit memo list</title> + </list> + </creditmemo> + </order> + </sales> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/Sales/etc/wsdl.xml b/app/code/core/Mage/Sales/etc/wsdl.xml new file mode 100644 index 00000000000..343e3330dd7 --- /dev/null +++ b/app/code/core/Mage/Sales/etc/wsdl.xml @@ -0,0 +1,1346 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="salesOrderEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="store_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="customer_id" type="xsd:string" minOccurs="0" /> + <element name="tax_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="discount_amount" type="xsd:string" minOccurs="0" /> + <element name="subtotal" type="xsd:string" minOccurs="0" /> + <element name="grand_total" type="xsd:string" minOccurs="0" /> + <element name="total_paid" type="xsd:string" minOccurs="0" /> + <element name="total_refunded" type="xsd:string" minOccurs="0" /> + <element name="total_qty_ordered" type="xsd:string" minOccurs="0" /> + <element name="total_canceled" type="xsd:string" minOccurs="0" /> + <element name="total_invoiced" type="xsd:string" minOccurs="0" /> + <element name="total_online_refunded" type="xsd:string" minOccurs="0" /> + <element name="total_offline_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal" type="xsd:string" minOccurs="0" /> + <element name="base_grand_total" type="xsd:string" minOccurs="0" /> + <element name="base_total_paid" type="xsd:string" minOccurs="0" /> + <element name="base_total_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_total_qty_ordered" type="xsd:string" minOccurs="0" /> + <element name="base_total_canceled" type="xsd:string" minOccurs="0" /> + <element name="base_total_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_total_online_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_total_offline_refunded" type="xsd:string" minOccurs="0" /> + <element name="billing_address_id" type="xsd:string" minOccurs="0" /> + <element name="billing_firstname" type="xsd:string" minOccurs="0" /> + <element name="billing_lastname" type="xsd:string" minOccurs="0" /> + <element name="shipping_address_id" type="xsd:string" minOccurs="0" /> + <element name="shipping_firstname" type="xsd:string" minOccurs="0" /> + <element name="shipping_lastname" type="xsd:string" minOccurs="0" /> + <element name="billing_name" type="xsd:string" minOccurs="0" /> + <element name="shipping_name" type="xsd:string" minOccurs="0" /> + <element name="store_to_base_rate" type="xsd:string" minOccurs="0" /> + <element name="store_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="base_to_global_rate" type="xsd:string" minOccurs="0" /> + <element name="base_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="weight" type="xsd:string" minOccurs="0" /> + <element name="store_name" type="xsd:string" minOccurs="0" /> + <element name="remote_ip" type="xsd:string" minOccurs="0" /> + <element name="status" type="xsd:string" minOccurs="0" /> + <element name="state" type="xsd:string" minOccurs="0" /> + <element name="applied_rule_ids" type="xsd:string" minOccurs="0" /> + <element name="global_currency_code" type="xsd:string" minOccurs="0" /> + <element name="base_currency_code" type="xsd:string" minOccurs="0" /> + <element name="store_currency_code" type="xsd:string" minOccurs="0" /> + <element name="order_currency_code" type="xsd:string" minOccurs="0" /> + <element name="shipping_method" type="xsd:string" minOccurs="0" /> + <element name="shipping_description" type="xsd:string" minOccurs="0" /> + <element name="customer_email" type="xsd:string" minOccurs="0" /> + <element name="customer_firstname" type="xsd:string" minOccurs="0" /> + <element name="customer_lastname" type="xsd:string" minOccurs="0" /> + <element name="quote_id" type="xsd:string" minOccurs="0" /> + <element name="is_virtual" type="xsd:string" minOccurs="0" /> + <element name="customer_group_id" type="xsd:string" minOccurs="0" /> + <element name="customer_note_notify" type="xsd:string" minOccurs="0" /> + <element name="customer_is_guest" type="xsd:string" minOccurs="0" /> + <element name="email_sent" type="xsd:string" minOccurs="0" /> + <element name="order_id" type="xsd:string" minOccurs="0" /> + <element name="gift_message_id" type="xsd:string" minOccurs="0" /> + <element name="gift_message" type="xsd:string" minOccurs="0" /> + <element name="shipping_address" type="typens:salesOrderAddressEntity" minOccurs="0" /> + <element name="billing_address" type="typens:salesOrderAddressEntity" minOccurs="0" /> + <element name="items" type="typens:salesOrderItemEntityArray" minOccurs="0" /> + <element name="payment" type="typens:salesOrderPaymentEntity" minOccurs="0" /> + <element name="status_history" type="typens:salesOrderStatusHistoryEntityArray" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderListEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="store_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="customer_id" type="xsd:string" minOccurs="0" /> + <element name="tax_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="discount_amount" type="xsd:string" minOccurs="0" /> + <element name="subtotal" type="xsd:string" minOccurs="0" /> + <element name="grand_total" type="xsd:string" minOccurs="0" /> + <element name="total_paid" type="xsd:string" minOccurs="0" /> + <element name="total_refunded" type="xsd:string" minOccurs="0" /> + <element name="total_qty_ordered" type="xsd:string" minOccurs="0" /> + <element name="total_canceled" type="xsd:string" minOccurs="0" /> + <element name="total_invoiced" type="xsd:string" minOccurs="0" /> + <element name="total_online_refunded" type="xsd:string" minOccurs="0" /> + <element name="total_offline_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal" type="xsd:string" minOccurs="0" /> + <element name="base_grand_total" type="xsd:string" minOccurs="0" /> + <element name="base_total_paid" type="xsd:string" minOccurs="0" /> + <element name="base_total_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_total_qty_ordered" type="xsd:string" minOccurs="0" /> + <element name="base_total_canceled" type="xsd:string" minOccurs="0" /> + <element name="base_total_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_total_online_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_total_offline_refunded" type="xsd:string" minOccurs="0" /> + <element name="billing_address_id" type="xsd:string" minOccurs="0" /> + <element name="billing_firstname" type="xsd:string" minOccurs="0" /> + <element name="billing_lastname" type="xsd:string" minOccurs="0" /> + <element name="shipping_address_id" type="xsd:string" minOccurs="0" /> + <element name="shipping_firstname" type="xsd:string" minOccurs="0" /> + <element name="shipping_lastname" type="xsd:string" minOccurs="0" /> + <element name="billing_name" type="xsd:string" minOccurs="0" /> + <element name="shipping_name" type="xsd:string" minOccurs="0" /> + <element name="store_to_base_rate" type="xsd:string" minOccurs="0" /> + <element name="store_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="base_to_global_rate" type="xsd:string" minOccurs="0" /> + <element name="base_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="weight" type="xsd:string" minOccurs="0" /> + <element name="store_name" type="xsd:string" minOccurs="0" /> + <element name="remote_ip" type="xsd:string" minOccurs="0" /> + <element name="status" type="xsd:string" minOccurs="0" /> + <element name="state" type="xsd:string" minOccurs="0" /> + <element name="applied_rule_ids" type="xsd:string" minOccurs="0" /> + <element name="global_currency_code" type="xsd:string" minOccurs="0" /> + <element name="base_currency_code" type="xsd:string" minOccurs="0" /> + <element name="store_currency_code" type="xsd:string" minOccurs="0" /> + <element name="order_currency_code" type="xsd:string" minOccurs="0" /> + <element name="shipping_method" type="xsd:string" minOccurs="0" /> + <element name="shipping_description" type="xsd:string" minOccurs="0" /> + <element name="customer_email" type="xsd:string" minOccurs="0" /> + <element name="customer_firstname" type="xsd:string" minOccurs="0" /> + <element name="customer_lastname" type="xsd:string" minOccurs="0" /> + <element name="quote_id" type="xsd:string" minOccurs="0" /> + <element name="is_virtual" type="xsd:string" minOccurs="0" /> + <element name="customer_group_id" type="xsd:string" minOccurs="0" /> + <element name="customer_note_notify" type="xsd:string" minOccurs="0" /> + <element name="customer_is_guest" type="xsd:string" minOccurs="0" /> + <element name="email_sent" type="xsd:string" minOccurs="0" /> + <element name="order_id" type="xsd:string" minOccurs="0" /> + <element name="gift_message_id" type="xsd:string" minOccurs="0" /> + <element name="coupon_code" type="xsd:string" minOccurs="0" /> + <element name="protect_code" type="xsd:string" minOccurs="0" /> + <element name="base_discount_canceled" type="xsd:string" minOccurs="0" /> + <element name="base_discount_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_discount_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_canceled" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_tax_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal_canceled" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_tax_canceled" type="xsd:string" minOccurs="0" /> + <element name="base_tax_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_tax_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_total_invoiced_cost" type="xsd:string" minOccurs="0" /> + <element name="discount_canceled" type="xsd:string" minOccurs="0" /> + <element name="discount_invoiced" type="xsd:string" minOccurs="0" /> + <element name="discount_refunded" type="xsd:string" minOccurs="0" /> + <element name="shipping_canceled" type="xsd:string" minOccurs="0" /> + <element name="shipping_invoiced" type="xsd:string" minOccurs="0" /> + <element name="shipping_refunded" type="xsd:string" minOccurs="0" /> + <element name="shipping_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_tax_refunded" type="xsd:string" minOccurs="0" /> + <element name="subtotal_canceled" type="xsd:string" minOccurs="0" /> + <element name="subtotal_invoiced" type="xsd:string" minOccurs="0" /> + <element name="subtotal_refunded" type="xsd:string" minOccurs="0" /> + <element name="tax_canceled" type="xsd:string" minOccurs="0" /> + <element name="tax_invoiced" type="xsd:string" minOccurs="0" /> + <element name="tax_refunded" type="xsd:string" minOccurs="0" /> + <element name="can_ship_partially" type="xsd:string" minOccurs="0" /> + <element name="can_ship_partially_item" type="xsd:string" minOccurs="0" /> + <element name="edit_increment" type="xsd:string" minOccurs="0" /> + <element name="forced_do_shipment_with_invoice" type="xsd:string" minOccurs="0" /> + <element name="payment_authorization_expiration" type="xsd:string" minOccurs="0" /> + <element name="paypal_ipn_customer_notified" type="xsd:string" minOccurs="0" /> + <element name="quote_address_id" type="xsd:string" minOccurs="0" /> + <element name="adjustment_negative" type="xsd:string" minOccurs="0" /> + <element name="adjustment_positive" type="xsd:string" minOccurs="0" /> + <element name="base_adjustment_negative" type="xsd:string" minOccurs="0" /> + <element name="base_adjustment_positive" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="base_total_due" type="xsd:string" minOccurs="0" /> + <element name="payment_authorization_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="subtotal_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="total_due" type="xsd:string" minOccurs="0" /> + <element name="customer_dob" type="xsd:string" minOccurs="0" /> + <element name="customer_middlename" type="xsd:string" minOccurs="0" /> + <element name="customer_prefix" type="xsd:string" minOccurs="0" /> + <element name="customer_suffix" type="xsd:string" minOccurs="0" /> + <element name="customer_taxvat" type="xsd:string" minOccurs="0" /> + <element name="discount_description" type="xsd:string" minOccurs="0" /> + <element name="ext_customer_id" type="xsd:string" minOccurs="0" /> + <element name="ext_order_id" type="xsd:string" minOccurs="0" /> + <element name="hold_before_state" type="xsd:string" minOccurs="0" /> + <element name="hold_before_status" type="xsd:string" minOccurs="0" /> + <element name="original_increment_id" type="xsd:string" minOccurs="0" /> + <element name="relation_child_id" type="xsd:string" minOccurs="0" /> + <element name="relation_child_real_id" type="xsd:string" minOccurs="0" /> + <element name="relation_parent_id" type="xsd:string" minOccurs="0" /> + <element name="relation_parent_real_id" type="xsd:string" minOccurs="0" /> + <element name="x_forwarded_for" type="xsd:string" minOccurs="0" /> + <element name="customer_note" type="xsd:string" minOccurs="0" /> + <element name="total_item_count" type="xsd:string" minOccurs="0" /> + <element name="customer_gender" type="xsd:string" minOccurs="0" /> + <element name="hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="hidden_tax_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_hidden_tax_invoiced" type="xsd:string" minOccurs="0" /> + <element name="hidden_tax_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_hidden_tax_refunded" type="xsd:string" minOccurs="0" /> + <element name="shipping_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="base_customer_balance_amount" type="xsd:string" minOccurs="0" /> + <element name="customer_balance_amount" type="xsd:string" minOccurs="0" /> + <element name="base_customer_balance_invoiced" type="xsd:string" minOccurs="0" /> + <element name="customer_balance_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_customer_balance_refunded" type="xsd:string" minOccurs="0" /> + <element name="customer_balance_refunded" type="xsd:string" minOccurs="0" /> + <element name="bs_customer_bal_total_refunded" type="xsd:string" minOccurs="0" /> + <element name="customer_bal_total_refunded" type="xsd:string" minOccurs="0" /> + <element name="gift_cards" type="xsd:string" minOccurs="0" /> + <element name="base_gift_cards_amount" type="xsd:string" minOccurs="0" /> + <element name="gift_cards_amount" type="xsd:string" minOccurs="0" /> + <element name="base_gift_cards_invoiced" type="xsd:string" minOccurs="0" /> + <element name="gift_cards_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_gift_cards_refunded" type="xsd:string" minOccurs="0" /> + <element name="gift_cards_refunded" type="xsd:string" minOccurs="0" /> + <element name="reward_points_balance" type="xsd:string" minOccurs="0" /> + <element name="base_reward_currency_amount" type="xsd:string" minOccurs="0" /> + <element name="reward_currency_amount" type="xsd:string" minOccurs="0" /> + <element name="base_rwrd_crrncy_amt_invoiced" type="xsd:string" minOccurs="0" /> + <element name="rwrd_currency_amount_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_rwrd_crrncy_amnt_refnded" type="xsd:string" minOccurs="0" /> + <element name="rwrd_crrncy_amnt_refunded" type="xsd:string" minOccurs="0" /> + <element name="reward_points_balance_refunded" type="xsd:string" minOccurs="0" /> + <element name="reward_points_balance_refund" type="xsd:string" minOccurs="0" /> + <element name="reward_salesrule_points" type="xsd:string" minOccurs="0" /> + <element name="firstname" type="xsd:string" minOccurs="0" /> + <element name="lastname" type="xsd:string" minOccurs="0" /> + <element name="telephone" type="xsd:string" minOccurs="0" /> + <element name="postcode" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderListEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderListEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderAddressEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="address_type" type="xsd:string" minOccurs="0" /> + <element name="firstname" type="xsd:string" minOccurs="0" /> + <element name="lastname" type="xsd:string" minOccurs="0" /> + <element name="company" type="xsd:string" minOccurs="0" /> + <element name="street" type="xsd:string" minOccurs="0" /> + <element name="city" type="xsd:string" minOccurs="0" /> + <element name="region" type="xsd:string" minOccurs="0" /> + <element name="postcode" type="xsd:string" minOccurs="0" /> + <element name="country_id" type="xsd:string" minOccurs="0" /> + <element name="telephone" type="xsd:string" minOccurs="0" /> + <element name="fax" type="xsd:string" minOccurs="0" /> + <element name="region_id" type="xsd:string" minOccurs="0" /> + <element name="address_id" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderItemEntity"> + <all> + <element name="item_id" type="xsd:string" minOccurs="0" /> + <element name="order_id" type="xsd:string" minOccurs="0" /> + <element name="quote_item_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="product_id" type="xsd:string" minOccurs="0" /> + <element name="product_type" type="xsd:string" minOccurs="0" /> + <element name="product_options" type="xsd:string" minOccurs="0" /> + <element name="weight" type="xsd:string" minOccurs="0" /> + <element name="is_virtual" type="xsd:string" minOccurs="0" /> + <element name="sku" type="xsd:string" minOccurs="0" /> + <element name="name" type="xsd:string" minOccurs="0" /> + <element name="applied_rule_ids" type="xsd:string" minOccurs="0" /> + <element name="free_shipping" type="xsd:string" minOccurs="0" /> + <element name="is_qty_decimal" type="xsd:string" minOccurs="0" /> + <element name="no_discount" type="xsd:string" minOccurs="0" /> + <element name="qty_canceled" type="xsd:string" minOccurs="0" /> + <element name="qty_invoiced" type="xsd:string" minOccurs="0" /> + <element name="qty_ordered" type="xsd:string" minOccurs="0" /> + <element name="qty_refunded" type="xsd:string" minOccurs="0" /> + <element name="qty_shipped" type="xsd:string" minOccurs="0" /> + <element name="cost" type="xsd:string" minOccurs="0" /> + <element name="price" type="xsd:string" minOccurs="0" /> + <element name="base_price" type="xsd:string" minOccurs="0" /> + <element name="original_price" type="xsd:string" minOccurs="0" /> + <element name="base_original_price" type="xsd:string" minOccurs="0" /> + <element name="tax_percent" type="xsd:string" minOccurs="0" /> + <element name="tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="tax_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_tax_invoiced" type="xsd:string" minOccurs="0" /> + <element name="discount_percent" type="xsd:string" minOccurs="0" /> + <element name="discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="discount_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_discount_invoiced" type="xsd:string" minOccurs="0" /> + <element name="amount_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_amount_refunded" type="xsd:string" minOccurs="0" /> + <element name="row_total" type="xsd:string" minOccurs="0" /> + <element name="base_row_total" type="xsd:string" minOccurs="0" /> + <element name="row_invoiced" type="xsd:string" minOccurs="0" /> + <element name="base_row_invoiced" type="xsd:string" minOccurs="0" /> + <element name="row_weight" type="xsd:string" minOccurs="0" /> + <element name="gift_message_id" type="xsd:string" minOccurs="0" /> + <element name="gift_message" type="xsd:string" minOccurs="0" /> + <element name="gift_message_available" type="xsd:string" minOccurs="0" /> + <element name="base_tax_before_discount" type="xsd:string" minOccurs="0" /> + <element name="tax_before_discount" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_applied_row_amnt" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderItemEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderItemEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="orderItemIdQty"> + <all> + <element name="order_item_id" type="xsd:int" /> + <element name="qty" type="xsd:double" /> + </all> + </complexType> + <complexType name="orderItemIdQtyArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:orderItemIdQty[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderPaymentEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="amount_ordered" type="xsd:string" minOccurs="0" /> + <element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="base_amount_ordered" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="method" type="xsd:string" minOccurs="0" /> + <element name="po_number" type="xsd:string" minOccurs="0" /> + <element name="cc_type" type="xsd:string" minOccurs="0" /> + <element name="cc_number_enc" type="xsd:string" minOccurs="0" /> + <element name="cc_last4" type="xsd:string" minOccurs="0" /> + <element name="cc_owner" type="xsd:string" minOccurs="0" /> + <element name="cc_exp_month" type="xsd:string" minOccurs="0" /> + <element name="cc_exp_year" type="xsd:string" minOccurs="0" /> + <element name="cc_ss_start_month" type="xsd:string" minOccurs="0" /> + <element name="cc_ss_start_year" type="xsd:string" minOccurs="0" /> + <element name="payment_id" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderStatusHistoryEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="is_customer_notified" type="xsd:string" minOccurs="0" /> + <element name="status" type="xsd:string" minOccurs="0" /> + <element name="comment" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderStatusHistoryEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderStatusHistoryEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderShipmentEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="store_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="shipping_address_id" type="xsd:string" minOccurs="0" /> + <element name="shipping_firstname" type="xsd:string" minOccurs="0" /> + <element name="shipping_lastname" type="xsd:string" minOccurs="0" /> + <element name="order_id" type="xsd:string" minOccurs="0" /> + <element name="order_increment_id" type="xsd:string" minOccurs="0" /> + <element name="order_created_at" type="xsd:string" minOccurs="0" /> + <element name="total_qty" type="xsd:string" minOccurs="0" /> + <element name="shipment_id" type="xsd:string" minOccurs="0" /> + <element name="items" type="typens:salesOrderShipmentItemEntityArray" minOccurs="0" /> + <element name="tracks" type="typens:salesOrderShipmentTrackEntityArray" minOccurs="0" /> + <element name="comments" type="typens:salesOrderShipmentCommentEntityArray" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderShipmentEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderShipmentEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderShipmentCommentEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="comment" type="xsd:string" minOccurs="0" /> + <element name="is_customer_notified" type="xsd:string" minOccurs="0" /> + <element name="comment_id" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderShipmentCommentEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderShipmentCommentEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderShipmentTrackEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="carrier_code" type="xsd:string" minOccurs="0" /> + <element name="title" type="xsd:string" minOccurs="0" /> + <element name="number" type="xsd:string" minOccurs="0" /> + <element name="order_id" type="xsd:string" minOccurs="0" /> + <element name="track_id" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderShipmentTrackEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderShipmentTrackEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderShipmentItemEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="sku" type="xsd:string" minOccurs="0" /> + <element name="name" type="xsd:string" minOccurs="0" /> + <element name="order_item_id" type="xsd:string" minOccurs="0" /> + <element name="product_id" type="xsd:string" minOccurs="0" /> + <element name="weight" type="xsd:string" minOccurs="0" /> + <element name="price" type="xsd:string" minOccurs="0" /> + <element name="qty" type="xsd:string" minOccurs="0" /> + <element name="item_id" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderShipmentItemEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderShipmentItemEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderInvoiceEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="store_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="global_currency_code" type="xsd:string" minOccurs="0" /> + <element name="base_currency_code" type="xsd:string" minOccurs="0" /> + <element name="store_currency_code" type="xsd:string" minOccurs="0" /> + <element name="order_currency_code" type="xsd:string" minOccurs="0" /> + <element name="store_to_base_rate" type="xsd:string" minOccurs="0" /> + <element name="store_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="base_to_global_rate" type="xsd:string" minOccurs="0" /> + <element name="base_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="subtotal" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal" type="xsd:string" minOccurs="0" /> + <element name="base_grand_total" type="xsd:string" minOccurs="0" /> + <element name="discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="billing_address_id" type="xsd:string" minOccurs="0" /> + <element name="billing_firstname" type="xsd:string" minOccurs="0" /> + <element name="billing_lastname" type="xsd:string" minOccurs="0" /> + <element name="order_id" type="xsd:string" minOccurs="0" /> + <element name="order_increment_id" type="xsd:string" minOccurs="0" /> + <element name="order_created_at" type="xsd:string" minOccurs="0" /> + <element name="state" type="xsd:string" minOccurs="0" /> + <element name="grand_total" type="xsd:string" minOccurs="0" /> + <element name="invoice_id" type="xsd:string" minOccurs="0" /> + <element name="items" type="typens:salesOrderInvoiceItemEntityArray" minOccurs="0" /> + <element name="comments" type="typens:salesOrderInvoiceCommentEntityArray" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderInvoiceEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderInvoiceEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderInvoiceItemEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied" type="xsd:string" minOccurs="0" /> + <element name="qty" type="xsd:string" minOccurs="0" /> + <element name="cost" type="xsd:string" minOccurs="0" /> + <element name="price" type="xsd:string" minOccurs="0" /> + <element name="tax_amount" type="xsd:string" minOccurs="0" /> + <element name="row_total" type="xsd:string" minOccurs="0" /> + <element name="base_price" type="xsd:string" minOccurs="0" /> + <element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_row_total" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_applied_row_amnt" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <element name="sku" type="xsd:string" minOccurs="0" /> + <element name="name" type="xsd:string" minOccurs="0" /> + <element name="order_item_id" type="xsd:string" minOccurs="0" /> + <element name="product_id" type="xsd:string" minOccurs="0" /> + <element name="item_id" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderInvoiceItemEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderInvoiceItemEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderInvoiceCommentEntity"> + <all> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="is_active" type="xsd:string" minOccurs="0" /> + <element name="comment" type="xsd:string" minOccurs="0" /> + <element name="is_customer_notified" type="xsd:string" minOccurs="0" /> + <element name="comment_id" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderInvoiceCommentEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderInvoiceCommentEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderCreditmemoEntity"> + <all> + <element name="updated_at" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="increment_id" type="xsd:string" minOccurs="0" /> + <element name="transaction_id" type="xsd:string" minOccurs="0" /> + <element name="global_currency_code" type="xsd:string" minOccurs="0" /> + <element name="base_currency_code" type="xsd:string" minOccurs="0" /> + <element name="order_currency_code" type="xsd:string" minOccurs="0" /> + <element name="store_currency_code" type="xsd:string" minOccurs="0" /> + <element name="cybersource_token" type="xsd:string" minOccurs="0" /> + <element name="invoice_id" type="xsd:string" minOccurs="0" /> + <element name="billing_address_id" type="xsd:string" minOccurs="0" /> + <element name="shipping_address_id" type="xsd:string" minOccurs="0" /> + <element name="state" type="xsd:string" minOccurs="0" /> + <element name="creditmemo_status" type="xsd:string" minOccurs="0" /> + <element name="email_sent" type="xsd:string" minOccurs="0" /> + <element name="order_id" type="xsd:string" minOccurs="0" /> + <element name="tax_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_adjustment_positive" type="xsd:string" minOccurs="0" /> + <element name="base_grand_total" type="xsd:string" minOccurs="0" /> + <element name="adjustment" type="xsd:string" minOccurs="0" /> + <element name="subtotal" type="xsd:string" minOccurs="0" /> + <element name="discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal" type="xsd:string" minOccurs="0" /> + <element name="base_adjustment" type="xsd:string" minOccurs="0" /> + <element name="base_to_global_rate" type="xsd:string" minOccurs="0" /> + <element name="store_to_base_rate" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="adjustment_negative" type="xsd:string" minOccurs="0" /> + <element name="subtotal_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <element name="base_subtotal_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="base_adjustment_negative" type="xsd:string" minOccurs="0" /> + <element name="grand_total" type="xsd:string" minOccurs="0" /> + <element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="store_to_order_rate" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="adjustment_positive" type="xsd:string" minOccurs="0" /> + <element name="store_id" type="xsd:string" minOccurs="0" /> + <element name="hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="shipping_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_hidden_tax_amnt" type="xsd:string" minOccurs="0" /> + <element name="shipping_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="base_shipping_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="base_customer_balance_amount" type="xsd:string" minOccurs="0" /> + <element name="customer_balance_amount" type="xsd:string" minOccurs="0" /> + <element name="bs_customer_bal_total_refunded" type="xsd:string" minOccurs="0" /> + <element name="customer_bal_total_refunded" type="xsd:string" minOccurs="0" /> + <element name="base_gift_cards_amount" type="xsd:string" minOccurs="0" /> + <element name="gift_cards_amount" type="xsd:string" minOccurs="0" /> + <element name="gw_base_price" type="xsd:string" minOccurs="0" /> + <element name="gw_price" type="xsd:string" minOccurs="0" /> + <element name="gw_items_base_price" type="xsd:string" minOccurs="0" /> + <element name="gw_items_price" type="xsd:string" minOccurs="0" /> + <element name="gw_card_base_price" type="xsd:string" minOccurs="0" /> + <element name="gw_card_price" type="xsd:string" minOccurs="0" /> + <element name="gw_base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="gw_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="gw_items_base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="gw_items_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="gw_card_base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="gw_card_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_reward_currency_amount" type="xsd:string" minOccurs="0" /> + <element name="reward_currency_amount" type="xsd:string" minOccurs="0" /> + <element name="reward_points_balance" type="xsd:string" minOccurs="0" /> + <element name="reward_points_balance_refund" type="xsd:string" minOccurs="0" /> + <element name="creditmemo_id" type="xsd:string" minOccurs="0" /> + <element name="items" type="typens:salesOrderCreditmemoItemEntityArray" minOccurs="0" /> + <element name="comments" type="typens:salesOrderCreditmemoCommentEntityArray" minOccurs="0" /> + </all> + </complexType> + <complexType name="salesOrderCreditmemoEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderCreditmemoEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderCreditmemoItemEntity"> + <all> + <element name="item_id" type="xsd:string" minOccurs="0" /> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" /> + <element name="base_price" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <element name="tax_amount" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <element name="base_row_total" type="xsd:string" minOccurs="0" /> + <element name="discount_amount" type="xsd:string" minOccurs="0" /> + <element name="row_total" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <element name="price_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <element name="base_price_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="qty" type="xsd:string" minOccurs="0" /> + <element name="base_cost" type="xsd:string" minOccurs="0" /> + <element name="base_weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" /> + <element name="price" type="xsd:string" minOccurs="0" /> + <element name="base_row_total_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="row_total_incl_tax" type="xsd:string" minOccurs="0" /> + <element name="product_id" type="xsd:string" minOccurs="0" /> + <element name="order_item_id" type="xsd:string" minOccurs="0" /> + <element name="additional_data" type="xsd:string" minOccurs="0" /> + <element name="description" type="xsd:string" minOccurs="0" /> + <element name="weee_tax_applied" type="xsd:string" minOccurs="0" /> + <element name="sku" type="xsd:string" minOccurs="0" /> + <element name="name" type="xsd:string" minOccurs="0" /> + <element name="hidden_tax_amount" type="xsd:string" minOccurs="0"/> + <element name="base_hidden_tax_amount" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="salesOrderCreditmemoItemEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderCreditmemoItemEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderCreditmemoCommentEntity"> + <all> + <element name="parent_id" type="xsd:string" minOccurs="0" /> + <element name="created_at" type="xsd:string" minOccurs="0" /> + <element name="comment" type="xsd:string" minOccurs="0" /> + <element name="is_customer_notified" type="xsd:string" minOccurs="0" /> + <element name="comment_id" type="xsd:string" minOccurs="0" /> + <element name="is_visible_on_front" type="xsd:string" minOccurs="0"/> + </all> + </complexType> + <complexType name="salesOrderCreditmemoCommentEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:salesOrderCreditmemoCommentEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="salesOrderCreditmemoData"> + <all> + <element name="qtys" type="typens:orderItemIdQtyArray" minOccurs="0"/> + <element name="shipping_amount" type="xsd:double" minOccurs="0"/> + <element name="adjustment_positive" type="xsd:double" minOccurs="0"/> + <element name="adjustment_negative" type="xsd:double" minOccurs="0"/> + </all> + </complexType> + </schema> + </types> + <message name="salesOrderListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="filters" type="typens:filters" /> + </message> + <message name="salesOrderListResponse"> + <part name="result" type="typens:salesOrderListEntityArray" /> + </message> + <message name="salesOrderInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderInfoResponse"> + <part name="result" type="typens:salesOrderEntity" /> + </message> + <message name="salesOrderAddCommentRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + <part name="status" type="xsd:string" /> + <part name="comment" type="xsd:string" /> + <part name="notify" type="xsd:string" /> + </message> + <message name="salesOrderAddCommentResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderHoldRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderHoldResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderUnholdRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderUnholdResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderCancelRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderCancelResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderShipmentListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="filters" type="typens:filters" /> + </message> + <message name="salesOrderShipmentListResponse"> + <part name="result" type="typens:salesOrderShipmentEntityArray" /> + </message> + <message name="salesOrderShipmentInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="shipmentIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderShipmentInfoResponse"> + <part name="result" type="typens:salesOrderShipmentEntity" /> + </message> + <message name="salesOrderShipmentCreateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + <part name="itemsQty" type="typens:orderItemIdQtyArray" /> + <part name="comment" type="xsd:string" /> + <part name="email" type="xsd:int" /> + <part name="includeComment" type="xsd:int" /> + </message> + <message name="salesOrderShipmentCreateResponse"> + <part name="shipmentIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderShipmentAddCommentRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="shipmentIncrementId" type="xsd:string" /> + <part name="comment" type="xsd:string" /> + <part name="email" type="xsd:string" /> + <part name="includeInEmail" type="xsd:string" /> + </message> + <message name="salesOrderShipmentAddCommentResponse"> + <part name="shipmentIncrementId" type="xsd:boolean" /> + </message> + <message name="salesOrderShipmentAddTrackRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="shipmentIncrementId" type="xsd:string" /> + <part name="carrier" type="xsd:string" /> + <part name="title" type="xsd:string" /> + <part name="trackNumber" type="xsd:string" /> + </message> + <message name="salesOrderShipmentAddTrackResponse"> + <part name="result" type="xsd:int" /> + </message> + <message name="salesOrderShipmentSendInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="shipmentIncrementId" type="xsd:string" /> + <part name="comment" type="xsd:string" /> + </message> + <message name="salesOrderShipmentSendInfoResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderShipmentRemoveTrackRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="shipmentIncrementId" type="xsd:string" /> + <part name="trackId" type="xsd:string" /> + </message> + <message name="salesOrderShipmentRemoveTrackResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderShipmentGetCarriersRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderShipmentGetCarriersResponse"> + <part name="result" type="typens:associativeArray" /> + </message> + <message name="salesOrderInvoiceListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="filters" type="typens:filters" /> + </message> + <message name="salesOrderInvoiceListResponse"> + <part name="result" type="typens:salesOrderInvoiceEntityArray" /> + </message> + <message name="salesOrderInvoiceInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="invoiceIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderInvoiceInfoResponse"> + <part name="result" type="typens:salesOrderInvoiceEntity" /> + </message> + <message name="salesOrderInvoiceCreateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="orderIncrementId" type="xsd:string" /> + <part name="itemsQty" type="typens:orderItemIdQtyArray" /> + <part name="comment" type="xsd:string" /> + <part name="email" type="xsd:string" /> + <part name="includeComment" type="xsd:string" /> + </message> + <message name="salesOrderInvoiceCreateResponse"> + <part name="result" type="xsd:string" /> + </message> + <message name="salesOrderInvoiceAddCommentRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="invoiceIncrementId" type="xsd:string" /> + <part name="comment" type="xsd:string" /> + <part name="email" type="xsd:string" /> + <part name="includeComment" type="xsd:string" /> + </message> + <message name="salesOrderInvoiceAddCommentResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderCreditmemoListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="filters" type="typens:filters" /> + </message> + <message name="salesOrderCreditmemoListResponse"> + <part name="result" type="typens:salesOrderCreditmemoEntityArray" /> + </message> + <message name="salesOrderCreditmemoInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="creditmemoIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderCreditmemoInfoResponse"> + <part name="result" type="typens:salesOrderCreditmemoEntity" /> + </message> + <message name="salesOrderCreditmemoCreateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="creditmemoIncrementId" type="xsd:string" /> + <part name="creditmemoData" type="typens:salesOrderCreditmemoData" /> + <part name="comment" type="xsd:string" /> + <part name="notifyCustomer" type="xsd:int" /> + <part name="includeComment" type="xsd:int" /> + <part name="refundToStoreCreditAmount" type="xsd:string" /> + </message> + <message name="salesOrderCreditmemoCreateResponse"> + <part name="result" type="xsd:string" /> + </message> + <message name="salesOrderCreditmemoAddCommentRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="creditmemoIncrementId" type="xsd:string" /> + <part name="comment" type="xsd:string" /> + <part name="notifyCustomer" type="xsd:int" /> + <part name="includeComment" type="xsd:int" /> + </message> + <message name="salesOrderCreditmemoAddCommentResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderCreditmemoCancelRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="creditmemoIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderCreditmemoCancelResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderInvoiceCaptureRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="invoiceIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderInvoiceCaptureResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderInvoiceVoidRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="invoiceIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderInvoiceVoidResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="salesOrderInvoiceCancelRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="invoiceIncrementId" type="xsd:string" /> + </message> + <message name="salesOrderInvoiceCancelResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="salesOrderList"> + <documentation>Retrieve list of orders by filters</documentation> + <input message="typens:salesOrderListRequest" /> + <output message="typens:salesOrderListResponse" /> + </operation> + <operation name="salesOrderInfo"> + <documentation>Retrieve order information</documentation> + <input message="typens:salesOrderInfoRequest" /> + <output message="typens:salesOrderInfoResponse" /> + </operation> + <operation name="salesOrderAddComment"> + <documentation>Add comment to order</documentation> + <input message="typens:salesOrderAddCommentRequest" /> + <output message="typens:salesOrderAddCommentResponse" /> + </operation> + <operation name="salesOrderHold"> + <documentation>Hold order</documentation> + <input message="typens:salesOrderHoldRequest" /> + <output message="typens:salesOrderHoldResponse" /> + </operation> + <operation name="salesOrderUnhold"> + <documentation>Unhold order</documentation> + <input message="typens:salesOrderUnholdRequest" /> + <output message="typens:salesOrderUnholdResponse" /> + </operation> + <operation name="salesOrderCancel"> + <documentation>Cancel order</documentation> + <input message="typens:salesOrderCancelRequest" /> + <output message="typens:salesOrderCancelResponse" /> + </operation> + <operation name="salesOrderShipmentList"> + <documentation>Retrieve list of shipments by filters</documentation> + <input message="typens:salesOrderShipmentListRequest" /> + <output message="typens:salesOrderShipmentListResponse" /> + </operation> + <operation name="salesOrderShipmentInfo"> + <documentation>Retrieve shipment information</documentation> + <input message="typens:salesOrderShipmentInfoRequest" /> + <output message="typens:salesOrderShipmentInfoResponse" /> + </operation> + <operation name="salesOrderShipmentCreate"> + <documentation>Create new shipment for order</documentation> + <input message="typens:salesOrderShipmentCreateRequest" /> + <output message="typens:salesOrderShipmentCreateResponse" /> + </operation> + <operation name="salesOrderShipmentAddComment"> + <documentation>Add new comment to shipment</documentation> + <input message="typens:salesOrderShipmentAddCommentRequest" /> + <output message="typens:salesOrderShipmentAddCommentResponse" /> + </operation> + <operation name="salesOrderShipmentAddTrack"> + <documentation>Add new tracking number</documentation> + <input message="typens:salesOrderShipmentAddTrackRequest" /> + <output message="typens:salesOrderShipmentAddTrackResponse" /> + </operation> + <operation name="salesOrderShipmentSendInfo"> + <documentation>Send shipment info</documentation> + <input message="typens:salesOrderShipmentSendInfoRequest" /> + <output message="typens:salesOrderShipmentSendInfoResponse" /> + </operation> + <operation name="salesOrderShipmentRemoveTrack"> + <documentation>Remove tracking number</documentation> + <input message="typens:salesOrderShipmentRemoveTrackRequest" /> + <output message="typens:salesOrderShipmentRemoveTrackResponse" /> + </operation> + <operation name="salesOrderShipmentGetCarriers"> + <documentation>Retrieve list of allowed carriers for order</documentation> + <input message="typens:salesOrderShipmentGetCarriersRequest" /> + <output message="typens:salesOrderShipmentGetCarriersResponse" /> + </operation> + <operation name="salesOrderInvoiceList"> + <documentation>Retrieve list of invoices by filters</documentation> + <input message="typens:salesOrderInvoiceListRequest" /> + <output message="typens:salesOrderInvoiceListResponse" /> + </operation> + <operation name="salesOrderInvoiceInfo"> + <documentation>Retrieve invoice information</documentation> + <input message="typens:salesOrderInvoiceInfoRequest" /> + <output message="typens:salesOrderInvoiceInfoResponse" /> + </operation> + <operation name="salesOrderInvoiceCreate"> + <documentation>Create new invoice for order</documentation> + <input message="typens:salesOrderInvoiceCreateRequest" /> + <output message="typens:salesOrderInvoiceCreateResponse" /> + </operation> + <operation name="salesOrderInvoiceAddComment"> + <documentation>Add new comment to shipment</documentation> + <input message="typens:salesOrderInvoiceAddCommentRequest" /> + <output message="typens:salesOrderInvoiceAddCommentResponse" /> + </operation> + <operation name="salesOrderInvoiceCapture"> + <documentation>Capture invoice</documentation> + <input message="typens:salesOrderInvoiceCaptureRequest" /> + <output message="typens:salesOrderInvoiceCaptureResponse" /> + </operation> + <operation name="salesOrderInvoiceVoid"> + <documentation>Void invoice</documentation> + <input message="typens:salesOrderInvoiceVoidRequest" /> + <output message="typens:salesOrderInvoiceVoidResponse" /> + </operation> + <operation name="salesOrderInvoiceCancel"> + <documentation>Cancel invoice</documentation> + <input message="typens:salesOrderInvoiceCancelRequest" /> + <output message="typens:salesOrderInvoiceCancelResponse" /> + </operation> + <operation name="salesOrderCreditmemoList"> + <documentation>Retrieve list of creditmemos by filters</documentation> + <input message="typens:salesOrderCreditmemoListRequest" /> + <output message="typens:salesOrderCreditmemoListResponse" /> + </operation> + <operation name="salesOrderCreditmemoInfo"> + <documentation>Retrieve creditmemo information</documentation> + <input message="typens:salesOrderCreditmemoInfoRequest" /> + <output message="typens:salesOrderCreditmemoInfoResponse" /> + </operation> + <operation name="salesOrderCreditmemoCreate"> + <documentation>Create new creditmemo for order</documentation> + <input message="typens:salesOrderCreditmemoCreateRequest" /> + <output message="typens:salesOrderCreditmemoCreateResponse" /> + </operation> + <operation name="salesOrderCreditmemoAddComment"> + <documentation>Add new comment to shipment</documentation> + <input message="typens:salesOrderCreditmemoAddCommentRequest" /> + <output message="typens:salesOrderCreditmemoAddCommentResponse" /> + </operation> + <operation name="salesOrderCreditmemoCancel"> + <documentation>Cancel creditmemo</documentation> + <input message="typens:salesOrderCreditmemoCancelRequest" /> + <output message="typens:salesOrderCreditmemoCancelResponse" /> + </operation> + </portType> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="salesOrderList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderAddComment"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderHold"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderUnhold"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderCancel"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentAddComment"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentAddTrack"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentSendInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentRemoveTrack"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderShipmentGetCarriers"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInvoiceList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInvoiceInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInvoiceCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInvoiceAddComment"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInvoiceCapture"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInvoiceVoid"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderInvoiceCancel"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderCreditmemoList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderCreditmemoInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderCreditmemoCreate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderCreditmemoAddComment"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + <operation name="salesOrderCreditmemoCancel"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/Sales/etc/wsi.xml b/app/code/core/Mage/Sales/etc/wsi.xml new file mode 100644 index 00000000000..0d697c86ce8 --- /dev/null +++ b/app/code/core/Mage/Sales/etc/wsi.xml @@ -0,0 +1,1686 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="salesOrderEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotal" type="xsd:string" minOccurs="0" /> + <xsd:element name="grand_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_paid" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_qty_ordered" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_online_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_offline_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_subtotal" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_grand_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_paid" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_qty_ordered" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_online_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_offline_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_address_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_address_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_name" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_name" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_to_base_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_to_order_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_to_global_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_to_order_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="weight" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_name" type="xsd:string" minOccurs="0" /> + <xsd:element name="remote_ip" type="xsd:string" minOccurs="0" /> + <xsd:element name="status" type="xsd:string" minOccurs="0" /> + <xsd:element name="state" type="xsd:string" minOccurs="0" /> + <xsd:element name="applied_rule_ids" type="xsd:string" minOccurs="0" /> + <xsd:element name="global_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_method" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_email" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="quote_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_virtual" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_group_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_note_notify" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_is_guest" type="xsd:string" minOccurs="0" /> + <xsd:element name="email_sent" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_address" type="typens:salesOrderAddressEntity" minOccurs="0" /> + <xsd:element name="billing_address" type="typens:salesOrderAddressEntity" minOccurs="0" /> + <xsd:element name="items" type="typens:salesOrderItemEntityArray" minOccurs="0" /> + <xsd:element name="payment" type="typens:salesOrderPaymentEntity" minOccurs="0" /> + <xsd:element name="status_history" type="typens:salesOrderStatusHistoryEntityArray" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderListEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotal" type="xsd:string" minOccurs="0" /> + <xsd:element name="grand_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_paid" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_qty_ordered" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_online_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_offline_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_subtotal" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_grand_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_paid" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_qty_ordered" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_online_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_offline_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_address_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_address_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_name" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_name" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_to_base_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_to_order_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_to_global_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_to_order_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="weight" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_name" type="xsd:string" minOccurs="0" /> + <xsd:element name="remote_ip" type="xsd:string" minOccurs="0" /> + <xsd:element name="status" type="xsd:string" minOccurs="0" /> + <xsd:element name="state" type="xsd:string" minOccurs="0" /> + <xsd:element name="applied_rule_ids" type="xsd:string" minOccurs="0" /> + <xsd:element name="global_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_method" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_email" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="quote_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_virtual" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_group_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_note_notify" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_is_guest" type="xsd:string" minOccurs="0" /> + <xsd:element name="email_sent" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="coupon_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="protect_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_tax_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_subtotal_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_subtotal_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_subtotal_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_invoiced_cost" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_tax_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotal_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotal_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotal_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="can_ship_partially" type="xsd:string" minOccurs="0" /> + <xsd:element name="can_ship_partially_item" type="xsd:string" minOccurs="0" /> + <xsd:element name="edit_increment" type="xsd:string" minOccurs="0" /> + <xsd:element name="forced_do_shipment_with_invoice" type="xsd:string" minOccurs="0" /> + <xsd:element name="payment_authorization_expiration" type="xsd:string" minOccurs="0" /> + <xsd:element name="paypal_ipn_customer_notified" type="xsd:string" minOccurs="0" /> + <xsd:element name="quote_address_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="adjustment_negative" type="xsd:string" minOccurs="0" /> + <xsd:element name="adjustment_positive" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_adjustment_negative" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_adjustment_positive" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_subtotal_incl_tax" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_total_due" type="xsd:string" minOccurs="0" /> + <xsd:element name="payment_authorization_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotal_incl_tax" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_due" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_dob" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_middlename" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_prefix" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_suffix" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_taxvat" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_description" type="xsd:string" minOccurs="0" /> + <xsd:element name="ext_customer_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="ext_order_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="hold_before_state" type="xsd:string" minOccurs="0" /> + <xsd:element name="hold_before_status" type="xsd:string" minOccurs="0" /> + <xsd:element name="original_increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="relation_child_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="relation_child_real_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="relation_parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="relation_parent_real_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="x_forwarded_for" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_note" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_item_count" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_gender" type="xsd:string" minOccurs="0" /> + <xsd:element name="hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_hidden_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="hidden_tax_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_hidden_tax_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="hidden_tax_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_hidden_tax_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_incl_tax" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_incl_tax" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_customer_balance_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_balance_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_customer_balance_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_balance_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_customer_balance_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_balance_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="bs_customer_bal_total_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="customer_bal_total_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_cards" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_gift_cards_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_cards_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_gift_cards_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_cards_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_gift_cards_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_cards_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="reward_points_balance" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_reward_currency_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="reward_currency_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_rwrd_crrncy_amt_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="rwrd_currency_amount_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_rwrd_crrncy_amnt_refnded" type="xsd:string" minOccurs="0" /> + <xsd:element name="rwrd_crrncy_amnt_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="reward_points_balance_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="reward_points_balance_refund" type="xsd:string" minOccurs="0" /> + <xsd:element name="reward_salesrule_points" type="xsd:string" minOccurs="0" /> + <xsd:element name="firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="telephone" type="xsd:string" minOccurs="0" /> + <xsd:element name="postcode" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderListEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderListEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderAddressEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="address_type" type="xsd:string" minOccurs="0" /> + <xsd:element name="firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="company" type="xsd:string" minOccurs="0" /> + <xsd:element name="street" type="xsd:string" minOccurs="0" /> + <xsd:element name="city" type="xsd:string" minOccurs="0" /> + <xsd:element name="region" type="xsd:string" minOccurs="0" /> + <xsd:element name="postcode" type="xsd:string" minOccurs="0" /> + <xsd:element name="country_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="telephone" type="xsd:string" minOccurs="0" /> + <xsd:element name="fax" type="xsd:string" minOccurs="0" /> + <xsd:element name="region_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="address_id" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderItemEntity"> + <xsd:sequence> + <xsd:element name="item_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="quote_item_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="product_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="product_type" type="xsd:string" minOccurs="0" /> + <xsd:element name="product_options" type="xsd:string" minOccurs="0" /> + <xsd:element name="weight" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_virtual" type="xsd:string" minOccurs="0" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="applied_rule_ids" type="xsd:string" minOccurs="0" /> + <xsd:element name="free_shipping" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_qty_decimal" type="xsd:string" minOccurs="0" /> + <xsd:element name="no_discount" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty_canceled" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty_ordered" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty_shipped" type="xsd:string" minOccurs="0" /> + <xsd:element name="cost" type="xsd:string" minOccurs="0" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_price" type="xsd:string" minOccurs="0" /> + <xsd:element name="original_price" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_original_price" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_percent" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_percent" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="amount_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_amount_refunded" type="xsd:string" minOccurs="0" /> + <xsd:element name="row_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_row_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="row_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_row_invoiced" type="xsd:string" minOccurs="0" /> + <xsd:element name="row_weight" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message" type="xsd:string" minOccurs="0" /> + <xsd:element name="gift_message_available" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_before_discount" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_before_discount" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_applied" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_applied_row_amnt" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderItemEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderItemEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="orderItemIdQty"> + <xsd:sequence> + <xsd:element name="order_item_id" type="xsd:int" /> + <xsd:element name="qty" type="xsd:double" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="orderItemIdQtyArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:orderItemIdQty" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderPaymentEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="amount_ordered" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_amount_ordered" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="method" type="xsd:string" minOccurs="0" /> + <xsd:element name="po_number" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_type" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_number_enc" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_last4" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_owner" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_exp_month" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_exp_year" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_ss_start_month" type="xsd:string" minOccurs="0" /> + <xsd:element name="cc_ss_start_year" type="xsd:string" minOccurs="0" /> + <xsd:element name="payment_id" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderStatusHistoryEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_customer_notified" type="xsd:string" minOccurs="0" /> + <xsd:element name="status" type="xsd:string" minOccurs="0" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderStatusHistoryEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderStatusHistoryEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_address_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="total_qty" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="items" type="typens:salesOrderShipmentItemEntityArray" minOccurs="0" /> + <xsd:element name="tracks" type="typens:salesOrderShipmentTrackEntityArray" minOccurs="0" /> + <xsd:element name="comments" type="typens:salesOrderShipmentCommentEntityArray" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderShipmentEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentCommentEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_customer_notified" type="xsd:string" minOccurs="0" /> + <xsd:element name="comment_id" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentCommentEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderShipmentCommentEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentTrackEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="carrier_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="title" type="xsd:string" minOccurs="0" /> + <xsd:element name="number" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="track_id" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentTrackEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderShipmentTrackEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentItemEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_item_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="product_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="weight" type="xsd:string" minOccurs="0" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty" type="xsd:string" minOccurs="0" /> + <xsd:element name="item_id" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderShipmentItemEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderShipmentItemEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderInvoiceEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="global_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_currency_code" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_to_base_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="store_to_order_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_to_global_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_to_order_rate" type="xsd:string" minOccurs="0" /> + <xsd:element name="subtotal" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_subtotal" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_grand_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_discount_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_shipping_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_address_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_firstname" type="xsd:string" minOccurs="0" /> + <xsd:element name="billing_lastname" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="state" type="xsd:string" minOccurs="0" /> + <xsd:element name="grand_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="invoice_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="items" type="typens:salesOrderInvoiceItemEntityArray" minOccurs="0" /> + <xsd:element name="comments" type="typens:salesOrderInvoiceCommentEntityArray" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderInvoiceEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderInvoiceEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderInvoiceItemEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_applied" type="xsd:string" minOccurs="0" /> + <xsd:element name="qty" type="xsd:string" minOccurs="0" /> + <xsd:element name="cost" type="xsd:string" minOccurs="0" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" /> + <xsd:element name="tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="row_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_price" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_tax_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_row_total" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_applied_row_amnt" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_applied_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <xsd:element name="weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_disposition" type="xsd:string" minOccurs="0" /> + <xsd:element name="base_weee_tax_row_disposition" type="xsd:string" minOccurs="0" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" /> + <xsd:element name="order_item_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="product_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="item_id" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderInvoiceItemEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderInvoiceItemEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderInvoiceCommentEntity"> + <xsd:sequence> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_active" type="xsd:string" minOccurs="0" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" /> + <xsd:element name="is_customer_notified" type="xsd:string" minOccurs="0" /> + <xsd:element name="comment_id" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderInvoiceCommentEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderInvoiceCommentEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderCreditmemoEntity"> + <xsd:sequence> + <xsd:element name="updated_at" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="increment_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="transaction_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="global_currency_code" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_currency_code" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="order_currency_code" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="store_currency_code" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="cybersource_token" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="invoice_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="billing_address_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="shipping_address_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="state" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="creditmemo_status" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="email_sent" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="order_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="shipping_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_adjustment_positive" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_grand_total" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="adjustment" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="subtotal" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="discount_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_subtotal" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_adjustment" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_to_global_rate" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="store_to_base_rate" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_shipping_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="adjustment_negative" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="subtotal_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="shipping_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_subtotal_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_adjustment_negative" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="grand_total" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_discount_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_to_order_rate" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="store_to_order_rate" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_shipping_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="adjustment_positive" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="store_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="hidden_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_hidden_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="shipping_hidden_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_shipping_hidden_tax_amnt" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="shipping_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_shipping_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_customer_balance_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="customer_balance_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="bs_customer_bal_total_refunded" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="customer_bal_total_refunded" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_gift_cards_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gift_cards_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_base_price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_items_base_price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_items_price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_card_base_price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_card_price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_base_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_items_base_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_items_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_card_base_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="gw_card_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_reward_currency_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="reward_currency_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="reward_points_balance" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="reward_points_balance_refund" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="creditmemo_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="items" type="typens:salesOrderCreditmemoItemEntityArray" minOccurs="0" maxOccurs="1" /> + <xsd:element name="comments" type="typens:salesOrderCreditmemoCommentEntityArray" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderCreditmemoEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderCreditmemoEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderCreditmemoItemEntity"> + <xsd:sequence> + <xsd:element name="item_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_weee_tax_row_disposition" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_weee_tax_applied_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="weee_tax_row_disposition" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_row_total" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="discount_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="row_total" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="weee_tax_applied_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_discount_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_weee_tax_disposition" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="price_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="weee_tax_disposition" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_price_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="qty" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_cost" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_weee_tax_applied_row_amount" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="price" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_row_total_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="row_total_incl_tax" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="product_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="order_item_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="additional_data" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="description" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="weee_tax_applied" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="sku" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="name" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="hidden_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1"/> + <xsd:element name="base_hidden_tax_amount" type="xsd:string" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderCreditmemoItemEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderCreditmemoItemEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderCreditmemoCommentEntity"> + <xsd:sequence> + <xsd:element name="parent_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="created_at" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_customer_notified" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="comment_id" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="is_visible_on_front" type="xsd:string" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderCreditmemoCommentEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:salesOrderCreditmemoCommentEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="salesOrderCreditmemoData"> + <xsd:sequence> + <xsd:element name="qtys" type="typens:orderItemIdQtyArray" minOccurs="0" maxOccurs="1"/> + <xsd:element name="shipping_amount" type="xsd:double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="adjustment_positive" type="xsd:double" minOccurs="0" maxOccurs="1"/> + <xsd:element name="adjustment_negative" type="xsd:double" minOccurs="0" maxOccurs="1"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="salesOrderListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="filters" type="typens:filters" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderListEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderAddCommentRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="status" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="comment" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="notify" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderAddCommentResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderHoldRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderHoldResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderUnholdRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderUnholdResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCancelRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCancelResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="filters" type="typens:filters" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderShipmentEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="shipmentIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderShipmentEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="itemsQty" type="typens:orderItemIdQtyArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="comment" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="email" type="xsd:int" /> + <xsd:element minOccurs="1" maxOccurs="1" name="includeComment" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentAddTrackRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="shipmentIncrementId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="carrier" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="title" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="trackNumber" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentAddTrackResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentRemoveTrackRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="shipmentIncrementId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="trackId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentRemoveTrackResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentSendInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="shipmentIncrementId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="comment" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentSendInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentAddCommentRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="shipmentIncrementId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="comment" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="email" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="includeInEmail" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentAddCommentResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentGetCarriersRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderShipmentGetCarriersResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:associativeArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="filters" type="typens:filters" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderInvoiceEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="invoiceIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderInvoiceEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="orderIncrementId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="itemsQty" type="typens:orderItemIdQtyArray" /> + <xsd:element minOccurs="0" maxOccurs="1" name="comment" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="email" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="includeComment" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceAddCommentRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="invoiceIncrementId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="comment" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="email" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="includeComment" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceAddCommentResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceCaptureRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="invoiceIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceCaptureResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceVoidRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="invoiceIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceVoidResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceCancelRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="invoiceIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderInvoiceCancelResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="filters" type="typens:filters" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderCreditmemoEntityArray" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="creditmemoIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="typens:salesOrderCreditmemoEntity" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoCreateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="creditmemoIncrementId" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="creditmemoData" type="typens:salesOrderCreditmemoData" /> + <xsd:element minOccurs="0" maxOccurs="1" name="comment" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="notifyCustomer" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="includeComment" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="refundToStoreCreditAmount" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoCreateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoAddCommentRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="creditmemoIncrementId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="comment" type="xsd:string" /> + <xsd:element minOccurs="0" maxOccurs="1" name="notifyCustomer" type="xsd:int" /> + <xsd:element minOccurs="0" maxOccurs="1" name="includeComment" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoAddCommentResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:int" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoCancelRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string" /> + <xsd:element minOccurs="1" maxOccurs="1" name="creditmemoIncrementId" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="salesOrderCreditmemoCancelResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element minOccurs="1" maxOccurs="1" name="result" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + <wsdl:message name="salesOrderListRequest"> + <wsdl:part name="parameters" element="typens:salesOrderListRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderListResponse"> + <wsdl:part name="parameters" element="typens:salesOrderListResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInfoRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInfoResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderAddCommentRequest"> + <wsdl:part name="parameters" element="typens:salesOrderAddCommentRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderAddCommentResponse"> + <wsdl:part name="parameters" element="typens:salesOrderAddCommentResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderHoldRequest"> + <wsdl:part name="parameters" element="typens:salesOrderHoldRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderHoldResponse"> + <wsdl:part name="parameters" element="typens:salesOrderHoldResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderUnholdRequest"> + <wsdl:part name="parameters" element="typens:salesOrderUnholdRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderUnholdResponse"> + <wsdl:part name="parameters" element="typens:salesOrderUnholdResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCancelRequest"> + <wsdl:part name="parameters" element="typens:salesOrderCancelRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCancelResponse"> + <wsdl:part name="parameters" element="typens:salesOrderCancelResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentListRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentListRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentListResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentListResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentInfoRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentInfoResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentCreateRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentCreateResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentAddCommentRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentAddCommentRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentAddCommentResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentAddCommentResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentAddTrackRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentAddTrackRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentAddTrackResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentAddTrackResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentRemoveTrackRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentRemoveTrackRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentRemoveTrackResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentRemoveTrackResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentSendInfoRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentSendInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentSendInfoResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentSendInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentGetCarriersRequest"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentGetCarriersRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderShipmentGetCarriersResponse"> + <wsdl:part name="parameters" element="typens:salesOrderShipmentGetCarriersResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceListRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceListRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceListResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceListResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceInfoRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceInfoResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceCreateRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceCreateResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceAddCommentRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceAddCommentRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceAddCommentResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceAddCommentResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceCaptureRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceCaptureRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceCaptureResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceCaptureResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceVoidRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceVoidRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceVoidResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceVoidResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceCancelRequest"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceCancelRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderInvoiceCancelResponse"> + <wsdl:part name="parameters" element="typens:salesOrderInvoiceCancelResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoListRequest"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoListRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoListResponse"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoListResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoInfoRequest"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoInfoResponse"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoCreateRequest"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoCreateRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoCreateResponse"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoCreateResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoAddCommentRequest"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoAddCommentRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoAddCommentResponse"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoAddCommentResponseParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoCancelRequest"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoCancelRequestParam" /> + </wsdl:message> + <wsdl:message name="salesOrderCreditmemoCancelResponse"> + <wsdl:part name="parameters" element="typens:salesOrderCreditmemoCancelResponseParam" /> + </wsdl:message> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="salesOrderList"> + <wsdl:documentation>Retrieve list of orders by filters</wsdl:documentation> + <wsdl:input message="typens:salesOrderListRequest" /> + <wsdl:output message="typens:salesOrderListResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInfo"> + <wsdl:documentation>Retrieve order information</wsdl:documentation> + <wsdl:input message="typens:salesOrderInfoRequest" /> + <wsdl:output message="typens:salesOrderInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderAddComment"> + <wsdl:documentation>Add comment to order</wsdl:documentation> + <wsdl:input message="typens:salesOrderAddCommentRequest" /> + <wsdl:output message="typens:salesOrderAddCommentResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderHold"> + <wsdl:documentation>Hold order</wsdl:documentation> + <wsdl:input message="typens:salesOrderHoldRequest" /> + <wsdl:output message="typens:salesOrderHoldResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderUnhold"> + <wsdl:documentation>Unhold order</wsdl:documentation> + <wsdl:input message="typens:salesOrderUnholdRequest" /> + <wsdl:output message="typens:salesOrderUnholdResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderCancel"> + <wsdl:documentation>Cancel order</wsdl:documentation> + <wsdl:input message="typens:salesOrderCancelRequest" /> + <wsdl:output message="typens:salesOrderCancelResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentList"> + <wsdl:documentation>Retrieve list of shipments by filters</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentListRequest" /> + <wsdl:output message="typens:salesOrderShipmentListResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentInfo"> + <wsdl:documentation>Retrieve shipment information</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentInfoRequest" /> + <wsdl:output message="typens:salesOrderShipmentInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentCreate"> + <wsdl:documentation>Create new shipment for order</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentCreateRequest" /> + <wsdl:output message="typens:salesOrderShipmentCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentAddComment"> + <wsdl:documentation>Add new comment to shipment</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentAddCommentRequest" /> + <wsdl:output message="typens:salesOrderShipmentAddCommentResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentAddTrack"> + <wsdl:documentation>Add new tracking number</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentAddTrackRequest" /> + <wsdl:output message="typens:salesOrderShipmentAddTrackResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentRemoveTrack"> + <wsdl:documentation>Remove tracking number</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentRemoveTrackRequest" /> + <wsdl:output message="typens:salesOrderShipmentRemoveTrackResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentSendInfo"> + <wsdl:documentation>Send shipment info</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentSendInfoRequest" /> + <wsdl:output message="typens:salesOrderShipmentSendInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentGetCarriers"> + <wsdl:documentation>Retrieve list of allowed carriers for order</wsdl:documentation> + <wsdl:input message="typens:salesOrderShipmentGetCarriersRequest" /> + <wsdl:output message="typens:salesOrderShipmentGetCarriersResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceList"> + <wsdl:documentation>Retrieve list of invoices by filters</wsdl:documentation> + <wsdl:input message="typens:salesOrderInvoiceListRequest" /> + <wsdl:output message="typens:salesOrderInvoiceListResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceInfo"> + <wsdl:documentation>Retrieve invoice information</wsdl:documentation> + <wsdl:input message="typens:salesOrderInvoiceInfoRequest" /> + <wsdl:output message="typens:salesOrderInvoiceInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceCreate"> + <wsdl:documentation>Create new invoice for order</wsdl:documentation> + <wsdl:input message="typens:salesOrderInvoiceCreateRequest" /> + <wsdl:output message="typens:salesOrderInvoiceCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceAddComment"> + <wsdl:documentation>Add new comment to shipment</wsdl:documentation> + <wsdl:input message="typens:salesOrderInvoiceAddCommentRequest" /> + <wsdl:output message="typens:salesOrderInvoiceAddCommentResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceCapture"> + <wsdl:documentation>Capture invoice</wsdl:documentation> + <wsdl:input message="typens:salesOrderInvoiceCaptureRequest" /> + <wsdl:output message="typens:salesOrderInvoiceCaptureResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceVoid"> + <wsdl:documentation>Void invoice</wsdl:documentation> + <wsdl:input message="typens:salesOrderInvoiceVoidRequest" /> + <wsdl:output message="typens:salesOrderInvoiceVoidResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceCancel"> + <wsdl:documentation>Cancel invoice</wsdl:documentation> + <wsdl:input message="typens:salesOrderInvoiceCancelRequest" /> + <wsdl:output message="typens:salesOrderInvoiceCancelResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoList"> + <wsdl:documentation>Retrieve list of creditmemos by filters</wsdl:documentation> + <wsdl:input message="typens:salesOrderCreditmemoListRequest" /> + <wsdl:output message="typens:salesOrderCreditmemoListResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoInfo"> + <wsdl:documentation>Retrieve creditmemo information</wsdl:documentation> + <wsdl:input message="typens:salesOrderCreditmemoInfoRequest" /> + <wsdl:output message="typens:salesOrderCreditmemoInfoResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoCreate"> + <wsdl:documentation>Create new creditmemo for order</wsdl:documentation> + <wsdl:input message="typens:salesOrderCreditmemoCreateRequest" /> + <wsdl:output message="typens:salesOrderCreditmemoCreateResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoAddComment"> + <wsdl:documentation>Add new comment to creditmemo</wsdl:documentation> + <wsdl:input message="typens:salesOrderCreditmemoAddCommentRequest" /> + <wsdl:output message="typens:salesOrderCreditmemoAddCommentResponse" /> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoCancel"> + <wsdl:documentation>Cancel creditmemo</wsdl:documentation> + <wsdl:input message="typens:salesOrderCreditmemoCancelRequest" /> + <wsdl:output message="typens:salesOrderCreditmemoCancelResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="salesOrderList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderAddComment"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderHold"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderUnhold"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderCancel"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentAddComment"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentAddTrack"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentRemoveTrack"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentSendInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderShipmentGetCarriers"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceAddComment"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceCapture"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceVoid"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderInvoiceCancel"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoCreate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoAddComment"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="salesOrderCreditmemoCancel"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="{{var wsdl.name}}Service"> + <wsdl:port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php index c9a841d36f9..85dff9eccc9 100644 --- a/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php +++ b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag.php @@ -72,6 +72,8 @@ class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_Authorization $authSession * @param array $data @@ -89,12 +91,14 @@ class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_Authorization $authSession, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); if (isset($data['helpers'])) { diff --git a/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php index 857a7fa2702..b8e88378574 100644 --- a/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php +++ b/app/code/core/Mage/Tag/Block/Adminhtml/Catalog/Product/Edit/Tab/Tag/Customer.php @@ -71,7 +71,9 @@ class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer * @param Mage_Core_Model_Session $session * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController - * @param Mage_Core_Model_Factory_Helper $helperFactory, + * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem, * @param Mage_Core_Model_Authorization $authSession * @param array $data @@ -90,12 +92,15 @@ class Mage_Tag_Block_Adminhtml_Catalog_Product_Edit_Tab_Tag_Customer Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_Authorization $authSession, array $data = array() ) { - parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, $session, - $storeConfig, $frontController, $helperFactory, $filesystem, $data); + parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); if (isset($data['helpers'])) { $this->_helpers = $data['helpers']; diff --git a/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php index 9b131ff2b87..355bb0961b4 100644 --- a/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php +++ b/app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php @@ -53,7 +53,7 @@ class Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag extends Mage_Backend_Block_ protected $_authSession; /** - * Class constructor + * Constructor * * @param Mage_Core_Controller_Request_Http $request * @param Mage_Core_Model_Layout $layout @@ -66,6 +66,8 @@ class Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag extends Mage_Backend_Block_ * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Core_Model_Authorization $authSession * @param array $data @@ -83,12 +85,15 @@ class Mage_Tag_Block_Adminhtml_Customer_Edit_Tab_Tag extends Mage_Backend_Block_ Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Core_Model_Authorization $authSession, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data); + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data + ); $this->_authSession = $authSession; if (isset($data['helpers'])) { diff --git a/app/code/core/Mage/Tag/Model/Api.php b/app/code/core/Mage/Tag/Model/Api.php new file mode 100644 index 00000000000..b3d8d716ec0 --- /dev/null +++ b/app/code/core/Mage/Tag/Model/Api.php @@ -0,0 +1,245 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Tag + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Product Tag API + * + * @category Mage + * @package Mage_Tag + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Tag_Model_Api extends Mage_Catalog_Model_Api_Resource +{ + /** + * Retrieve list of tags for specified product + * + * @param int $productId + * @param string|int $store + * @return array + */ + public function items($productId, $store = null) + { + $result = array(); + // fields list to return + $fieldsForResult = array('tag_id', 'name'); + + /** @var $product Mage_Catalog_Model_Product */ + $product = Mage::getModel('Mage_Catalog_Model_Product')->load($productId); + if (!$product->getId()) { + $this->_fault('product_not_exists'); + } + + /** @var $tags Mage_Tag_Model_Resource_Tag_Collection */ + $tags = Mage::getModel('Mage_Tag_Model_Tag')->getCollection()->joinRel()->addProductFilter($productId); + if ($store) { + $tags->addStoreFilter($this->_getStoreId($store)); + } + + /** @var $tag Mage_Tag_Model_Tag */ + foreach ($tags as $tag) { + $result[$tag->getId()] = $tag->toArray($fieldsForResult); + } + + return $result; + } + + /** + * Retrieve tag info as array('name'-> .., 'status' => .., + * 'base_popularity' => .., 'products' => array($productId => $popularity, ...)) + * + * @param int $tagId + * @param string|int $store + * @return array + */ + public function info($tagId, $store) + { + $result = array(); + $storeId = $this->_getStoreId($store); + /** @var $tag Mage_Tag_Model_Tag */ + $tag = Mage::getModel('Mage_Tag_Model_Tag')->setStoreId($storeId)->setAddBasePopularity()->load($tagId); + if (!$tag->getId()) { + $this->_fault('tag_not_exists'); + } + $result['status'] = $tag->getStatus(); + $result['name'] = $tag->getName(); + $result['base_popularity'] = (is_numeric($tag->getBasePopularity())) ? $tag->getBasePopularity() : 0; + // retrieve array($productId => $popularity, ...) + $result['products'] = array(); + $relatedProductsCollection = $tag->getEntityCollection()->addTagFilter($tagId) + ->addStoreFilter($storeId)->addPopularity($tagId); + foreach ($relatedProductsCollection as $product) { + $result['products'][$product->getId()] = $product->getPopularity(); + } + + return $result; + } + + /** + * Add tag(s) to product. + * Return array of added/updated tags as array($tagName => $tagId, ...) + * + * @param array $data + * @return array + */ + public function add($data) + { + $data = $this->_prepareDataForAdd($data); + /** @var $product Mage_Catalog_Model_Product */ + $product = Mage::getModel('Mage_Catalog_Model_Product')->load($data['product_id']); + if (!$product->getId()) { + $this->_fault('product_not_exists'); + } + /** @var $customer Mage_Customer_Model_Customer */ + $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($data['customer_id']); + if (!$customer->getId()) { + $this->_fault('customer_not_exists'); + } + $storeId = $this->_getStoreId($data['store']); + + try { + /** @var $tag Mage_Tag_Model_Tag */ + $tag = Mage::getModel('Mage_Tag_Model_Tag'); + $tagHelper = Mage::helper('Mage_Tag_Helper_Data'); + $tagNamesArr = $tagHelper->cleanTags($tagHelper->extractTags($data['tag'])); + foreach ($tagNamesArr as $tagName) { + // unset previously added tag data + $tag->unsetData(); + $tag->loadByName($tagName); + if (!$tag->getId()) { + $tag->setName($tagName) + ->setFirstCustomerId($customer->getId()) + ->setFirstStoreId($storeId) + ->setStatus($tag->getPendingStatus()) + ->save(); + } + $tag->saveRelation($product->getId(), $customer->getId(), $storeId); + $result[$tagName] = $tag->getId(); + } + } catch (Mage_Core_Exception $e) { + $this->_fault('save_error', $e->getMessage()); + } + + return $result; + } + + /** + * Change existing tag information + * + * @param int $tagId + * @param array $data + * @param string|int $store + * @return bool + */ + public function update($tagId, $data, $store) + { + $data = $this->_prepareDataForUpdate($data); + $storeId = $this->_getStoreId($store); + /** @var $tag Mage_Tag_Model_Tag */ + $tag = Mage::getModel('Mage_Tag_Model_Tag')->setStoreId($storeId)->setAddBasePopularity()->load($tagId); + if (!$tag->getId()) { + $this->_fault('tag_not_exists'); + } + + // store should be set for 'base_popularity' to be saved in Mage_Tag_Model_Resource_Tag::_afterSave() + $tag->setStore($storeId); + if (isset($data['base_popularity'])) { + $tag->setBasePopularity($data['base_popularity']); + } + if (isset($data['name'])) { + $tag->setName(trim($data['name'])); + } + if (isset($data['status'])) { + // validate tag status + if (!in_array($data['status'], array( + $tag->getApprovedStatus(), $tag->getPendingStatus(), $tag->getDisabledStatus()))) { + $this->_fault('invalid_data'); + } + $tag->setStatus($data['status']); + } + + try { + $tag->save(); + } catch (Mage_Core_Exception $e) { + $this->_fault('save_error', $e->getMessage()); + } + + return true; + } + + /** + * Remove existing tag + * + * @param int $tagId + * @return bool + */ + public function remove($tagId) + { + /** @var $tag Mage_Tag_Model_Tag */ + $tag = Mage::getModel('Mage_Tag_Model_Tag')->load($tagId); + if (!$tag->getId()) { + $this->_fault('tag_not_exists'); + } + try { + $tag->delete(); + } catch (Mage_Core_Exception $e) { + $this->_fault('remove_error', $e->getMessage()); + } + + return true; + } + + /** + * Check data before add + * + * @param array $data + * @return array + */ + protected function _prepareDataForAdd($data) + { + if (!isset($data['product_id']) or !isset($data['tag']) + or !isset($data['customer_id']) or !isset($data['store'])) { + $this->_fault('invalid_data'); + } + + return $data; + } + + /** + * Check data before update + * + * @param $data + * @return + */ + protected function _prepareDataForUpdate($data) + { + // $data should contain at least one field to change + if ( !(isset($data['name']) or isset($data['status']) or isset($data['base_popularity']))) { + $this->_fault('invalid_data'); + } + + return $data; + } +} diff --git a/app/code/core/Mage/Tag/Model/Api/V2.php b/app/code/core/Mage/Tag/Model/Api/V2.php new file mode 100644 index 00000000000..75650247993 --- /dev/null +++ b/app/code/core/Mage/Tag/Model/Api/V2.php @@ -0,0 +1,109 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Tag + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Product Tag API + * + * @category Mage + * @package Mage_Tag + * @author Magento Core Team <core@magentocommerce.com> + */ +class Mage_Tag_Model_Api_V2 extends Mage_Tag_Model_Api +{ + /** + * Retrieve list of tags for specified product as array of objects + * + * @param int $productId + * @param string|int $store + * @return array + */ + public function items($productId, $store = null) + { + $result = parent::items($productId, $store); + foreach ($result as $key => $tag) { + $result[$key] = Mage::helper('Mage_Api_Helper_Data')->wsiArrayPacker($tag); + } + return array_values($result); + } + + /** + * Add tag(s) to product. + * Return array of objects + * + * @param array $data + * @return array + */ + public function add($data) + { + $result = array(); + foreach (parent::add($data) as $key => $value) { + $result[] = array('key' => $key, 'value' => $value); + } + + return $result; + } + + /** + * Retrieve tag info as object + * + * @param int $tagId + * @param string|int $store + * @return object + */ + public function info($tagId, $store) + { + $result = parent::info($tagId, $store); + $result = Mage::helper('Mage_Api_Helper_Data')->wsiArrayPacker($result); + foreach ($result->products as $key => $value) { + $result->products[$key] = array('key' => $key, 'value' => $value); + } + return $result; + } + + /** + * Convert data from object to array before add + * + * @param object $data + * @return array + */ + protected function _prepareDataForAdd($data) + { + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::_prepareDataForAdd($data); + } + + /** + * Convert data from object to array before update + * + * @param object $data + * @return array + */ + protected function _prepareDataForUpdate($data) + { + Mage::helper('Mage_Api_Helper_Data')->toArray($data); + return parent::_prepareDataForUpdate($data); + } +} diff --git a/app/code/core/Mage/Tag/etc/api.xml b/app/code/core/Mage/Tag/etc/api.xml new file mode 100644 index 00000000000..f8ca46a630d --- /dev/null +++ b/app/code/core/Mage/Tag/etc/api.xml @@ -0,0 +1,138 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Mage + * @package Mage_Tag + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<config> + <api> + <resources> + <catalog_product_tag translate="title" module="Mage_Tag"> + <title>Product Tag API</title> + <model>Mage_Tag_Model_Api</model> + <acl>catalog/product/tag</acl> + <methods> + <list translate="title" module="Mage_Tag"> + <title>Retrieve list of tags by product</title> + <method>items</method> + <acl>catalog/product/tag/list</acl> + </list> + <info translate="title" module="Mage_Tag"> + <title>Retrieve product tag info</title> + <acl>catalog/product/tag/info</acl> + </info> + <add translate="title" module="Mage_Tag"> + <title>Add tag(s) to product</title> + <acl>catalog/product/tag/add</acl> + </add> + <update translate="title" module="Mage_Tag"> + <title>Update product tag</title> + <acl>catalog/product/tag/update</acl> + </update> + <remove translate="title" module="Mage_Tag"> + <title>Remove product tag</title> + <acl>catalog/product/tag/remove</acl> + </remove> + </methods> + <faults module="Mage_Tag"> + <store_not_exists> + <code>101</code> + <message>Requested store does not exist.</message> + </store_not_exists> + <product_not_exists> + <code>102</code> + <message>Requested product does not exist.</message> + </product_not_exists> + <customer_not_exists> + <code>103</code> + <message>Requested customer does not exist.</message> + </customer_not_exists> + <tag_not_exists> + <code>104</code> + <message>Requested tag does not exist.</message> + </tag_not_exists> + <invalid_data> + <code>105</code> + <message>Provided data is invalid.</message> + </invalid_data> + <save_error> + <code>106</code> + <message>Error occurred while saving tag. Details are in error message.</message> + </save_error> + <remove_error> + <code>107</code> + <message>Error occurred while removing tag. Details are in error message.</message> + </remove_error> + </faults> + </catalog_product_tag> + </resources> + <resources_alias> + <product_tag>catalog_product_tag</product_tag> + </resources_alias> + <v2> + <resources_function_prefix> + <product_tag>catalogProductTag</product_tag> + </resources_function_prefix> + </v2> + <rest> + <mapping> + <product_tag> + <post> + <method>add</method> + </post> + <delete> + <method>remove</method> + </delete> + </product_tag> + </mapping> + </rest> + <acl> + <resources> + <catalog> + <product> + <tag translate="title" module="Mage_Tag"> + <title>Tag</title> + <sort_order>103</sort_order> + <list translate="title" module="Mage_Tag"> + <title>List</title> + </list> + <info translate="title" module="Mage_Tag"> + <title>Info</title> + </info> + <add translate="title" module="Mage_Tag"> + <title>Add</title> + </add> + <update translate="title" module="Mage_Tag"> + <title>Update</title> + </update> + <remove translate="title" module="Mage_Tag"> + <title>Remove</title> + </remove> + </tag> + </product> + </catalog> + </resources> + </acl> + </api> +</config> diff --git a/app/code/core/Mage/Tag/etc/wsdl.xml b/app/code/core/Mage/Tag/etc/wsdl.xml new file mode 100644 index 00000000000..c7d114736c7 --- /dev/null +++ b/app/code/core/Mage/Tag/etc/wsdl.xml @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8"?> +<definitions xmlns:typens="urn:{{var wsdl.name}}" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> + <types> + <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento"> + <import namespace="http://schemas.xmlsoap.org/soap/encoding/" schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" /> + <complexType name="catalogProductTagListEntity"> + <all> + <element name="tag_id" type="xsd:string" minOccurs="1" /> + <element name="name" type="xsd:string" minOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductTagListEntityArray"> + <complexContent> + <restriction base="soapenc:Array"> + <attribute ref="soapenc:arrayType" wsdl:arrayType="typens:catalogProductTagListEntity[]" /> + </restriction> + </complexContent> + </complexType> + <complexType name="catalogProductTagAddEntity"> + <all> + <element name="tag" type="xsd:string" minOccurs="1" /> + <element name="product_id" type="xsd:string" minOccurs="1" /> + <element name="customer_id" type="xsd:string" minOccurs="1" /> + <element name="store" type="xsd:string" minOccurs="1" /> + </all> + </complexType> + <complexType name="catalogProductTagUpdateEntity"> + <all> + <element name="name" type="xsd:string" minOccurs="0" /> + <element name="status" type="xsd:string" minOccurs="0" /> + <element name="base_popularity" type="xsd:string" minOccurs="0" /> + </all> + </complexType> + <complexType name="catalogProductTagInfoEntity"> + <all> + <element name="name" type="xsd:string" minOccurs="1" /> + <element name="status" type="xsd:string" minOccurs="1" /> + <element name="base_popularity" type="xsd:string" minOccurs="1" /> + <element name="products" type="typens:associativeArray" minOccurs="1" /> + </all> + </complexType> + </schema> + </types> + + <message name="catalogProductTagListRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="productId" type="xsd:string" /> + <part name="store" type="xsd:string" /> + </message> + <message name="catalogProductTagListResponse"> + <part name="result" type="typens:catalogProductTagListEntityArray" /> + </message> + <message name="catalogProductTagInfoRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="tagId" type="xsd:string" /> + <part name="store" type="xsd:string" /> + </message> + <message name="catalogProductTagInfoResponse"> + <part name="result" type="typens:catalogProductTagInfoEntity" /> + </message> + <message name="catalogProductTagAddRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="data" type="typens:catalogProductTagAddEntity" /> + </message> + <message name="catalogProductTagAddResponse"> + <part name="result" type="typens:associativeArray" /> + </message> + <message name="catalogProductTagUpdateRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="tagId" type="xsd:string" /> + <part name="data" type="typens:catalogProductTagUpdateEntity" /> + <part name="store" type="xsd:string" /> + </message> + <message name="catalogProductTagUpdateResponse"> + <part name="result" type="xsd:boolean" /> + </message> + <message name="catalogProductTagRemoveRequest"> + <part name="sessionId" type="xsd:string" /> + <part name="tagId" type="xsd:string" /> + </message> + <message name="catalogProductTagRemoveResponse"> + <part name="result" type="xsd:boolean" /> + </message> + + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogProductTagList"> + <documentation>Retrieve list of tags by product</documentation> + <input message="typens:catalogProductTagListRequest" /> + <output message="typens:catalogProductTagListResponse" /> + </operation> + </portType> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogProductTagInfo"> + <documentation>Retrieve product tag info</documentation> + <input message="typens:catalogProductTagInfoRequest" /> + <output message="typens:catalogProductTagInfoResponse" /> + </operation> + </portType> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogProductTagAdd"> + <documentation>Add tag(s) to product</documentation> + <input message="typens:catalogProductTagAddRequest" /> + <output message="typens:catalogProductTagAddResponse" /> + </operation> + </portType> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogProductTagUpdate"> + <documentation>Update product tag</documentation> + <input message="typens:catalogProductTagUpdateRequest" /> + <output message="typens:catalogProductTagUpdateResponse" /> + </operation> + </portType> + <portType name="{{var wsdl.handler}}PortType"> + <operation name="catalogProductTagRemove"> + <documentation>Remove product tag</documentation> + <input message="typens:catalogProductTagRemoveRequest" /> + <output message="typens:catalogProductTagRemoveResponse" /> + </operation> + </portType> + + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="catalogProductTagList"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="catalogProductTagInfo"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="catalogProductTagAdd"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="catalogProductTagUpdate"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + <binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> + <operation name="catalogProductTagRemove"> + <soap:operation soapAction="urn:{{var wsdl.handler}}Action" /> + <input> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </input> + <output> + <soap:body namespace="urn:{{var wsdl.name}}" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> + </output> + </operation> + </binding> + + <service name="{{var wsdl.name}}Service"> + <port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </port> + </service> +</definitions> diff --git a/app/code/core/Mage/Tag/etc/wsi.xml b/app/code/core/Mage/Tag/etc/wsi.xml new file mode 100644 index 00000000000..615e2a44583 --- /dev/null +++ b/app/code/core/Mage/Tag/etc/wsi.xml @@ -0,0 +1,262 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:typens="urn:{{var wsdl.name}}" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" + xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" + name="{{var wsdl.name}}" + targetNamespace="urn:{{var wsdl.name}}"> + + <wsdl:types> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}"> + <xsd:complexType name="catalogProductTagListEntity"> + <xsd:sequence> + <xsd:element name="tag_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTagListEntityArray"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" name="complexObjectArray" type="typens:catalogProductTagListEntity" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTagAddEntity"> + <xsd:sequence> + <xsd:element name="tag" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="product_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="customer_id" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="store" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTagUpdateEntity"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="status" type="xsd:string" minOccurs="0" maxOccurs="1" /> + <xsd:element name="base_popularity" type="xsd:string" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + <xsd:complexType name="catalogProductTagInfoEntity"> + <xsd:sequence> + <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="status" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="base_popularity" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="products" type="typens:associativeArray" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="catalogProductTagListRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="sessionId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="productId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="store" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagListResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="result" type="typens:catalogProductTagListEntityArray" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagInfoRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="sessionId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="tagId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="store" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagInfoResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="result" type="typens:catalogProductTagInfoEntity" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagAddRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="sessionId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="data" type="typens:catalogProductTagAddEntity" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagAddResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="result" type="typens:associativeArray" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagUpdateRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="sessionId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="tagId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="data" type="typens:catalogProductTagUpdateEntity" minOccurs="1" maxOccurs="1" /> + <xsd:element name="store" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagUpdateResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="result" type="xsd:int" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagRemoveRequestParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="sessionId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + <xsd:element name="tagId" type="xsd:string" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="catalogProductTagRemoveResponseParam"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="result" type="xsd:int" minOccurs="1" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:schema> + </wsdl:types> + + <wsdl:message name="catalogProductTagListRequest"> + <wsdl:part name="parameters" element="typens:catalogProductTagListRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagListResponse"> + <wsdl:part name="parameters" element="typens:catalogProductTagListResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagInfoRequest"> + <wsdl:part name="parameters" element="typens:catalogProductTagInfoRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagInfoResponse"> + <wsdl:part name="parameters" element="typens:catalogProductTagInfoResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagAddRequest"> + <wsdl:part name="parameters" element="typens:catalogProductTagAddRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagAddResponse"> + <wsdl:part name="parameters" element="typens:catalogProductTagAddResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagUpdateRequest"> + <wsdl:part name="parameters" element="typens:catalogProductTagUpdateRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagUpdateResponse"> + <wsdl:part name="parameters" element="typens:catalogProductTagUpdateResponseParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagRemoveRequest"> + <wsdl:part name="parameters" element="typens:catalogProductTagRemoveRequestParam" /> + </wsdl:message> + <wsdl:message name="catalogProductTagRemoveResponse"> + <wsdl:part name="parameters" element="typens:catalogProductTagRemoveResponseParam" /> + </wsdl:message> + + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogProductTagList"> + <wsdl:documentation>Retrieve list of tags by product</wsdl:documentation> + <wsdl:input message="typens:catalogProductTagListRequest" /> + <wsdl:output message="typens:catalogProductTagListResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogProductTagInfo"> + <wsdl:documentation>Retrieve product tag info</wsdl:documentation> + <wsdl:input message="typens:catalogProductTagInfoRequest" /> + <wsdl:output message="typens:catalogProductTagInfoResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogProductTagAdd"> + <wsdl:documentation>Add tag(s) to product</wsdl:documentation> + <wsdl:input message="typens:catalogProductTagAddRequest" /> + <wsdl:output message="typens:catalogProductTagAddResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogProductTagUpdate"> + <wsdl:documentation>Update product tag</wsdl:documentation> + <wsdl:input message="typens:catalogProductTagUpdateRequest" /> + <wsdl:output message="typens:catalogProductTagUpdateResponse" /> + </wsdl:operation> + </wsdl:portType> + <wsdl:portType name="{{var wsdl.handler}}PortType"> + <wsdl:operation name="catalogProductTagRemove"> + <wsdl:documentation>Remove product tag</wsdl:documentation> + <wsdl:input message="typens:catalogProductTagRemoveRequest" /> + <wsdl:output message="typens:catalogProductTagRemoveResponse" /> + </wsdl:operation> + </wsdl:portType> + + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogProductTagList"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogProductTagInfo"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogProductTagAdd"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogProductTagUpdate"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:binding name="{{var wsdl.handler}}Binding" type="typens:{{var wsdl.handler}}PortType"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> + <wsdl:operation name="catalogProductTagRemove"> + <soap:operation soapAction="" /> + <wsdl:input> + <soap:body use="literal" /> + </wsdl:input> + <wsdl:output> + <soap:body use="literal" /> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + + <wsdl:service name="{{var wsdl.name}}Service"> + <wsdl:port name="{{var wsdl.handler}}Port" binding="typens:{{var wsdl.handler}}Binding"> + <soap:address location="{{var wsdl.url}}" /> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> diff --git a/app/code/core/Mage/Theme/Block/Adminhtml/System/Design/Theme/Edit/Tab/Css.php b/app/code/core/Mage/Theme/Block/Adminhtml/System/Design/Theme/Edit/Tab/Css.php index 9d695ad4fa6..e316a844e11 100644 --- a/app/code/core/Mage/Theme/Block/Adminhtml/System/Design/Theme/Edit/Tab/Css.php +++ b/app/code/core/Mage/Theme/Block/Adminhtml/System/Design/Theme/Edit/Tab/Css.php @@ -60,9 +60,11 @@ class Mage_Theme_Block_Adminhtml_System_Design_Theme_Edit_Tab_Css * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger + * @param Magento_Filesystem $filesystem * @param Magento_ObjectManager $objectManager * @param Mage_Theme_Model_Uploader_Service $uploaderService - * @param Magento_Filesystem $filesystem * @param array $data * * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -79,13 +81,15 @@ class Mage_Theme_Block_Adminhtml_System_Design_Theme_Edit_Tab_Css Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, + Magento_Filesystem $filesystem, Magento_ObjectManager $objectManager, Mage_Theme_Model_Uploader_Service $uploaderService, - Magento_Filesystem $filesystem, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); $this->_objectManager = $objectManager; $this->_uploaderService = $uploaderService; @@ -225,9 +229,8 @@ class Mage_Theme_Block_Adminhtml_System_Design_Theme_Edit_Tab_Css */ protected function _getGroupedFiles() { - $options = Mage::getConfig()->getOptions(); - $jsDir = $options->getJsDir(); - $codeDir = $options->getCodeDir(); + $jsDir = $this->_dirs->getDir(Mage_Core_Model_Dir::PUB_LIB); + $codeDir = $this->_dirs->getDir(Mage_Core_Model_Dir::MODULES); $groups = array(); $themes = array(); @@ -297,10 +300,9 @@ class Mage_Theme_Block_Adminhtml_System_Design_Theme_Edit_Tab_Css */ protected function _getGroup($filename) { - $options = Mage::getConfig()->getOptions(); - $designDir = $options->getDesignDir(); - $jsDir = $options->getJsDir(); - $codeDir = $options->getCodeDir(); + $designDir = $this->_dirs->getDir(Mage_Core_Model_Dir::THEMES); + $jsDir = $this->_dirs->getDir(Mage_Core_Model_Dir::PUB_LIB); + $codeDir = $this->_dirs->getDir(Mage_Core_Model_Dir::MODULES); $group = null; $theme = null; @@ -348,7 +350,7 @@ class Mage_Theme_Block_Adminhtml_System_Design_Theme_Edit_Tab_Css */ protected function _getThemeByFilename($filename) { - $designDir = Mage::getConfig()->getOptions()->getDesignDir(); + $designDir = $this->_dirs->getDir(Mage_Core_Model_Dir::THEMES); list(, $area, $package, $theme,) = explode('/', substr($filename, strlen($designDir)), 5); /** @var $collection Mage_Core_Model_Resource_Theme_Collection */ $collection = Mage::getModel('Mage_Core_Model_Resource_Theme_Collection'); @@ -364,8 +366,8 @@ class Mage_Theme_Block_Adminhtml_System_Design_Theme_Edit_Tab_Css protected function _getGroupLabels($themes) { $labels = array( - Mage::getConfig()->getOptions()->getJsDir() => $this->__('Library files'), - Mage::getConfig()->getOptions()->getCodeDir() => $this->__('Framework files') + $this->_dirs->getDir(Mage_Core_Model_Dir::PUB_LIB) => $this->__('Library files'), + $this->_dirs->getDir(Mage_Core_Model_Dir::MODULES) => $this->__('Framework files') ); foreach ($themes as $theme) { /** @var $theme Mage_Core_Model_Theme */ diff --git a/app/code/core/Mage/Usa/Block/Adminhtml/Dhl/Unitofmeasure.php b/app/code/core/Mage/Usa/Block/Adminhtml/Dhl/Unitofmeasure.php index af765b4529a..fe1b3ff9af1 100644 --- a/app/code/core/Mage/Usa/Block/Adminhtml/Dhl/Unitofmeasure.php +++ b/app/code/core/Mage/Usa/Block/Adminhtml/Dhl/Unitofmeasure.php @@ -77,6 +77,6 @@ class Mage_Usa_Block_Adminhtml_Dhl_Unitofmeasure extends Mage_Backend_Block_Syst */ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) { - return parent::_getElementHtml($element) . $this->renderView(); + return parent::_getElementHtml($element) . $this->_toHtml(); } } diff --git a/app/code/core/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/Resource.php b/app/code/core/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/Resource.php index 7ea5bd9ff7b..4c07225d798 100644 --- a/app/code/core/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/Resource.php +++ b/app/code/core/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/Resource.php @@ -64,6 +64,8 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_Resource extends Mage_Backend_Bl * @param Mage_Core_Model_Store_Config $storeConfig * @param Mage_Core_Controller_Varien_Front $frontController * @param Mage_Core_Model_Factory_Helper $helperFactory + * @param Mage_Core_Model_Dir $dirs + * @param Mage_Core_Model_Logger $logger * @param Magento_Filesystem $filesystem * @param Mage_Webapi_Model_Authorization_Config $authorizationConfig * @param Mage_Webapi_Model_Resource_Acl_Rule $ruleResource @@ -83,13 +85,15 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_Resource extends Mage_Backend_Bl Mage_Core_Model_Store_Config $storeConfig, Mage_Core_Controller_Varien_Front $frontController, Mage_Core_Model_Factory_Helper $helperFactory, + Mage_Core_Model_Dir $dirs, + Mage_Core_Model_Logger $logger, Magento_Filesystem $filesystem, Mage_Webapi_Model_Authorization_Config $authorizationConfig, Mage_Webapi_Model_Resource_Acl_Rule $ruleResource, array $data = array() ) { parent::__construct($request, $layout, $eventManager, $urlBuilder, $translator, $cache, $designPackage, - $session, $storeConfig, $frontController, $helperFactory, $filesystem, $data + $session, $storeConfig, $frontController, $helperFactory, $dirs, $logger, $filesystem, $data ); $this->_authorizationConfig = $authorizationConfig; $this->_ruleResource = $ruleResource; diff --git a/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation.php b/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation.php index 815036b8344..4aeb73cbd80 100644 --- a/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation.php +++ b/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation.php @@ -25,54 +25,24 @@ */ class Mage_Webapi_Controller_Dispatcher_Rest_Presentation { - /** @var Mage_Webapi_Model_Config_Rest */ - protected $_apiConfig; + /** @var Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Request */ + protected $_requestProcessor; - /** @var Mage_Webapi_Helper_Data */ - protected $_apiHelper; - - /** @var Mage_Webapi_Helper_Config */ - protected $_configHelper; - - /** @var Mage_Webapi_Controller_Request_Rest */ - protected $_request; - - /** @var Mage_Webapi_Controller_Response_Rest */ - protected $_response; - - /** @var Magento_Controller_Router_Route_Factory */ - protected $_routeFactory; - - /** @var Mage_Webapi_Controller_Response_Rest_RendererInterface */ - protected $_renderer; + /** @var Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Response */ + protected $_responseProcessor; /** * Initialize dependencies. * - * @param Mage_Webapi_Model_Config_Rest $apiConfig - * @param Mage_Webapi_Helper_Data $helper - * @param Mage_Webapi_Helper_Config $configHelper - * @param Mage_Webapi_Controller_Request_Factory $requestFactory - * @param Mage_Webapi_Controller_Response_Rest $response - * @param Mage_Webapi_Controller_Response_Rest_Renderer_Factory $rendererFactory - * @param Magento_Controller_Router_Route_Factory $routeFactory + * @param Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Request $requestPresentation + * @param Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Response $responsePresentation */ public function __construct( - Mage_Webapi_Model_Config_Rest $apiConfig, - Mage_Webapi_Helper_Data $helper, - Mage_Webapi_Helper_Config $configHelper, - Mage_Webapi_Controller_Request_Factory $requestFactory, - Mage_Webapi_Controller_Response_Rest $response, - Mage_Webapi_Controller_Response_Rest_Renderer_Factory $rendererFactory, - Magento_Controller_Router_Route_Factory $routeFactory + Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Request $requestPresentation, + Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Response $responsePresentation ) { - $this->_apiConfig = $apiConfig; - $this->_apiHelper = $helper; - $this->_configHelper = $configHelper; - $this->_request = $requestFactory->get(); - $this->_response = $response; - $this->_routeFactory = $routeFactory; - $this->_renderer = $rendererFactory->get(); + $this->_requestProcessor = $requestPresentation; + $this->_responseProcessor = $responsePresentation; } /** @@ -84,26 +54,7 @@ class Mage_Webapi_Controller_Dispatcher_Rest_Presentation */ public function fetchRequestData($controllerInstance, $action) { - $methodReflection = Mage_Webapi_Helper_Data::createMethodReflection($controllerInstance, $action); - $methodName = $this->_configHelper->getMethodNameWithoutVersionSuffix($methodReflection); - $bodyParamName = $this->_configHelper->getOperationBodyParamName($methodReflection); - $requestParams = array_merge( - $this->_request->getParams(), - array($bodyParamName => $this->_getRequestBody($methodName)) - ); - /** Convert names of ID and Parent ID params in request to those which are used in method interface. */ - $idArgumentName = $this->_configHelper->getOperationIdParamName($methodReflection); - $parentIdParamName = Mage_Webapi_Controller_Router_Route_Rest::PARAM_PARENT_ID; - $idParamName = Mage_Webapi_Controller_Router_Route_Rest::PARAM_ID; - if (isset($requestParams[$parentIdParamName]) && ($idArgumentName != $parentIdParamName)) { - $requestParams[$idArgumentName] = $requestParams[$parentIdParamName]; - unset($requestParams[$parentIdParamName]); - } elseif (isset($requestParams[$idParamName]) && ($idArgumentName != $idParamName)) { - $requestParams[$idArgumentName] = $requestParams[$idParamName]; - unset($requestParams[$idParamName]); - } - - return $this->_apiHelper->prepareMethodParams($controllerInstance, $action, $requestParams, $this->_apiConfig); + return $this->_requestProcessor->fetchRequestData($controllerInstance, $action); } /** @@ -114,121 +65,6 @@ class Mage_Webapi_Controller_Dispatcher_Rest_Presentation */ public function prepareResponse($method, $outputData = null) { - switch ($method) { - case Mage_Webapi_Controller_ActionAbstract::METHOD_CREATE: - /** @var $createdItem Mage_Core_Model_Abstract */ - $createdItem = $outputData; - $this->_response->setHeader('Location', $this->_getCreatedItemLocation($createdItem)); - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_GET: - // TODO: Implement fields filtration - $filteredData = $outputData; - $this->_render($filteredData); - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_LIST: - // TODO: Implement fields filtration - $filteredData = $outputData; - $this->_render($filteredData); - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_UPDATE: - // break is intentionally omitted - case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_CREATE: - // break is intentionally omitted - case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_DELETE: - $this->_response->setHttpResponseCode(Mage_Webapi_Controller_Response_Rest::HTTP_MULTI_STATUS); - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_UPDATE: - // break is intentionally omitted - case Mage_Webapi_Controller_ActionAbstract::METHOD_DELETE: - break; - } - $this->_renderMessages(); - } - - /** - * Render error and success messages. - */ - protected function _renderMessages() - { - if ($this->_response->getMessages()) { - $this->_render(array('messages' => $this->_response->getMessages())); - } - } - - /** - * Generate resource location. - * - * @param Mage_Core_Model_Abstract $createdItem - * @return string URL - */ - protected function _getCreatedItemLocation($createdItem) - { - $apiTypeRoute = $this->_routeFactory->createRoute( - 'Mage_Webapi_Controller_Router_Route_Webapi', - Mage_Webapi_Controller_Router_Route_Webapi::getApiRoute() - ); - $resourceName = $this->_request->getResourceName(); - $routeToItem = $this->_routeFactory->createRoute( - 'Zend_Controller_Router_Route', - $this->_apiConfig->getRestRouteToItem($resourceName) - ); - $chain = $apiTypeRoute->chain($routeToItem); - $params = array( - Mage_Webapi_Controller_Router_Route_Webapi::PARAM_API_TYPE => $this->_request->getApiType(), - Mage_Webapi_Controller_Router_Route_Rest::PARAM_ID => $createdItem->getId(), - Mage_Webapi_Controller_Router_Route_Rest::PARAM_VERSION => $this->_request->getResourceVersion() - ); - $uri = $chain->assemble($params); - - return '/' . $uri; - } - - /** - * Retrieve request data. Ensure that data is not empty. - * - * @param string $method - * @return array - */ - protected function _getRequestBody($method) - { - $processedInputData = null; - switch ($method) { - case Mage_Webapi_Controller_ActionAbstract::METHOD_CREATE: - $processedInputData = $this->_request->getBodyParams(); - // TODO: Implement data filtration of item - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_CREATE: - $processedInputData = $this->_request->getBodyParams(); - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_UPDATE: - $processedInputData = $this->_request->getBodyParams(); - // TODO: Implement data filtration - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_UPDATE: - $processedInputData = $this->_request->getBodyParams(); - // TODO: Implement fields filtration - break; - case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_DELETE: - // break is intentionally omitted - case Mage_Webapi_Controller_ActionAbstract::METHOD_GET: - // break is intentionally omitted - case Mage_Webapi_Controller_ActionAbstract::METHOD_DELETE: - // break is intentionally omitted - case Mage_Webapi_Controller_ActionAbstract::METHOD_LIST: - break; - } - return $processedInputData; - } - - /** - * Render data using registered Renderer. - * - * @param mixed $data - */ - protected function _render($data) - { - $mimeType = $this->_renderer->getMimeType(); - $body = $this->_renderer->render($data); - $this->_response->setMimeType($mimeType)->setBody($body); + $this->_responseProcessor->prepareResponse($method, $outputData); } } diff --git a/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Request.php b/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Request.php new file mode 100644 index 00000000000..f5a73cfc61c --- /dev/null +++ b/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Request.php @@ -0,0 +1,127 @@ +<?php +/** + * Helper for request data processing according to REST presentation. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Request +{ + /** @var Mage_Webapi_Model_Config_Rest */ + protected $_apiConfig; + + /** @var Mage_Webapi_Helper_Data */ + protected $_apiHelper; + + /** @var Mage_Webapi_Helper_Config */ + protected $_configHelper; + + /** @var Mage_Webapi_Controller_Request_Rest */ + protected $_request; + + /** + * Initialize dependencies. + * + * @param Mage_Webapi_Model_Config_Rest $apiConfig + * @param Mage_Webapi_Helper_Data $helper + * @param Mage_Webapi_Helper_Config $configHelper + * @param Mage_Webapi_Controller_Request_Factory $requestFactory + */ + public function __construct( + Mage_Webapi_Model_Config_Rest $apiConfig, + Mage_Webapi_Helper_Data $helper, + Mage_Webapi_Helper_Config $configHelper, + Mage_Webapi_Controller_Request_Factory $requestFactory + ) { + $this->_apiConfig = $apiConfig; + $this->_apiHelper = $helper; + $this->_configHelper = $configHelper; + $this->_request = $requestFactory->get(); + } + + /** + * Fetch data from request and prepare it for passing to specified action. + * + * @param object $controllerInstance + * @param string $action + * @return array + */ + public function fetchRequestData($controllerInstance, $action) + { + $methodReflection = Mage_Webapi_Helper_Data::createMethodReflection($controllerInstance, $action); + $methodName = $this->_configHelper->getMethodNameWithoutVersionSuffix($methodReflection); + $bodyParamName = $this->_configHelper->getOperationBodyParamName($methodReflection); + $requestParams = array_merge( + $this->_request->getParams(), + array($bodyParamName => $this->_getRequestBody($methodName)) + ); + /** Convert names of ID and Parent ID params in request to those which are used in method interface. */ + $idArgumentName = $this->_configHelper->getOperationIdParamName($methodReflection); + $parentIdParamName = Mage_Webapi_Controller_Router_Route_Rest::PARAM_PARENT_ID; + $idParamName = Mage_Webapi_Controller_Router_Route_Rest::PARAM_ID; + if (isset($requestParams[$parentIdParamName]) && ($idArgumentName != $parentIdParamName)) { + $requestParams[$idArgumentName] = $requestParams[$parentIdParamName]; + unset($requestParams[$parentIdParamName]); + } elseif (isset($requestParams[$idParamName]) && ($idArgumentName != $idParamName)) { + $requestParams[$idArgumentName] = $requestParams[$idParamName]; + unset($requestParams[$idParamName]); + } + + return $this->_apiHelper->prepareMethodParams($controllerInstance, $action, $requestParams, $this->_apiConfig); + } + + /** + * Retrieve request data. Ensure that data is not empty. + * + * @param string $method + * @return array + */ + protected function _getRequestBody($method) + { + $processedInputData = null; + switch ($method) { + case Mage_Webapi_Controller_ActionAbstract::METHOD_CREATE: + $processedInputData = $this->_request->getBodyParams(); + // TODO: Implement data filtration of item + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_CREATE: + $processedInputData = $this->_request->getBodyParams(); + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_UPDATE: + $processedInputData = $this->_request->getBodyParams(); + // TODO: Implement data filtration + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_UPDATE: + $processedInputData = $this->_request->getBodyParams(); + // TODO: Implement fields filtration + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_DELETE: + // break is intentionally omitted + case Mage_Webapi_Controller_ActionAbstract::METHOD_GET: + // break is intentionally omitted + case Mage_Webapi_Controller_ActionAbstract::METHOD_DELETE: + // break is intentionally omitted + case Mage_Webapi_Controller_ActionAbstract::METHOD_LIST: + break; + } + return $processedInputData; + } +} diff --git a/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Response.php b/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Response.php new file mode 100644 index 00000000000..e9b7ea94c9e --- /dev/null +++ b/app/code/core/Mage/Webapi/Controller/Dispatcher/Rest/Presentation/Response.php @@ -0,0 +1,160 @@ +<?php +/** + * Helper for response data processing according to REST presentation. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Webapi_Controller_Dispatcher_Rest_Presentation_Response +{ + /** @var Mage_Webapi_Model_Config_Rest */ + protected $_apiConfig; + + /** @var Mage_Webapi_Controller_Request_Rest */ + protected $_request; + + /** @var Mage_Webapi_Controller_Response_Rest */ + protected $_response; + + /** @var Magento_Controller_Router_Route_Factory */ + protected $_routeFactory; + + /** @var Mage_Webapi_Controller_Response_Rest_RendererInterface */ + protected $_renderer; + + /** @var Mage_Core_Model_Config */ + protected $_applicationConfig; + + /** + * Initialize dependencies. + * + * @param Mage_Webapi_Model_Config_Rest $apiConfig + * @param Mage_Webapi_Controller_Request_Factory $requestFactory + * @param Mage_Webapi_Controller_Response_Rest $response + * @param Mage_Webapi_Controller_Response_Rest_Renderer_Factory $rendererFactory + * @param Magento_Controller_Router_Route_Factory $routeFactory + * @param Mage_Core_Model_Config $applicationConfig + */ + public function __construct( + Mage_Webapi_Model_Config_Rest $apiConfig, + Mage_Webapi_Controller_Request_Factory $requestFactory, + Mage_Webapi_Controller_Response_Rest $response, + Mage_Webapi_Controller_Response_Rest_Renderer_Factory $rendererFactory, + Magento_Controller_Router_Route_Factory $routeFactory, + Mage_Core_Model_Config $applicationConfig + ) { + $this->_apiConfig = $apiConfig; + $this->_request = $requestFactory->get(); + $this->_response = $response; + $this->_routeFactory = $routeFactory; + $this->_renderer = $rendererFactory->get(); + $this->_applicationConfig = $applicationConfig; + } + + /** + * Perform rendering of action results. + * + * @param string $method + * @param array|null $outputData + */ + public function prepareResponse($method, $outputData = null) + { + switch ($method) { + case Mage_Webapi_Controller_ActionAbstract::METHOD_CREATE: + /** @var $createdItem Mage_Core_Model_Abstract */ + $createdItem = $outputData; + $this->_response->setHeader('Location', $this->_getCreatedItemLocation($createdItem)); + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_GET: + // TODO: Implement fields filtration + $filteredData = $outputData; + $this->_render($filteredData); + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_LIST: + // TODO: Implement fields filtration + $filteredData = $outputData; + $this->_render($filteredData); + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_UPDATE: + // break is intentionally omitted + case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_CREATE: + // break is intentionally omitted + case Mage_Webapi_Controller_ActionAbstract::METHOD_MULTI_DELETE: + $this->_response->setHttpResponseCode(Mage_Webapi_Controller_Response_Rest::HTTP_MULTI_STATUS); + break; + case Mage_Webapi_Controller_ActionAbstract::METHOD_UPDATE: + // break is intentionally omitted + case Mage_Webapi_Controller_ActionAbstract::METHOD_DELETE: + break; + } + $this->_renderMessages(); + } + + /** + * Render error and success messages. + */ + protected function _renderMessages() + { + if ($this->_response->getMessages()) { + $this->_render(array('messages' => $this->_response->getMessages())); + } + } + + /** + * Generate resource location. + * + * @param Mage_Core_Model_Abstract $createdItem + * @return string URL + */ + protected function _getCreatedItemLocation($createdItem) + { + $apiTypeRoute = $this->_routeFactory->createRoute( + 'Mage_Webapi_Controller_Router_Route', + $this->_applicationConfig->getAreaFrontName() . '/:' . Mage_Webapi_Controller_Request::PARAM_API_TYPE + ); + $resourceName = $this->_request->getResourceName(); + $routeToItem = $this->_routeFactory->createRoute( + 'Zend_Controller_Router_Route', + $this->_apiConfig->getRestRouteToItem($resourceName) + ); + $chain = $apiTypeRoute->chain($routeToItem); + $params = array( + Mage_Webapi_Controller_Request::PARAM_API_TYPE => $this->_request->getApiType(), + Mage_Webapi_Controller_Router_Route_Rest::PARAM_ID => $createdItem->getId(), + Mage_Webapi_Controller_Router_Route_Rest::PARAM_VERSION => $this->_request->getResourceVersion() + ); + $uri = $chain->assemble($params); + + return '/' . $uri; + } + + /** + * Render data using registered Renderer. + * + * @param mixed $data + */ + protected function _render($data) + { + $mimeType = $this->_renderer->getMimeType(); + $body = $this->_renderer->render($data); + $this->_response->setMimeType($mimeType)->setBody($body); + } +} diff --git a/app/code/core/Mage/Webapi/Controller/Front.php b/app/code/core/Mage/Webapi/Controller/Front.php index 94193c03700..ffd5e5fb158 100644 --- a/app/code/core/Mage/Webapi/Controller/Front.php +++ b/app/code/core/Mage/Webapi/Controller/Front.php @@ -148,16 +148,18 @@ class Mage_Webapi_Controller_Front implements Mage_Core_Controller_FrontInterfac { if (is_null($this->_apiType)) { $request = $this->_application->getRequest(); + $apiRoutePath = $this->_application->getConfig()->getAreaFrontName() + . '/:' . Mage_Webapi_Controller_Request::PARAM_API_TYPE; $apiRoute = $this->_routeFactory->createRoute( - 'Mage_Webapi_Controller_Router_Route_Webapi', - Mage_Webapi_Controller_Router_Route_Webapi::getApiRoute() + 'Mage_Webapi_Controller_Router_Route', + $apiRoutePath ); if (!($apiTypeMatch = $apiRoute->match($request, true))) { throw new Mage_Webapi_Exception($this->_helper->__('Request does not match any API type route.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } - $apiType = $apiTypeMatch[Mage_Webapi_Controller_Router_Route_Webapi::PARAM_API_TYPE]; + $apiType = $apiTypeMatch[Mage_Webapi_Controller_Request::PARAM_API_TYPE]; if (!in_array($apiType, $this->getListOfAvailableApiTypes())) { throw new Mage_Webapi_Exception($this->_helper->__('The "%s" API type is not defined.', $apiType), Mage_Webapi_Exception::HTTP_BAD_REQUEST); diff --git a/app/code/core/Mage/Webapi/Controller/Request.php b/app/code/core/Mage/Webapi/Controller/Request.php index 8d436e4afac..9d4d196cb72 100644 --- a/app/code/core/Mage/Webapi/Controller/Request.php +++ b/app/code/core/Mage/Webapi/Controller/Request.php @@ -25,6 +25,8 @@ */ class Mage_Webapi_Controller_Request extends Zend_Controller_Request_Http { + const PARAM_API_TYPE = 'api_type'; + /**#@+ * Name of query ($_GET) parameters to use in navigation and so on. */ diff --git a/app/code/core/Mage/Webapi/Controller/Request/Rest.php b/app/code/core/Mage/Webapi/Controller/Request/Rest.php index 46abbd72b06..bd5b9f0251c 100644 --- a/app/code/core/Mage/Webapi/Controller/Request/Rest.php +++ b/app/code/core/Mage/Webapi/Controller/Request/Rest.php @@ -160,16 +160,16 @@ class Mage_Webapi_Controller_Request_Rest extends Mage_Webapi_Controller_Request $headerValue = $this->getHeader('Content-Type'); if (!$headerValue) { - throw new Mage_Webapi_Exception($this->_helper->__('Content-Type header is empty'), + throw new Mage_Webapi_Exception($this->_helper->__('Content-Type header is empty.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } if (!preg_match('~^([a-z\d/\-+.]+)(?:; *charset=(.+))?$~Ui', $headerValue, $matches)) { - throw new Mage_Webapi_Exception($this->_helper->__('Invalid Content-Type header'), + throw new Mage_Webapi_Exception($this->_helper->__('Content-Type header is invalid.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } // request encoding check if it is specified in header if (isset($matches[2]) && self::REQUEST_CHARSET != strtolower($matches[2])) { - throw new Mage_Webapi_Exception($this->_helper->__('UTF-8 is the only supported charset'), + throw new Mage_Webapi_Exception($this->_helper->__('UTF-8 is the only supported charset.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } @@ -185,7 +185,7 @@ class Mage_Webapi_Controller_Request_Rest extends Mage_Webapi_Controller_Request public function getHttpMethod() { if (!$this->isGet() && !$this->isPost() && !$this->isPut() && !$this->isDelete()) { - throw new Mage_Webapi_Exception($this->_helper->__('Invalid request method'), + throw new Mage_Webapi_Exception($this->_helper->__('Request method is invalid.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } // Map HTTP methods to classic CRUD verbs diff --git a/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Json.php b/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Json.php index 773ee5dbcc4..48151e1e537 100644 --- a/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Json.php +++ b/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Json.php @@ -58,7 +58,7 @@ class Mage_Webapi_Controller_Request_Rest_Interpreter_Json implements { if (!is_string($encodedBody)) { throw new InvalidArgumentException(sprintf( - 'Invalid data type "%s". String is expected.', + '"%s" data type is invalid. String is expected.', gettype($encodedBody) )); } diff --git a/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Xml.php b/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Xml.php index 2a8a0656e4e..08a95447552 100644 --- a/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Xml.php +++ b/app/code/core/Mage/Webapi/Controller/Request/Rest/Interpreter/Xml.php @@ -77,7 +77,7 @@ class Mage_Webapi_Controller_Request_Rest_Interpreter_Xml implements { if (!is_string($xmlRequestBody)) { throw new InvalidArgumentException( - sprintf('Invalid data type "%s". String is expected.', gettype($xmlRequestBody)) + sprintf('"%s" data type is invalid. String is expected.', gettype($xmlRequestBody)) ); } /** Disable external entity loading to prevent possible vulnerability */ diff --git a/app/code/core/Mage/Webapi/Controller/Request/Soap.php b/app/code/core/Mage/Webapi/Controller/Request/Soap.php index 8e00c687cde..2888d07c2c4 100644 --- a/app/code/core/Mage/Webapi/Controller/Request/Soap.php +++ b/app/code/core/Mage/Webapi/Controller/Request/Soap.php @@ -51,7 +51,7 @@ class Mage_Webapi_Controller_Request_Soap extends Mage_Webapi_Controller_Request $wsdlParam = Mage_Webapi_Model_Soap_Server::REQUEST_PARAM_WSDL; $resourcesParam = Mage_Webapi_Model_Soap_Server::REQUEST_PARAM_RESOURCES; $requestParams = array_keys($this->getParams()); - $allowedParams = array(Mage_Webapi_Controller_Router_Route_Webapi::PARAM_API_TYPE, $wsdlParam, $resourcesParam); + $allowedParams = array(Mage_Webapi_Controller_Request::PARAM_API_TYPE, $wsdlParam, $resourcesParam); $notAllowedParameters = array_diff($requestParams, $allowedParams); if (count($notAllowedParameters)) { $message = $this->_helper->__('Not allowed parameters: %s. ', implode(', ', $notAllowedParameters)) diff --git a/app/code/core/Mage/Webapi/Controller/Router/RouteAbstract.php b/app/code/core/Mage/Webapi/Controller/Router/Route.php similarity index 93% rename from app/code/core/Mage/Webapi/Controller/Router/RouteAbstract.php rename to app/code/core/Mage/Webapi/Controller/Router/Route.php index 371559b7f95..41d1d0494eb 100644 --- a/app/code/core/Mage/Webapi/Controller/Router/RouteAbstract.php +++ b/app/code/core/Mage/Webapi/Controller/Router/Route.php @@ -23,7 +23,7 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -abstract class Mage_Webapi_Controller_Router_RouteAbstract extends Zend_Controller_Router_Route +class Mage_Webapi_Controller_Router_Route extends Zend_Controller_Router_Route { /** * Matches a Request with parts defined by a map. Assigns and diff --git a/app/code/core/Mage/Webapi/Controller/Router/Route/Rest.php b/app/code/core/Mage/Webapi/Controller/Router/Route/Rest.php index 31851fed156..722a159f0d9 100644 --- a/app/code/core/Mage/Webapi/Controller/Router/Route/Rest.php +++ b/app/code/core/Mage/Webapi/Controller/Router/Route/Rest.php @@ -23,7 +23,7 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -class Mage_Webapi_Controller_Router_Route_Rest extends Mage_Webapi_Controller_Router_RouteAbstract +class Mage_Webapi_Controller_Router_Route_Rest extends Mage_Webapi_Controller_Router_Route { /**#@+ * Names of special parameters in routes. diff --git a/app/code/core/Mage/Webapi/Model/Authorization/Config.php b/app/code/core/Mage/Webapi/Model/Authorization/Config.php index b5edcd6425b..56aabdf35c1 100644 --- a/app/code/core/Mage/Webapi/Model/Authorization/Config.php +++ b/app/code/core/Mage/Webapi/Model/Authorization/Config.php @@ -76,7 +76,7 @@ class Mage_Webapi_Model_Authorization_Config implements Mage_Core_Model_Acl_Conf { if (is_null($this->_reader)) { $aclResourceFiles = $this->_getAclResourceFiles(); - $this->_reader = $this->_readerFactory->createReader(array($aclResourceFiles)); + $this->_reader = $this->_readerFactory->createReader(array('configFiles' => $aclResourceFiles)); } return $this->_reader; } diff --git a/app/code/core/Mage/Webapi/Model/Authorization/Config/Reader.php b/app/code/core/Mage/Webapi/Model/Authorization/Config/Reader.php index a8039c7eede..7ffde825c51 100644 --- a/app/code/core/Mage/Webapi/Model/Authorization/Config/Reader.php +++ b/app/code/core/Mage/Webapi/Model/Authorization/Config/Reader.php @@ -39,7 +39,10 @@ class Mage_Webapi_Model_Authorization_Config_Reader extends Magento_Acl_Config_R Mage_Core_Model_Config $config, array $configFiles ) { - parent::__construct($configFiles); + // TODO: Remove temporary workaround, that allows to avoid exception if no ACL files are available + if (!empty($configFiles)) { + parent::__construct($configFiles); + } $this->_config = $config; } diff --git a/app/code/core/Mage/Webapi/Model/Config/Rest.php b/app/code/core/Mage/Webapi/Model/Config/Rest.php index 64bb74405a1..a1a2aa47d84 100644 --- a/app/code/core/Mage/Webapi/Model/Config/Rest.php +++ b/app/code/core/Mage/Webapi/Model/Config/Rest.php @@ -33,16 +33,16 @@ class Mage_Webapi_Model_Config_Rest extends Mage_Webapi_Model_ConfigAbstract * * @param Mage_Webapi_Model_Config_Reader_Rest $reader * @param Mage_Webapi_Helper_Config $helper - * @param Mage_Core_Model_App $app + * @param Mage_Core_Model_App $application * @param Magento_Controller_Router_Route_Factory $routeFactory */ public function __construct( Mage_Webapi_Model_Config_Reader_Rest $reader, Mage_Webapi_Helper_Config $helper, - Mage_Core_Model_App $app, + Mage_Core_Model_App $application, Magento_Controller_Router_Route_Factory $routeFactory ) { - parent::__construct($reader, $helper, $app); + parent::__construct($reader, $helper, $application); $this->_routeFactory = $routeFactory; } @@ -124,7 +124,7 @@ class Mage_Webapi_Model_Config_Rest extends Mage_Webapi_Model_ConfigAbstract */ protected function _createRoute($routePath, $resourceName, $actionType) { - $apiTypeRoutePath = Mage_Webapi_Controller_Router_Route_Webapi::API_AREA_NAME + $apiTypeRoutePath = $this->_application->getConfig()->getAreaFrontName() . '/:' . Mage_Webapi_Controller_Front::API_TYPE_REST; $fullRoutePath = $apiTypeRoutePath . $routePath; /** @var $route Mage_Webapi_Controller_Router_Route_Rest */ diff --git a/app/code/core/Mage/Webapi/Model/Config/Soap.php b/app/code/core/Mage/Webapi/Model/Config/Soap.php index c139217b918..5ed7ace1655 100644 --- a/app/code/core/Mage/Webapi/Model/Config/Soap.php +++ b/app/code/core/Mage/Webapi/Model/Config/Soap.php @@ -30,14 +30,14 @@ class Mage_Webapi_Model_Config_Soap extends Mage_Webapi_Model_ConfigAbstract * * @param Mage_Webapi_Model_Config_Reader_Soap $reader * @param Mage_Webapi_Helper_Config $helper - * @param Mage_Core_Model_App $app + * @param Mage_Core_Model_App $application */ public function __construct( Mage_Webapi_Model_Config_Reader_Soap $reader, Mage_Webapi_Helper_Config $helper, - Mage_Core_Model_App $app + Mage_Core_Model_App $application ) { - parent::__construct($reader, $helper, $app); + parent::__construct($reader, $helper, $application); } /** diff --git a/app/code/core/Mage/Webapi/Model/ConfigAbstract.php b/app/code/core/Mage/Webapi/Model/ConfigAbstract.php index 864f6b1a3d1..6fe290683d7 100644 --- a/app/code/core/Mage/Webapi/Model/ConfigAbstract.php +++ b/app/code/core/Mage/Webapi/Model/ConfigAbstract.php @@ -51,7 +51,7 @@ abstract class Mage_Webapi_Model_ConfigAbstract protected $_helper; /** @var Mage_Core_Model_App */ - protected $_app; + protected $_application; /** * Resources configuration data. @@ -65,16 +65,16 @@ abstract class Mage_Webapi_Model_ConfigAbstract * * @param Mage_Webapi_Model_Config_ReaderAbstract $reader * @param Mage_Webapi_Helper_Config $helper - * @param Mage_Core_Model_App $app + * @param Mage_Core_Model_App $application */ public function __construct( Mage_Webapi_Model_Config_ReaderAbstract $reader, Mage_Webapi_Helper_Config $helper, - Mage_Core_Model_App $app + Mage_Core_Model_App $application ) { $this->_reader = $reader; $this->_helper = $helper; - $this->_app = $app; + $this->_application = $application; $this->_data = $this->_reader->getData(); } @@ -288,7 +288,7 @@ abstract class Mage_Webapi_Model_ConfigAbstract $resourceName ); throw new Mage_Webapi_Exception($removalMessage . ' ' . $messageUseMethod, $badRequestCode); - } elseif (isset($deprecationPolicy['deprecated']) && $this->_app->isDeveloperMode()) { + } elseif (isset($deprecationPolicy['deprecated']) && $this->_application->isDeveloperMode()) { $deprecationMessage = $this->_helper ->__('Version "%s" of "%s" method in "%s" resource is deprecated.', $resourceVersion, diff --git a/app/code/core/Mage/Webapi/Model/Soap/Server.php b/app/code/core/Mage/Webapi/Model/Soap/Server.php index 5609192b567..f543e9163c5 100644 --- a/app/code/core/Mage/Webapi/Model/Soap/Server.php +++ b/app/code/core/Mage/Webapi/Model/Soap/Server.php @@ -193,7 +193,7 @@ class Mage_Webapi_Model_Soap_Server extends \Zend\Soap\Server { // @TODO: Implement proper endpoint URL retrieval mechanism in APIA-718 story return $this->_application->getStore()->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB) - . Mage_Webapi_Controller_Router_Route_Webapi::API_AREA_NAME . '/' + . $this->_application->getConfig()->getAreaFrontName() . '/' . Mage_Webapi_Controller_Front::API_TYPE_SOAP; } } diff --git a/app/code/core/Mage/Webapi/etc/adminhtml/menu.xml b/app/code/core/Mage/Webapi/etc/adminhtml/menu.xml index 332a4fbc88c..0dbadc30ed3 100644 --- a/app/code/core/Mage/Webapi/etc/adminhtml/menu.xml +++ b/app/code/core/Mage/Webapi/etc/adminhtml/menu.xml @@ -27,11 +27,11 @@ --> <config> <menu> - <add id="Mage_Webapi::system_api" title="Web Services" module="Mage_Webapi" sortOrder="25" + <add id="Mage_Webapi::system_webapi" title="Web Services" module="Mage_Webapi" sortOrder="26" parent="Mage_Adminhtml::system" resource="Mage_Webapi::webapi"/> <add id="Mage_Webapi::system_api_webapi_users" title="API Users" module="Mage_Webapi" sortOrder="1" - parent="Mage_Webapi::system_api" action="adminhtml/webapi_user" resource="Mage_Webapi::webapi_users"/> + parent="Mage_Webapi::system_webapi" action="adminhtml/webapi_user" resource="Mage_Webapi::webapi_users"/> <add id="Mage_Webapi::system_api_webapi_roles" title="API Roles" module="Mage_Webapi" sortOrder="2" - parent="Mage_Webapi::system_api" action="adminhtml/webapi_role" resource="Mage_Webapi::webapi_roles"/> + parent="Mage_Webapi::system_webapi" action="adminhtml/webapi_role" resource="Mage_Webapi::webapi_roles"/> </menu> </config> diff --git a/app/code/core/Mage/Webapi/etc/config.xml b/app/code/core/Mage/Webapi/etc/config.xml index 73dab0d689d..d90be7a2f48 100644 --- a/app/code/core/Mage/Webapi/etc/config.xml +++ b/app/code/core/Mage/Webapi/etc/config.xml @@ -41,7 +41,7 @@ <global> <areas> <webapi> - <frontName>api</frontName> + <frontName>webapi</frontName> <front_controller>Mage_Webapi_Controller_Front</front_controller> <!--TODO: Utilize base action controller from config, not constant--> <base_controller>Mage_Webapi_Controller_ActionAbstract</base_controller> @@ -125,10 +125,9 @@ </rest> </webapi> <di> - <!--<Zend/Server/Reflection><shared>0</shared></Zend/Server/Reflection>--> - <Mage_Webapi_Controller_Router_Route_Webapi> + <Mage_Webapi_Controller_Router_Route> <shared>0</shared> - </Mage_Webapi_Controller_Router_Route_Webapi> + </Mage_Webapi_Controller_Router_Route> <Mage_Xml_Generator> <shared>0</shared> </Mage_Xml_Generator> diff --git a/app/design/adminhtml/default/basic/boxes.css b/app/design/adminhtml/default/basic/boxes.css index 47bd9a8d83a..4529bcc7870 100644 --- a/app/design/adminhtml/default/basic/boxes.css +++ b/app/design/adminhtml/default/basic/boxes.css @@ -886,6 +886,51 @@ div.autocomplete ul li { padding:.5em .7em; min-height:32px; cursor:pointer; tex overflow: auto; max-height: 500px; } +.mage-suggest.category-select .mage-suggest-inner {background: transparent; position: static; border: none; border-radius: 0px; box-shadow: none;} +.mage-suggest.category-select .category-selector-choices {background: #fff; border: 1px solid #ddd; border-radius: 5px; box-shadow: none; overflow: hidden;} +.mage-suggest.category-select .category-selector-choices li {float: left; margin: 5px 0 5px 7px;} +.mage-suggest.category-select .category-selector-search-field input { + background: none repeat scroll 0 0 transparent !important; + border: 0 none; + box-shadow: none; + font-family: sans-serif; + font-size: 100%; + height: 22px; + margin: 1px 0; + outline: 0 none; + padding: 0 5; +} +.mage-suggest.category-select .mage-suggest-dropdown { + position: absolute; + width: 100%; + background: #fff; border: 1px solid #ddd; border-radius: 5px; + margin-top: 2px; +} +.mage-suggest-dropdown .jstree-default.jstree-focused { + background: #ffffff; +} +.mage-suggest-dropdown .jstree li { + margin-left: 18px; +} +.mage-suggest-dropdown .jstree > ul > li { + margin-left: 0px; +} +.mage-suggest-dropdown .jstree a { + padding: 2px 3px; +} +.mage-suggest-dropdown .jstree .jstree-hovered { + border: none; + background: #efefef; +} +.mage-suggest-dropdown .jstree .jstree-clicked { + border: none; + background: #e5e5e5; +} +.mage-suggest-dropdown .category-path { + color: #777777; + margin-left: 7px; + font-size: 11px; +} /* Footer */ .footer .bug-report { float:left; width:35%; text-align:left; } diff --git a/app/design/frontend/default/iphone/Mage_CatalogSearch/form.mini.phtml b/app/design/frontend/default/iphone/Mage_CatalogSearch/form.mini.phtml index 5ddae748685..549d2c85bdc 100644 --- a/app/design/frontend/default/iphone/Mage_CatalogSearch/form.mini.phtml +++ b/app/design/frontend/default/iphone/Mage_CatalogSearch/form.mini.phtml @@ -23,17 +23,19 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ -/* @var $this Mage_Core_Block_Template */ -/* @var $catalogSearchHelper Mage_CatalogSearch_Helper_Data */ -$catalogSearchHelper = $this->helper('Mage_CatalogSearch_Helper_Data'); ?> -<form id="search_mini_form" action="<?php echo $catalogSearchHelper->getResultUrl() ?>" method="get"> - <input type="search" name="<?php echo $this->helper('Mage_CatalogSearch_Helper_Data')->getQueryParamName() ?>" id="search" placeholder="Search" maxlength="<?php echo $catalogSearchHelper->getMaxQueryLength();?>"/> +<?php +/** @var $this Mage_Core_Block_Template */ +/** @var $helper Mage_CatalogSearch_Helper_Data */ +$helper = $this->helper('Mage_CatalogSearch_Helper_Data'); +?> +<form id="search_mini_form" action="<?php echo $helper->getResultUrl() ?>" method="get"> + <input type="search" name="<?php echo $helper->getQueryParamName() ?>" id="search" placeholder="Search" maxlength="<?php echo $helper->getMaxQueryLength();?>"/> <div id="search_autocomplete" class="search-autocomplete"></div> </form> <script type="text/javascript"> //<![CDATA[ - var searchForm = new Varien.searchForm('search_mini_form', 'search', '<?php echo $this->__('Search') ?>'); - searchForm.initAutocomplete('<?php echo $catalogSearchHelper->getSuggestUrl() ?>', 'search_autocomplete'); + var searchForm = new Varien.searchForm('search_mini_form', 'search', '<?php echo $helper->__('Search') ?>'); + searchForm.initAutocomplete('<?php echo $helper->getSuggestUrl() ?>', 'search_autocomplete'); //]]> </script> diff --git a/app/design/frontend/default/modern/Mage_CatalogSearch/form.mini.phtml b/app/design/frontend/default/modern/Mage_CatalogSearch/form.mini.phtml index fb416de6960..924848848d2 100644 --- a/app/design/frontend/default/modern/Mage_CatalogSearch/form.mini.phtml +++ b/app/design/frontend/default/modern/Mage_CatalogSearch/form.mini.phtml @@ -24,10 +24,15 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -<form id="search_mini_form" action="<?php echo $this->helper('Mage_CatalogSearch_Helper_Data')->getResultUrl() ?>" +<?php +/** @var $this Mage_Core_Block_Template */ +/** @var $helper Mage_CatalogSearch_Helper_Data */ +$helper = $this->helper('Mage_CatalogSearch_Helper_Data'); +?> +<form id="search_mini_form" action="<?php echo $helper->getResultUrl() ?>" method="get"> <div class="form-search"> - <label for="search"><?php echo $this->__('Search site:') ?></label><input id="search" type="text" name="<?php echo $this->helper('Mage_CatalogSearch_Helper_Data')->getQueryParamName() ?>" value="<?php echo $this->helper('Mage_CatalogSearch_Helper_Data')->getEscapedQueryText() ?>" class="input-text" autocomplete="off"/> <button type="submit" title="<?php echo $this->__('Go') ?>" class="button"><span><span><?php echo $this->__('Go') ?></span></span></button><a href="<?php echo Mage::helper('Mage_CatalogSearch_Helper_Data')->getAdvancedSearchUrl(); ?>"><?php echo $this->__('Advanced Search'); ?></a> + <label for="search"><?php echo $helper->__('Search:') ?></label><input id="search" type="text" name="<?php echo $helper->getQueryParamName() ?>" value="<?php echo $helper->getEscapedQueryText() ?>" class="input-text" autocomplete="off"/> <button type="submit" title="<?php echo $helper->__('Search') ?>" class="button"><span><span><?php echo $helper->__('Search') ?></span></span></button><a href="<?php echo $helper->getAdvancedSearchUrl(); ?>"><?php echo $helper->__('Advanced Search'); ?></a> <div id="search_autocomplete" class="search-autocomplete"></div> <script type="text/javascript"> //<![CDATA[ @@ -35,8 +40,8 @@ head.js("<?php echo $this->getViewFileUrl('Mage_CatalogSearch::form-mini.js')?>", function() { $('#search').catalogSearch({ formSelector: '#search_mini_form', - placeholder: '<?php echo $this->__('Search entire store here...') ?>', - url: '<?php echo $this->helper('Mage_CatalogSearch_Helper_Data')->getSuggestUrl() ?>', + placeholder: '<?php echo $helper->__('Search entire store here...') ?>', + url: '<?php echo $helper->getSuggestUrl() ?>', destinationSelector: '#search_autocomplete' }); }); diff --git a/dev/shell/install.php b/dev/shell/install.php index f383725f2b9..557cdf5c1da 100644 --- a/dev/shell/install.php +++ b/dev/shell/install.php @@ -64,7 +64,8 @@ define('BARE_BOOTSTRAP', 1); require_once __DIR__ . '/../../app/bootstrap.php'; $installer = new Mage_Install_Model_Installer_Console( - new Magento_Filesystem(new Magento_Filesystem_Adapter_Local()) + new Magento_Filesystem(new Magento_Filesystem_Adapter_Local()), + $args ); if (isset($args['show_locales'])) { var_export($installer->getAvailableLocales()); diff --git a/dev/tests/integration/framework/Magento/Test/Annotation/AppIsolation.php b/dev/tests/integration/framework/Magento/Test/Annotation/AppIsolation.php index 17e75d27f2c..4e8be43ed80 100644 --- a/dev/tests/integration/framework/Magento/Test/Annotation/AppIsolation.php +++ b/dev/tests/integration/framework/Magento/Test/Annotation/AppIsolation.php @@ -38,96 +38,9 @@ class Magento_Test_Annotation_AppIsolation private $_hasNonIsolatedTests = true; /** - * Should clearStaticVariables() be invoked in endTestSuite() - * - * @var bool - */ - protected $_runClearStatics = false; - - /** - * Directories to clear static variables - * - * @var array + * @var Zend_Cache_Core */ - protected static $_cleanableFolders = array( - '/app/code/', - '/dev/tests/', - '/lib/', - ); - - /** - * Classes to exclude from static variables cleaning - * - * @var array - */ - protected static $_classesToSkip = array( - 'Mage', - 'Magento_Test_Bootstrap', - 'Magento_Test_Event_Magento', - 'Magento_Test_Event_PhpUnit', - 'Magento_Test_Annotation_AppIsolation', - ); - - /** - * Check whether it is allowed to clean given class static variables - * - * @param ReflectionClass $reflectionClass - * @return bool - */ - protected static function _isClassCleanable(ReflectionClass $reflectionClass) - { - // 1. do not process php internal classes - if ($reflectionClass->isInternal()) { - return false; - } - - // 2. do not process blacklisted classes from integration framework - foreach (self::$_classesToSkip as $notCleanableClass) { - if ($reflectionClass->getName() == $notCleanableClass - || is_subclass_of($reflectionClass->getName(), $notCleanableClass) - ) { - return false; - } - } - - // 3. process only files from specific folders - $fileName = $reflectionClass->getFileName(); - - if ($fileName) { - $fileName = str_replace('\\', '/', $fileName); - foreach (self::$_cleanableFolders as $directory) { - if (stripos($fileName, $directory) !== false) { - return true; - } - } - } - return false; - } - - /** - * Clear static variables (after running controller test case) - * @TODO: workaround to reduce memory leak - * @TODO: refactor all code where objects are stored to static variables to use object manager instead - */ - public static function clearStaticVariables() - { - $classes = get_declared_classes(); - - foreach ($classes as $class) { - $reflectionCLass = new ReflectionClass($class); - if (self::_isClassCleanable($reflectionCLass)) { - $staticProperties = $reflectionCLass->getProperties(ReflectionProperty::IS_STATIC); - foreach ($staticProperties as $staticProperty) { - $staticProperty->setAccessible(true); - $value = $staticProperty->getValue(); - if (is_object($value) || (is_array($value) && is_object(current($value)))) { - $staticProperty->setValue(null); - } - unset($value); - } - } - } - } + private $_cache; /** * Isolate global application objects @@ -147,7 +60,10 @@ class Magento_Test_Annotation_AppIsolation */ protected function _cleanupCache() { - Mage::app()->getCache()->clean( + if (!$this->_cache) { + $this->_cache = Mage::app()->getCache(); + } + $this->_cache->clean( Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG, array(Mage_Core_Model_Config::CACHE_TAG, Varien_Db_Adapter_Pdo_Mysql::DDL_CACHE_TAG, @@ -194,31 +110,12 @@ class Magento_Test_Annotation_AppIsolation } $isIsolationEnabled = $isolation === array('enabled'); } else { - if ($test instanceof Magento_Test_TestCase_ControllerAbstract) { - $this->_runClearStatics = true; - /* Controller tests should be isolated by default */ - $isIsolationEnabled = true; - } else { - $isIsolationEnabled = false; - } + /* Controller tests should be isolated by default */ + $isIsolationEnabled = $test instanceof Magento_Test_TestCase_ControllerAbstract; } if ($isIsolationEnabled) { $this->_isolateApp(); } } - - /** - * Clear static cache - */ - public function endTestSuite() - { - if ($this->_runClearStatics) { - self::clearStaticVariables(); - // forced garbage collection to avoid process non-zero exit code (exec returned: 139) caused by PHP bug - gc_collect_cycles(); - - $this->_runClearStatics = false; - } - } } diff --git a/dev/tests/integration/framework/Magento/Test/Bootstrap.php b/dev/tests/integration/framework/Magento/Test/Bootstrap.php index 6f787cad3fc..b79a7e56c2e 100644 --- a/dev/tests/integration/framework/Magento/Test/Bootstrap.php +++ b/dev/tests/integration/framework/Magento/Test/Bootstrap.php @@ -24,7 +24,6 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -require_once __DIR__ . '/../../../../../../lib/Varien/Simplexml/Element.php'; /** * Tests entry point. Implements application installation, initialization and uninstall @@ -106,18 +105,11 @@ class Magento_Test_Bootstrap protected $_installEtcDir; /** - * Temporary directory - * - * @var string - */ - protected $_tmpDir; - - /** - * Application initialization options + * Application initialization parameters * * @var array */ - protected $_options = array(); + protected $_initParams = array(); /** * DB vendor name @@ -204,24 +196,22 @@ class Magento_Test_Bootstrap $this->_globalEtcFiles = $this->_exposeFiles($globalEtcFiles); $this->_moduleEtcFiles = $this->_exposeFiles($moduleEtcFiles); $this->_customXmlFile = $customXmlFile; - $this->_tmpDir = $tmpDir; $this->_readLocalXml(); - $this->_verifyDirectories(); + $this->_verifyDirectories($tmpDir); $sandboxUniqueId = md5(sha1_file($this->_localXmlFile) . '_' . $globalEtcFiles . '_' . $moduleEtcFiles); - $this->_installDir = "{$tmpDir}/sandbox-{$this->_dbVendorName}-{$sandboxUniqueId}"; - $this->_installEtcDir = $this->_installDir . '/etc'; - - $this->_options = array( - 'etc_dir' => $this->_installEtcDir, - 'var_dir' => $this->_installDir, - 'tmp_dir' => $this->_installDir . DIRECTORY_SEPARATOR . 'tmp', - 'cache_dir' => $this->_installDir . DIRECTORY_SEPARATOR . 'cache', - 'log_dir' => $this->_installDir . DIRECTORY_SEPARATOR . 'log', - 'session_dir' => $this->_installDir . DIRECTORY_SEPARATOR . 'session', - 'media_dir' => $this->_installDir . DIRECTORY_SEPARATOR . 'media', - 'upload_dir' => $this->_installDir . DIRECTORY_SEPARATOR . 'media' . DIRECTORY_SEPARATOR . 'upload', + $installDir = "{$tmpDir}/sandbox-{$this->_dbVendorName}-{$sandboxUniqueId}"; + $this->_ensureDirExists($installDir); + $this->_installDir = $installDir; + $this->_installEtcDir = "{$installDir}/etc"; + + $this->_initParams = array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::CONFIG => $this->_installEtcDir, + Mage_Core_Model_Dir::VAR_DIR => $installDir, + Mage_Core_Model_Dir::MEDIA => "{$installDir}/media", + ), ); $this->_db = $this->_instantiateDb($shell); @@ -229,19 +219,26 @@ class Magento_Test_Bootstrap if ($isCleanupEnabled) { $this->_cleanup(); } - $this->_ensureDirExists($this->_installDir); $this->_isDeveloperMode = $isDeveloperMode; $this->_emulateEnvironment(); if ($this->_isInstalled()) { - $this->initialize(); + $this->_initialize($this->_initParams); } else { $this->_install(); } } + /** + * Get directory path with application instance custom data (cache, temporary directory, etc...) + */ + public function getInstallDir() + { + return $this->_installDir; + } + /** * Get DB vendor name * @@ -254,53 +251,52 @@ class Magento_Test_Bootstrap /** * Initialize an already installed Magento application + * + * @param array $initParams */ - public function initialize() + protected function _initialize($initParams) { Mage::setIsDeveloperMode($this->_isDeveloperMode); - Mage_Core_Utility_Theme::registerDesignMock(); Mage::$headersSentThrowsException = false; - Mage::app('', 'store', $this->_options); + Mage::app($initParams); } /** * Initialize an already installed Magento application + * + * @param array $additionalParams */ - public function reinitialize() + public function reinitialize(array $additionalParams = array()) { - $this->resetApp(); - $this->initialize(); + $this->_resetApp(); + $this->_initialize($this->_customizeParams($additionalParams)); } /** - * Re-create empty temporary dir by specified + * Run application normally, but with encapsulated initialization options * - * @param string $optionCode - * @throws Magento_Exception if one of protected directories specified + * @param array $additionalParams */ - public function cleanupDir($optionCode) + public function runApp(array $additionalParams) { - if (in_array($optionCode, array('etc_dir', 'var_dir', 'media_dir'))) { - throw new Magento_Exception("Directory '{$optionCode}' must not be cleaned up while running tests."); - } - $dir = $this->_options[$optionCode]; - $this->_removeDirectory($dir, false); + Mage::run($this->_customizeParams($additionalParams)); } /** - * Get application initialization options + * Sub-routine for merging custom parameters with the ones defined in object state * + * @param array $params * @return array */ - public function getAppOptions() + private function _customizeParams($params) { - return $this->_options; + return array_replace_recursive($this->_initParams, $params); } /** * Reset application global state */ - public function resetApp() + protected function _resetApp() { /** @var $objectManager Magento_Test_ObjectManager */ $objectManager = Mage::getObjectManager(); @@ -360,17 +356,18 @@ class Magento_Test_Bootstrap /** * Check all required directories contents and permissions * + * @param string $tmpDir * @throws Magento_Exception when any of required directories is not eligible */ - protected function _verifyDirectories() + protected function _verifyDirectories($tmpDir) { /* Magento application dir */ if (!is_file($this->_magentoDir . '/app/bootstrap.php')) { throw new Magento_Exception('Unable to locate Magento root folder and bootstrap.php.'); } /* Temporary directory */ - if (!is_dir($this->_tmpDir) || !is_writable($this->_tmpDir)) { - throw new Magento_Exception("The '{$this->_tmpDir}' is not a directory or not writable."); + if (!is_dir($tmpDir) || !is_writable($tmpDir)) { + throw new Magento_Exception("The '{$tmpDir}' is not a directory or not writable."); } } @@ -502,7 +499,7 @@ class Magento_Test_Bootstrap $this->_localXml->asNiceXml($targetLocalXml); /* Initialize an application in non-installed mode */ - $this->initialize(); + $this->_initialize($this->_initParams); /* Run all install and data-install scripts */ Mage_Core_Model_Resource_Setup::applyAllUpdates(); @@ -523,7 +520,7 @@ class Magento_Test_Bootstrap $this->_createAdminUser(); /* Switch an application to installed mode */ - $this->initialize(); + $this->_initialize($this->_initParams); } /** @@ -585,24 +582,24 @@ class Magento_Test_Bootstrap )); $roleUser->save(); } - + /** - * Returns path to framework's temporary directory + * Returns path to integration tests root directory * * @return string */ - public function getTmpDir() + public function getTestsDir() { - return $this->_tmpDir; + return $this->_testsDir; } /** - * Returns path to integration tests root directory + * Get application initialization parameters * - * @return string + * @return array */ - public function getTestsDir() + public function getInitParams() { - return $this->_testsDir; + return $this->_initParams; } } diff --git a/dev/tests/integration/framework/Magento/Test/Helper/Api.php b/dev/tests/integration/framework/Magento/Test/Helper/Api.php new file mode 100644 index 00000000000..6789a751b05 --- /dev/null +++ b/dev/tests/integration/framework/Magento/Test/Helper/Api.php @@ -0,0 +1,170 @@ +<?php +/** + * Helper for API integration tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Magento_Test_Helper_Api +{ + /** + * Call API method via API handler. + * + * @param PHPUnit_Framework_TestCase $testCase Active test case + * @param string $path + * @param array $params Order of items matters as they are passed to call_user_func_array + * @return mixed + */ + public static function call(PHPUnit_Framework_TestCase $testCase, $path, $params = array()) + { + $soapAdapterMock = $testCase->getMock('Mage_Api_Model_Server_Adapter_Soap', array('fault')); + $soapAdapterMock->expects($testCase->any())->method('fault')->will( + $testCase->returnCallback(array(__CLASS__, 'soapAdapterFaultCallback')) + ); + + $serverMock = $testCase->getMock('Mage_Api_Model_Server', array('getAdapter')); + $serverMock->expects($testCase->any())->method('getAdapter')->will($testCase->returnValue($soapAdapterMock)); + + $apiSessionMock = $testCase->getMock('Mage_Api_Model_Session', array('isAllowed', 'isLoggedIn')); + $apiSessionMock->expects($testCase->any())->method('isAllowed')->will($testCase->returnValue(true)); + $apiSessionMock->expects($testCase->any())->method('isLoggedIn')->will($testCase->returnValue(true)); + + $handlerMock = $testCase->getMock('Mage_Api_Model_Server_Handler_Soap', array('_getServer', '_getSession')); + $handlerMock->expects($testCase->any())->method('_getServer')->will($testCase->returnValue($serverMock)); + $handlerMock->expects($testCase->any())->method('_getSession')->will($testCase->returnValue($apiSessionMock)); + + array_unshift($params, 'sessionId'); + Mage::unregister('isSecureArea'); + Mage::register('isSecureArea', true); + $result = call_user_func_array(array($handlerMock, $path), $params); + Mage::unregister('isSecureArea'); + Mage::register('isSecureArea', false); + return $result; + } + + /** + * Throw SoapFault exception. Callback for 'fault' method of API. + * + * @param string $exceptionCode + * @param string $exceptionMessage + * @throws SoapFault + */ + public static function soapAdapterFaultCallback($exceptionCode, $exceptionMessage) + { + throw new SoapFault($exceptionCode, $exceptionMessage); + } + + /** + * Convert Simple XML to array + * + * @param SimpleXMLObject $xml + * @param String $keyTrimmer + * @return object + * + * In XML notation we can't have nodes with digital names in other words fallowing XML will be not valid: + * <24> + * Default category + * </24> + * + * But this one will not cause any problems: + * <qwe_24> + * Default category + * </qwe_24> + * + * So when we want to obtain an array with key 24 we will pass the correct XML from above and $keyTrimmer = 'qwe_'; + * As a result we will obtain an array with digital key node. + * + * In the other case just don't pass the $keyTrimmer. + */ + public static function simpleXmlToArray($xml, $keyTrimmer = null) + { + $result = array(); + + $isTrimmed = false; + if (null !== $keyTrimmer) { + $isTrimmed = true; + } + + if (is_object($xml)) { + foreach (get_object_vars($xml->children()) as $key => $node) { + $arrKey = $key; + if ($isTrimmed) { + $arrKey = str_replace($keyTrimmer, '', $key); //, &$isTrimmed); + } + if (is_numeric($arrKey)) { + $arrKey = 'Obj' . $arrKey; + } + if (is_object($node)) { + $result[$arrKey] = self::simpleXmlToArray($node, $keyTrimmer); + } elseif (is_array($node)) { + $result[$arrKey] = array(); + foreach ($node as $nodeValue) { + $result[$arrKey][] = self::simpleXmlToArray( + $nodeValue, + $keyTrimmer + ); + } + } else { + $result[$arrKey] = (string)$node; + } + } + } else { + $result = (string)$xml; + } + return $result; + } + + /** + * Check specific fields value in some entity data. + * + * @param PHPUnit_Framework_TestCase $testCase + * @param array $expectedData + * @param array $actualData + * @param array $fieldsToCompare To be able to compare fields from loaded model with fields from API response + * this parameter provides fields mapping. + * Array can store model field name $entityField mapped on field name in API response. + * $fieldsToCompare format is: + * $fieldsToCompare = array($modelFieldName => $apiResponseFieldName); + * Example: + * $fieldsToCompare = array( + * 'entity_id' => 'product_id', + * 'sku', + * 'attribute_set_id' => 'set', + * 'type_id' => 'type', + * 'category_ids', + * ); + */ + public static function checkEntityFields( + PHPUnit_Framework_TestCase $testCase, + array $expectedData, + array $actualData, + array $fieldsToCompare = array() + ) { + $fieldsToCompare = !empty($fieldsToCompare) ? $fieldsToCompare : array_keys($expectedData); + foreach ($fieldsToCompare as $entityField => $field) { + $testCase->assertEquals( + $expectedData[is_numeric($entityField) ? $field : $entityField], + $actualData[$field], + sprintf('"%s" filed has invalid value.', $field) + ); + } + } +} diff --git a/dev/tests/integration/framework/Magento/Test/Helper/Eav.php b/dev/tests/integration/framework/Magento/Test/Helper/Eav.php new file mode 100644 index 00000000000..4d7f0d86b80 --- /dev/null +++ b/dev/tests/integration/framework/Magento/Test/Helper/Eav.php @@ -0,0 +1,49 @@ +<?php +/** + * Helper for EAV functionality in integration tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Magento_Test_Helper_Eav +{ + /** + * Set increment id prefix in entity model. + * + * @param string $entityType + * @param string $prefix + */ + public static function setIncrementIdPrefix($entityType, $prefix) + { + $website = Mage::app()->getWebsite(); + $storeId = $website->getDefaultStore()->getId(); + $entityTypeModel = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode($entityType); + /** @var Mage_Eav_Model_Entity_Store $entityStore */ + $entityStore = Mage::getModel('Mage_Eav_Model_Entity_Store')->loadByEntityStore( + $entityTypeModel->getId(), + $storeId + ); + $entityStore->setEntityTypeId($entityTypeModel->getId()); + $entityStore->setStoreId($storeId); + $entityStore->setIncrementPrefix($prefix); + $entityStore->save(); + } +} diff --git a/dev/tests/integration/framework/Magento/Test/ObjectManager.php b/dev/tests/integration/framework/Magento/Test/ObjectManager.php index 2c049df6c16..e37a4cc610d 100644 --- a/dev/tests/integration/framework/Magento/Test/ObjectManager.php +++ b/dev/tests/integration/framework/Magento/Test/ObjectManager.php @@ -27,18 +27,6 @@ class Magento_Test_ObjectManager extends Magento_ObjectManager_Zend { - /** - * Classes with xml properties to explicitly call __destruct() due to https://bugs.php.net/bug.php?id=62468 - * - * @var array - */ - protected $_classesToDestruct = array( - 'Mage_Core_Model_Config', - 'Mage_Core_Model_Layout', - 'Mage_Core_Model_Layout_Merge', - 'Mage_Core_Model_Layout_ScheduledStructure', - ); - /** * Clear InstanceManager cache * @@ -46,16 +34,6 @@ class Magento_Test_ObjectManager extends Magento_ObjectManager_Zend */ public function clearCache() { - foreach ($this->_classesToDestruct as $className) { - if ($this->hasSharedInstance($className)) { - $object = $this->get($className); - if ($object) { - // force to cleanup circular references - $object->__destruct(); - } - } - } - $instanceManagerNew = new Magento_Di_InstanceManager_Zend(); $instanceManagerNew->addSharedInstance($this, 'Magento_ObjectManager'); if ($this->_di->instanceManager()->hasSharedInstance('Mage_Core_Model_Resource')) { diff --git a/dev/tests/integration/framework/Magento/Test/TestCase/ControllerAbstract.php b/dev/tests/integration/framework/Magento/Test/TestCase/ControllerAbstract.php index b63f1ab1f4e..e0e64a7dd36 100644 --- a/dev/tests/integration/framework/Magento/Test/TestCase/ControllerAbstract.php +++ b/dev/tests/integration/framework/Magento/Test/TestCase/ControllerAbstract.php @@ -64,19 +64,12 @@ abstract class Magento_Test_TestCase_ControllerAbstract extends PHPUnit_Framewor /** * Bootstrap application before eny test - * - * @return void */ protected function setUp() { $this->_objectManager = Mage::getObjectManager(); - - /** - * Use run options from bootstrap - */ - $this->_runOptions = $this->_getBootstrap()->getAppOptions(); - $this->_runOptions['request'] = $this->getRequest(); - $this->_runOptions['response'] = $this->getResponse(); + $this->_runOptions[Mage::INIT_OPTION_REQUEST] = $this->getRequest(); + $this->_runOptions[Mage::INIT_OPTION_RESPONSE] = $this->getResponse(); } protected function tearDown() @@ -95,7 +88,7 @@ abstract class Magento_Test_TestCase_ControllerAbstract extends PHPUnit_Framewor public function dispatch($uri) { $this->getRequest()->setRequestUri($uri); - Mage::run($this->_runCode, $this->_runScope, $this->_runOptions); + $this->_getBootstrap()->runApp($this->_runOptions); } /** diff --git a/dev/tests/integration/framework/Magento/Test/Workaround/Cleanup/StaticProperties.php b/dev/tests/integration/framework/Magento/Test/Workaround/Cleanup/StaticProperties.php new file mode 100644 index 00000000000..54c500ebe3b --- /dev/null +++ b/dev/tests/integration/framework/Magento/Test/Workaround/Cleanup/StaticProperties.php @@ -0,0 +1,135 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Workaround for decreasing memory consumption by cleaning up static properties + */ +class Magento_Test_Workaround_Cleanup_StaticProperties +{ + /** + * Directories to clear static variables + * + * @var array + */ + protected static $_cleanableFolders = array( + '/app/code/', + '/dev/tests/', + '/lib/', + ); + + /** + * Classes to exclude from static variables cleaning + * + * @var array + */ + protected static $_classesToSkip = array( + 'Mage', + 'Magento_Test_Bootstrap', + 'Magento_Test_Event_Magento', + 'Magento_Test_Event_PhpUnit', + 'Magento_Test_Annotation_AppIsolation', + ); + + /** + * Check whether it is allowed to clean given class static variables + * + * @param ReflectionClass $reflectionClass + * @return bool + */ + protected static function _isClassCleanable(ReflectionClass $reflectionClass) + { + // 1. do not process php internal classes + if ($reflectionClass->isInternal()) { + return false; + } + + // 2. do not process blacklisted classes from integration framework + foreach (self::$_classesToSkip as $notCleanableClass) { + if ($reflectionClass->getName() == $notCleanableClass + || is_subclass_of($reflectionClass->getName(), $notCleanableClass) + ) { + return false; + } + } + + // 3. process only files from specific folders + $fileName = $reflectionClass->getFileName(); + + if ($fileName) { + $fileName = str_replace('\\', '/', $fileName); + foreach (self::$_cleanableFolders as $directory) { + if (stripos($fileName, $directory) !== false) { + return true; + } + } + } + return false; + } + + /** + * Clear static variables (after running controller test case) + * @TODO: refactor all code where objects are stored to static variables to use object manager instead + */ + public static function clearStaticVariables() + { + $classes = get_declared_classes(); + + foreach ($classes as $class) { + $reflectionCLass = new ReflectionClass($class); + if (self::_isClassCleanable($reflectionCLass)) { + $staticProperties = $reflectionCLass->getProperties(ReflectionProperty::IS_STATIC); + foreach ($staticProperties as $staticProperty) { + $staticProperty->setAccessible(true); + $value = $staticProperty->getValue(); + if (is_object($value) || (is_array($value) && is_object(current($value)))) { + $staticProperty->setValue(null); + } + unset($value); + } + } + } + } + + /** + * Handler for 'endTestSuite' event + * + * @param PHPUnit_Framework_TestSuite $suite + */ + public function endTestSuite(PHPUnit_Framework_TestSuite $suite) + { + $clearStatics = false; + foreach ($suite->tests() as $test) { + if ($test instanceof Magento_Test_TestCase_ControllerAbstract) { + $clearStatics = true; + break; + } + } + if ($clearStatics) { + self::clearStaticVariables(); + } + } +} diff --git a/dev/tests/integration/framework/Magento/Test/ClearProperties.php b/dev/tests/integration/framework/Magento/Test/Workaround/Cleanup/TestCaseProperties.php similarity index 91% rename from dev/tests/integration/framework/Magento/Test/ClearProperties.php rename to dev/tests/integration/framework/Magento/Test/Workaround/Cleanup/TestCaseProperties.php index 0c01547dde3..e547eacb857 100644 --- a/dev/tests/integration/framework/Magento/Test/ClearProperties.php +++ b/dev/tests/integration/framework/Magento/Test/Workaround/Cleanup/TestCaseProperties.php @@ -26,9 +26,9 @@ */ /** - * Clear test method properties, it isn't needed to unset properties manually in tearDown() anymore + * Automatic cleanup of test case's properties, it isn't needed to unset properties manually in tearDown() anymore */ -class Magento_Test_ClearProperties +class Magento_Test_Workaround_Cleanup_TestCaseProperties { /** * Clear test method properties after each test suite diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/_files/Stub.php b/dev/tests/integration/framework/Magento/Test/Workaround/Segfault.php similarity index 81% rename from dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/_files/Stub.php rename to dev/tests/integration/framework/Magento/Test/Workaround/Segfault.php index cb26d2aa4f3..7ef528ffeb4 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/_files/Stub.php +++ b/dev/tests/integration/framework/Magento/Test/Workaround/Segfault.php @@ -25,15 +25,16 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -class Magento_Test_ClearProperties_Stub +/** + * Workaround for occasional non-zero exit code (exec returned: 139) caused by the PHP bug + */ +class Magento_Test_Workaround_Segfault { /** - * @var boolean + * Force garbage collection */ - public static $isDestructCalled = false; - - public function __destruct() + public function endTestSuite() { - self::$isDestructCalled = true; + gc_collect_cycles(); } } diff --git a/dev/tests/integration/framework/bootstrap.php b/dev/tests/integration/framework/bootstrap.php index 2c783a3eeca..f6109a62ea5 100644 --- a/dev/tests/integration/framework/bootstrap.php +++ b/dev/tests/integration/framework/bootstrap.php @@ -89,13 +89,15 @@ if (defined('TESTS_BAMBOO_PROFILER_FILE') && defined('TESTS_BAMBOO_PROFILER_METR * To allow config fixtures to deal with fixture stores, data fixtures should be processed before config fixtures. */ $eventManager = new Magento_Test_EventManager(array( - new Magento_Test_ClearProperties(), + new Magento_Test_Workaround_Segfault(), + new Magento_Test_Workaround_Cleanup_TestCaseProperties(), + new Magento_Test_Workaround_Cleanup_StaticProperties(), new Magento_Test_Annotation_AppIsolation(), new Magento_Test_Event_Transaction(new Magento_Test_EventManager(array( new Magento_Test_Annotation_DbIsolation(), new Magento_Test_Annotation_DataFixture("$testsBaseDir/testsuite"), ))), - new Magento_Test_Annotation_ConfigFixture(), + new Magento_Test_Annotation_ConfigFixture() )); Magento_Test_Event_PhpUnit::setDefaultEventManager($eventManager); Magento_Test_Event_Magento::setDefaultEventManager($eventManager); @@ -110,7 +112,7 @@ Magento_Test_Bootstrap::setInstance(new Magento_Test_Bootstrap( $localXmlFile, $globalEtcFiles, $moduleEtcFiles, - 'etc/integration-tests-config.xml', + $testsBaseDir . DIRECTORY_SEPARATOR . 'etc/integration-tests-config.xml', $testsTmpDir, new Magento_Shell(), $isCleanupEnabled, diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/BootstrapTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/BootstrapTest.php index c5a1cd3e069..f4d542cd440 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/BootstrapTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/BootstrapTest.php @@ -80,7 +80,8 @@ class Magento_Test_BootstrapTest extends PHPUnit_Framework_TestCase $this->_bootstrap = $this->getMock( 'Magento_Test_Bootstrap', array( - 'initialize', + '_initialize', + '_resetApp', '_verifyDirectories', '_instantiateDb', '_isInstalled', @@ -203,7 +204,7 @@ class Magento_Test_BootstrapTest extends PHPUnit_Framework_TestCase ; $this->_bootstrap ->expects($this->once()) - ->method('initialize') + ->method('_initialize') ; $this->_callBootstrapConstructor(); } @@ -269,33 +270,64 @@ class Magento_Test_BootstrapTest extends PHPUnit_Framework_TestCase } /** - * @dataProvider cleanupDirExceptionDataProvider - * @expectedException Magento_Exception + * @param $origParams + * @param $customParams + * @param $expectedResult + * @dataProvider reinitializeDataProvider */ - public function testCleanupDirException($optionCode) + public function testReinitialize($origParams, $customParams, $expectedResult) { - $this->_bootstrap->cleanupDir($optionCode); + + $property = new ReflectionProperty(get_class($this->_bootstrap), '_initParams'); + $property->setAccessible(true); + $property->setValue($this->_bootstrap, $origParams); + + $this->_bootstrap->expects($this->once())->method('_resetApp'); + $this->_bootstrap->expects($this->once())->method('_initialize')->with($expectedResult); + + $this->_bootstrap->reinitialize($customParams); } /** * @return array */ - public function cleanupDirExceptionDataProvider() + public function reinitializeDataProvider() { + $origParams = array('one' => array('two' => 'three')); return array( - 'etc' => array('etc_dir'), - 'var' => array('var_dir'), - 'media' => array('media_dir'), + array( + $origParams, + array(), + $origParams + ), + array( + $origParams, + array('one' => array('four' => 'five')), + array('one' => array('two' => 'three', 'four' => 'five')) + ), + array( + $origParams, + array('one' => array('two' => 'five')), + array('one' => array('two' => 'five')) + ), ); } - public function testGetTmpDir() + public function testGetTestsDir() { - $this->assertEquals(self::$_tmpDir, $this->_bootstrap->getTmpDir()); + $this->assertEquals(self::$_testsDir, $this->_bootstrap->getTestsDir()); } - public function testGetTestsDir() + public function testGetInitParams() { - $this->assertEquals(self::$_testsDir, $this->_bootstrap->getTestsDir()); + $initParams = $this->_bootstrap->getInitParams(); + $this->_bootstrap->expects($this->once()) + ->method('_initialize') + ->with($initParams); + $this->_bootstrap->expects($this->once()) + ->method('_isInstalled') + ->will($this->returnValue(true)); + + $this->_callBootstrapConstructor(); } } diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ClearPropertiesTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ClearPropertiesTest.php deleted file mode 100644 index 737f1c5ac1f..00000000000 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ClearPropertiesTest.php +++ /dev/null @@ -1,118 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Magento - * @subpackage integration_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -/** - * Test class for Magento_Test_ClearProperties. - */ -class Magento_Test_ClearPropertiesTest extends PHPUnit_Framework_TestCase -{ - /** - * @var array - */ - protected $_properties = array( - array( - 'name' => 'testPublic', - 'is_static' => false, - 'expectedValue' => 'public', - ), - array( - 'name' => '_testPrivate', - 'is_static' => false, - 'expectedValue' => 'private', - ), - array( - 'name' => '_testPropertyBoolean', - 'is_static' => false, - 'expectedValue' => true, - ), - array( - 'name' => '_testPropertyInteger', - 'is_static' => false, - 'expectedValue' => 10, - ), - array( - 'name' => '_testPropertyFloat', - 'is_static' => false, - 'expectedValue' => 1.97, - ), - array( - 'name' => '_testPropertyString', - 'is_static' => false, - 'expectedValue' => 'string', - ), - array( - 'name' => '_testPropertyArray', - 'is_static' => false, - 'expectedValue' => array('test', 20), - ), - array( - 'name' => 'testPublicStatic', - 'is_static' => true, - 'expectedValue' => 'static public', - ), - array( - 'name' => '_testProtectedStatic', - 'is_static' => true, - 'expectedValue' => 'static protected', - ), - array( - 'name' => '_testPrivateStatic', - 'is_static' => true, - 'expectedValue' => 'static private', - ), - ); - - public function testEndTestSuiteDestruct() - { - $clearProperties = new Magento_Test_ClearProperties(); - $phpUnitTestSuite = new PHPUnit_Framework_TestSuite(); - $phpUnitTestSuite->addTestFile(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR - . 'DummyTestCase.php' - ); - // Because addTestFile() adds classes from file to tests array, use first testsuite - /** @var $testSuite PHPUnit_Framework_TestSuite */ - $testSuite = $phpUnitTestSuite->testAt(0); - $testSuite->run(); - $testClass = $testSuite->testAt(0); - foreach ($this->_properties as $property) { - if ($property['is_static']) { - $this->assertAttributeEquals($property['expectedValue'], $property['name'], get_class($testClass)); - } else { - $this->assertAttributeEquals($property['expectedValue'], $property['name'], $testClass); - } - } - $clearProperties->endTestSuite($testSuite); - $this->assertTrue(Magento_Test_ClearProperties_Stub::$isDestructCalled); - foreach ($this->_properties as $property) { - if ($property['is_static']) { - $this->assertAttributeEmpty($property['name'], get_class($testClass)); - } else { - $this->assertAttributeEmpty($property['name'], $testClass); - } - } - } -} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ObjectManagerTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ObjectManagerTest.php index 632e2301940..6594b5b6c17 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ObjectManagerTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ObjectManagerTest.php @@ -42,30 +42,14 @@ class Magento_Test_ObjectManagerTest extends PHPUnit_Framework_TestCase public function testClearCache() { - $object = $this->getMock('stdClass', array('__destruct')); - $object - ->expects($this->once()) - ->method('__destruct') - ; - - $resource = $this->getMock('stdClass', array('__destruct')); - $object - ->expects($this->once()) - ->method('__destruct') - ; + $resource = new stdClass; $instanceManager = new Magento_Di_InstanceManager_Zend(); - $instanceManager->addSharedInstance($object, 'sharedInstance'); $instanceManager->addSharedInstance($resource, 'Mage_Core_Model_Resource'); $diInstance = new Magento_Di_Zend(); $model = new Magento_Test_ObjectManager(null, $diInstance); - // Reflection is the only way to setup fixture input data in place of the hard-coded property value - $reflectionClass = new ReflectionProperty(get_class($model), '_classesToDestruct'); - $reflectionClass->setAccessible(true); - $reflectionClass->setValue($model, array('sharedInstance', 'nonRegisteredInstance')); - $diInstance->setInstanceManager($instanceManager); $this->assertSame($model, $model->clearCache()); $this->assertNotSame($instanceManager, $diInstance->instanceManager()); diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Cleanup/TestCasePropertiesTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Cleanup/TestCasePropertiesTest.php new file mode 100644 index 00000000000..aaf332100bb --- /dev/null +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Cleanup/TestCasePropertiesTest.php @@ -0,0 +1,87 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Test class for Magento_Test_Workaround_Cleanup_TestCaseProperties. + */ +class Magento_Test_Workaround_Cleanup_TestCasePropertiesTest extends PHPUnit_Framework_TestCase +{ + /** + * @var array + */ + protected $_fixtureProperties = array( + array('name' => 'testPublic', 'is_static' => false), + array('name' => '_testPrivate', 'is_static' => false), + array('name' => '_testPropertyBoolean', 'is_static' => false), + array('name' => '_testPropertyInteger', 'is_static' => false), + array('name' => '_testPropertyFloat', 'is_static' => false), + array('name' => '_testPropertyString', 'is_static' => false), + array('name' => '_testPropertyArray', 'is_static' => false), + array('name' => '_testPropertyObject', 'is_static' => false), + array('name' => 'testPublicStatic', 'is_static' => true), + array('name' => '_testProtectedStatic', 'is_static' => true), + array('name' => '_testPrivateStatic', 'is_static' => true), + ); + + public function testEndTestSuiteDestruct() + { + $phpUnitTestSuite = new PHPUnit_Framework_TestSuite(); + $phpUnitTestSuite->addTestFile(__DIR__ . '/_files/DummyTestCase.php'); + // Because addTestFile() adds classes from file to tests array, use first testsuite + /** @var $testSuite PHPUnit_Framework_TestSuite */ + $testSuite = $phpUnitTestSuite->testAt(0); + $testSuite->run(); + /** @var $testClass Magento_Test_Workaround_Cleanup_DummyTestCase */ + $testClass = $testSuite->testAt(0); + + $propertyObjectMock = $this->getMock('stdClass', array('__destruct')); + $propertyObjectMock + ->expects($this->once()) + ->method('__destruct') + ; + $testClass->setPropertyObject($propertyObjectMock); + + foreach ($this->_fixtureProperties as $property) { + if ($property['is_static']) { + $this->assertAttributeNotEmpty($property['name'], get_class($testClass)); + } else { + $this->assertAttributeNotEmpty($property['name'], $testClass); + } + } + + $clearProperties = new Magento_Test_Workaround_Cleanup_TestCaseProperties(); + $clearProperties->endTestSuite($testSuite); + + foreach ($this->_fixtureProperties as $property) { + if ($property['is_static']) { + $this->assertAttributeEmpty($property['name'], get_class($testClass)); + } else { + $this->assertAttributeEmpty($property['name'], $testClass); + } + } + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/_files/DummyTestCase.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Cleanup/_files/DummyTestCase.php similarity index 84% rename from dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/_files/DummyTestCase.php rename to dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Cleanup/_files/DummyTestCase.php index 0570d8d31f2..5c02b9572fb 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/_files/DummyTestCase.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Workaround/Cleanup/_files/DummyTestCase.php @@ -25,14 +25,16 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -require_once __DIR__ . DIRECTORY_SEPARATOR . 'Stub.php'; - -class Magento_Test_ClearProperties_DummyTestCase extends PHPUnit_Framework_TestCase +class Magento_Test_Workaround_Cleanup_DummyTestCase extends PHPUnit_Framework_TestCase { /** * @var string */ public $testPublic; + + /** + * @var string + */ private $_testPrivate; /** @@ -61,7 +63,7 @@ class Magento_Test_ClearProperties_DummyTestCase extends PHPUnit_Framework_TestC protected $_testPropertyArray; /** - * @var mixed + * @var object */ protected $_testPropertyObject; @@ -69,7 +71,15 @@ class Magento_Test_ClearProperties_DummyTestCase extends PHPUnit_Framework_TestC * @var string */ static public $testPublicStatic; + + /** + * @var string + */ static protected $_testProtectedStatic; + + /** + * @var string + */ static private $_testPrivateStatic; public function testDummy() @@ -81,9 +91,18 @@ class Magento_Test_ClearProperties_DummyTestCase extends PHPUnit_Framework_TestC $this->_testPropertyFloat = 1.97; $this->_testPropertyString = 'string'; $this->_testPropertyArray = array('test', 20); - $this->_testPropertyObject = new Magento_Test_ClearProperties_Stub(); self::$testPublicStatic = 'static public'; self::$_testProtectedStatic = 'static protected'; self::$_testPrivateStatic = 'static private'; } + + /** + * Assign value to the object property + * + * @param object $object + */ + public function setPropertyObject($object) + { + $this->_testPropertyObject = $object; + } } diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Catalog/Category/TreeTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Catalog/Category/TreeTest.php index 83598e82947..29decfe9f8b 100644 --- a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Catalog/Category/TreeTest.php +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Catalog/Category/TreeTest.php @@ -42,7 +42,7 @@ class Mage_Adminhtml_Block_Catalog_Category_TreeTest extends PHPUnit_Framework_T public function testGetSuggestedCategoriesJson() { $this->assertEquals( - '[{"id":"2","children":[],"is_active":"1","name":"Default Category"}]', + '[{"id":"2","children":[],"is_active":"1","label":"Default Category"}]', $this->_block->getSuggestedCategoriesJson('Default') ); $this->assertEquals( diff --git a/app/code/core/Mage/Webapi/Controller/Router/Route/Webapi.php b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Notification/BaseurlTest.php similarity index 70% rename from app/code/core/Mage/Webapi/Controller/Router/Route/Webapi.php rename to dev/tests/integration/testsuite/Mage/Adminhtml/Block/Notification/BaseurlTest.php index eeba98de52d..f08c99dcaac 100644 --- a/app/code/core/Mage/Webapi/Controller/Router/Route/Webapi.php +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Notification/BaseurlTest.php @@ -1,7 +1,5 @@ <?php /** - * Route to Magento web API. - * * Magento * * NOTICE OF LICENSE @@ -23,18 +21,12 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -class Mage_Webapi_Controller_Router_Route_Webapi extends Mage_Webapi_Controller_Router_RouteAbstract +class Mage_Adminhtml_Block_Notification_BaseurlTest extends PHPUnit_Framework_TestCase { - const PARAM_API_TYPE = 'api_type'; - const API_AREA_NAME = 'api'; - - /** - * Retrieve API route. - * - * @return string - */ - public static function getApiRoute() + public function testGetConfigUrl() { - return self::API_AREA_NAME . '/:' . self::PARAM_API_TYPE; + /** @var $block Mage_Adminhtml_Block_Notification_Baseurl */ + $block = Mage::app()->getLayout()->createBlock('Mage_Adminhtml_Block_Notification_Baseurl'); + $this->assertStringStartsWith('http://localhost/', $block->getConfigUrl()); } } diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Page/HeadTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Page/HeadTest.php new file mode 100644 index 00000000000..7e87bc7e94c --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Page/HeadTest.php @@ -0,0 +1,32 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Adminhtml_Block_Page_HeadTest extends PHPUnit_Framework_TestCase +{ + public function testConstruct() + { + $this->assertInstanceOf( + 'Mage_Adminhtml_Block_Page_Head', Mage::app()->getLayout()->createBlock('Mage_Adminhtml_Block_Page_Head') + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/LabelsTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/LabelsTest.php new file mode 100644 index 00000000000..36dba811686 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Promo/Quote/Edit/Tab/LabelsTest.php @@ -0,0 +1,33 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_LabelsTest extends PHPUnit_Framework_TestCase +{ + public function testConstruct() + { + $this->assertInstanceOf( + 'Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Labels', + Mage::app()->getLayout()->createBlock('Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Labels') + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Rating/Edit/Tab/FormTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Rating/Edit/Tab/FormTest.php new file mode 100644 index 00000000000..5dcd7ad218b --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Rating/Edit/Tab/FormTest.php @@ -0,0 +1,33 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Adminhtml_Block_Rating_Edit_Tab_FormTest extends PHPUnit_Framework_TestCase +{ + public function testConstruct() + { + $this->assertInstanceOf( + 'Mage_Adminhtml_Block_Rating_Edit_Tab_Form', + Mage::app()->getLayout()->createBlock('Mage_Adminhtml_Block_Rating_Edit_Tab_Form') + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Sales/Order/Create/Form/AbstractTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Sales/Order/Create/Form/AbstractTest.php index a5f14a8427f..783f03bf178 100644 --- a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Sales/Order/Create/Form/AbstractTest.php +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Sales/Order/Create/Form/AbstractTest.php @@ -49,6 +49,8 @@ class Mage_Adminhtml_Block_Sales_Order_Create_Form_AbstractTest Mage::getObjectManager()->get('Mage_Core_Model_Store_Config'), Mage::getObjectManager()->get('Mage_Core_Controller_Varien_Front'), Mage::getObjectManager()->get('Mage_Core_Model_Factory_Helper'), + Mage::getObjectManager()->get('Mage_Core_Model_Dir'), + Mage::getObjectManager()->get('Mage_Core_Model_Logger'), Mage::getObjectManager()->get('Magento_Filesystem'), ); /** @var $block Mage_Adminhtml_Block_Sales_Order_Create_Form_Abstract */ diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Widget/Form/ContainerTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Widget/Form/ContainerTest.php index a0ae7015c79..221196265c7 100644 --- a/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Widget/Form/ContainerTest.php +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/Block/Widget/Form/ContainerTest.php @@ -44,9 +44,11 @@ class Mage_Adminhtml_Block_Widget_Form_ContainerTest extends PHPUnit_Framework_T 'Mage_Core_Model_Store_Config', 'Mage_Core_Controller_Varien_Front', 'Mage_Core_Model_Factory_Helper', + 'Mage_Core_Model_Dir', + 'Mage_Core_Model_Logger', 'Magento_Filesystem' ); - + public function testGetFormHtml() { /** @var $layout Mage_Core_Model_Layout */ @@ -75,7 +77,7 @@ class Mage_Adminhtml_Block_Widget_Form_ContainerTest extends PHPUnit_Framework_T { $arguments = array(); foreach ($this->_blockInjections as $injectionClass) { - $arguments[] = Mage::getModel($injectionClass); + $arguments[] = Mage::getObjectManager()->get($injectionClass); } return $arguments; } diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/CategoryControllerTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/CategoryControllerTest.php index b7869eef157..08d24895585 100644 --- a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/CategoryControllerTest.php +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/CategoryControllerTest.php @@ -81,6 +81,7 @@ class Mage_Adminhtml_Catalog_CategoryControllerTest extends Mage_Backend_Utility /** * @param array $postData * @dataProvider categoryCreatedFromProductCreationPageDataProvider + * @magentoDbIsolation enabled */ public function testSaveActionFromProductCreationPage($postData) { @@ -137,7 +138,7 @@ class Mage_Adminhtml_Catalog_CategoryControllerTest extends Mage_Backend_Utility $this->getRequest()->setParam('name_part', 'Default'); $this->dispatch('backend/admin/catalog_category/suggestCategories'); $this->assertEquals( - '[{"id":"2","children":[],"is_active":"1","name":"Default Category"}]', + '[{"id":"2","children":[],"is_active":"1","label":"Default Category"}]', $this->getResponse()->getBody() ); } diff --git a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/Product/AttributeControllerTest.php b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/Product/AttributeControllerTest.php index 7efdbfcaa72..9e13d09d73e 100644 --- a/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/Product/AttributeControllerTest.php +++ b/dev/tests/integration/testsuite/Mage/Adminhtml/controllers/Catalog/Product/AttributeControllerTest.php @@ -36,8 +36,8 @@ class Mage_Adminhtml_Catalog_Product_AttributeControllerTest extends Mage_Backen $this->getRequest()->setPost($postData); $this->dispatch('backend/admin/catalog_product_attribute/save'); $model = new Mage_Catalog_Model_Resource_Eav_Attribute( - new Mage_Core_Model_Event_Manager(), - new Mage_Core_Model_Cache() + Mage::getModel('Mage_Core_Model_Event_Manager'), + Mage::getModel('Mage_Core_Model_Cache') ); $model->load($postData['attribute_id']); $this->assertNull($model->getData('apply_to')); @@ -52,8 +52,8 @@ class Mage_Adminhtml_Catalog_Product_AttributeControllerTest extends Mage_Backen $this->getRequest()->setPost($postData); $this->dispatch('backend/admin/catalog_product_attribute/save'); $model = new Mage_Catalog_Model_Resource_Eav_Attribute( - new Mage_Core_Model_Event_Manager(), - new Mage_Core_Model_Cache() + Mage::getModel('Mage_Core_Model_Event_Manager'), + Mage::getModel('Mage_Core_Model_Cache') ); $model->load($postData['attribute_id']); $this->assertEquals('simple,configurable', $model->getData('apply_to')); @@ -69,8 +69,8 @@ class Mage_Adminhtml_Catalog_Product_AttributeControllerTest extends Mage_Backen $this->getRequest()->setPost($postData); $this->dispatch('backend/admin/catalog_product_attribute/save'); $model = new Mage_Catalog_Model_Resource_Eav_Attribute( - new Mage_Core_Model_Event_Manager(), - new Mage_Core_Model_Cache() + Mage::getModel('Mage_Core_Model_Event_Manager'), + Mage::getModel('Mage_Core_Model_Cache') ); $model->load($postData['attribute_id']); $this->assertEquals(array('simple', 'configurable'), $model->getApplyTo()); diff --git a/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormStub.php b/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormStub.php index 2062847df06..68a59d1bc29 100644 --- a/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormStub.php +++ b/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormStub.php @@ -44,7 +44,6 @@ class Mage_Backend_Block_System_Config_FormStub extends Mage_Backend_Block_Syste * Sets stub config data * * @param array $configData - * @return void */ public function setStubConfigData(array $configData = array()) { diff --git a/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormTest.php b/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormTest.php index 153d70d33b9..597a28347ba 100644 --- a/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormTest.php +++ b/dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormTest.php @@ -129,8 +129,10 @@ class Mage_Backend_Block_System_Config_FormTest extends PHPUnit_Framework_TestCa */ public function initFieldsInheritCheckboxDataProvider() { + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + 'global_ban_use_cache' => true, + )); Mage::getConfig()->setCurrentAreaCode('adminhtml'); - Mage::getConfig()->setOptions(array('global_ban_use_cache' => 1)); $configMock = $this->getMock('Mage_Core_Model_Config', array(), array(), '', false, false); $configMock->expects($this->any())->method('getModuleConfigurationFiles') diff --git a/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/Grid/MassactionTest.php b/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/Grid/MassactionTest.php index d6591f9808c..11553a173b0 100644 --- a/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/Grid/MassactionTest.php +++ b/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/Grid/MassactionTest.php @@ -26,9 +26,7 @@ */ /** - * @magentoAppIsolation enabled - * @magentoDbIsolation enabled - * @magentoDataFixture Mage/Backend/Block/_files/theme_registration.php + * @magentoDataFixture Mage/Backend/Block/_files/backend_theme.php */ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_TestCase { @@ -44,6 +42,8 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te protected function setUp() { + $this->_setFixtureTheme(); + $this->_layout = Mage::getModel('Mage_Core_Model_Layout', array('area' => 'adminhtml')); $this->_layout->getUpdate()->load('layout_test_grid_handle'); $this->_layout->generateXml(); @@ -52,6 +52,25 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te $this->_block = $this->_layout->getBlock('admin.test.grid.massaction'); } + /** + * Set fixture theme for admin backend area + */ + protected function _setFixtureTheme() + { + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_SCOPE_TYPE => 'store', + Mage_Core_Model_App::INIT_OPTION_SCOPE_CODE => 'admin', + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => __DIR__ . '/../../_files/design' + ), + )); + + Mage::app()->getConfig()->setNode( + 'adminhtml/' . Mage_Core_Model_Design_Package::XML_PATH_THEME, + 'test/default' + ); + } + protected function tearDown() { unset($this->_layout); @@ -63,7 +82,6 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te * @covers Mage_Backend_Block_Widget_Grid_Massaction::getCount * @covers Mage_Backend_Block_Widget_Grid_Massaction::getItemsJson * @covers Mage_Backend_Block_Widget_Grid_Massaction::isAvailable - * @magentoConfigFixture adminhtml/design/theme/full_name test/default */ public function testMassactionDefaultValues() { @@ -76,28 +94,22 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te $this->assertFalse($blockEmpty->isAvailable()); } - /** - * @magentoConfigFixture adminhtml/design/theme/full_name test/default - */ - public function testJavascript() + public function testGetJavaScript() { $javascript = $this->_block->getJavaScript(); $expectedItemFirst = '#"option_id1":{"label":"Option One",' - . '"url":"http:\\\/\\\/localhost\\\/index\.php\\\/key\\\/([\w\d]+)\\\/",' + . '"url":"http:\\\/\\\/localhost\\\/index\.php\\\/(?:key\\\/([\w\d]+)\\\/)?",' . '"complete":"Test","id":"option_id1"}#'; $this->assertRegExp($expectedItemFirst, $javascript); $expectedItemSecond = '#"option_id2":{"label":"Option Two",' - . '"url":"http:\\\/\\\/localhost\\\/index\.php\\\/key\\\/([\w\d]+)\\\/",' + . '"url":"http:\\\/\\\/localhost\\\/index\.php\\\/(?:key\\\/([\w\d]+)\\\/)?",' . '"confirm":"Are you sure\?","id":"option_id2"}#'; $this->assertRegExp($expectedItemSecond, $javascript); } - /** - * @magentoConfigFixture adminhtml/design/theme/full_name test/default - */ - public function testJavascriptWithAddedItem() + public function testGetJavaScriptWithAddedItem() { $input = array( 'id' => 'option_id3', @@ -106,31 +118,27 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te 'block_name' => 'admin.test.grid.massaction.option3' ); $expected = '#"option_id3":{"id":"option_id3","label":"Option Three",' - . '"url":"http:\\\/\\\/localhost\\\/index\.php\\\/key\\\/([\w\d]+)\\\/",' + . '"url":"http:\\\/\\\/localhost\\\/index\.php\\\/(?:key\\\/([\w\d]+)\\\/)?",' . '"block_name":"admin.test.grid.massaction.option3"}#'; $this->_block->addItem($input['id'], $input); $this->assertRegExp($expected, $this->_block->getJavaScript()); } - /** - * @magentoConfigFixture adminhtml/design/theme/full_name test/default - */ - public function testItemsCount() + public function testGetCount() { - $this->assertEquals(2, count($this->_block->getItems())); $this->assertEquals(2, $this->_block->getCount()); } /** * @param $itemId * @param $expectedItem - * @dataProvider itemsDataProvider - * @magentoConfigFixture adminhtml/design/theme/full_name test/default + * @dataProvider getItemsDataProvider */ - public function testItems($itemId, $expectedItem) + public function testGetItems($itemId, $expectedItem) { $items = $this->_block->getItems(); + $this->assertCount(2, $items); $this->assertArrayHasKey($itemId, $items); $actualItem = $items[$itemId]; @@ -144,7 +152,7 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te /** * @return array */ - public function itemsDataProvider() + public function getItemsDataProvider() { return array( array( @@ -152,7 +160,7 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te array( 'id' => 'option_id1', 'label' => 'Option One', - 'url' => '#http:\/\/localhost\/index\.php\/key\/([\w\d]+)\/#', + 'url' => '#http:\/\/localhost\/index\.php\/(?:key\/([\w\d]+)\/)?#', 'selected' => false, 'blockname' => '' ) @@ -162,7 +170,7 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te array( 'id' => 'option_id2', 'label' => 'Option Two', - 'url' => '#http:\/\/localhost\/index\.php\/key\/([\w\d]+)\/#', + 'url' => '#http:\/\/localhost\/index\.php\/(?:key\/([\w\d]+)\/)?#', 'selected' => false, 'blockname' => '' ) @@ -170,9 +178,6 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te ); } - /** - * @magentoConfigFixture adminhtml/design/theme/full_name test/default - */ public function testGridContainsMassactionColumn() { $this->_layout->getBlock('admin.test.grid')->toHtml(); @@ -180,11 +185,11 @@ class Mage_Backend_Block_Widget_Grid_MassactionTest extends PHPUnit_Framework_Te $gridMassactionColumn = $this->_layout->getBlock('admin.test.grid') ->getColumnSet() ->getChildBlock('massaction'); - $this->assertNotNull($gridMassactionColumn, 'Massaction column is not existed in grid column set'); + $this->assertNotNull($gridMassactionColumn, 'Massaction column does not exist in the grid column set'); $this->assertInstanceOf( 'Mage_Backend_Block_Widget_Grid_Column', $gridMassactionColumn, - 'Massaction column is not instance of Mage_Backend_Block_Widget_Column' + 'Massaction column is not an instance of Mage_Backend_Block_Widget_Column' ); } } diff --git a/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/GridTest.php b/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/GridTest.php index 966e1d28ae3..7afde5b2fbc 100644 --- a/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/GridTest.php +++ b/dev/tests/integration/testsuite/Mage/Backend/Block/Widget/GridTest.php @@ -42,36 +42,10 @@ class Mage_Backend_Block_Widget_GridTest extends PHPUnit_Framework_TestCase */ protected $_columnSetMock; - /** - * List of block injection classes - * - * @var array - */ - protected $_blockInjections = array( - 'Mage_Core_Controller_Request_Http', - 'Mage_Core_Model_Layout', - 'Mage_Core_Model_Event_Manager', - 'Mage_Backend_Model_Url', - 'Mage_Core_Model_Translate', - 'Mage_Core_Model_Cache', - 'Mage_Core_Model_Design_Package', - 'Mage_Core_Model_Session', - 'Mage_Core_Model_Store_Config', - 'Mage_Core_Controller_Varien_Front', - 'Mage_Core_Model_Factory_Helper', - 'Magento_Filesystem', - 'Mage_Backend_Helper_Data', - 'Mage_Backend_Model_Widget_Grid_Row_UrlGeneratorFactory', - 'Mage_Backend_Model_Widget_Grid_SubTotals', - 'Mage_Backend_Model_Widget_Grid_Totals', - ); - protected function setUp() { $this->_layoutMock = $this->getMock('Mage_Core_Model_Layout', array(), array(), '', false); - $this->_columnSetMock = $this->getMock( - 'Mage_Backend_Block_Widget_Grid_ColumnSet', array(), $this->_prepareConstructorArguments() - ); + $this->_columnSetMock = $this->_getColumnSetMock(); $returnValueMap = array( array('grid', 'grid.columnSet', 'grid.columnSet'), @@ -92,18 +66,40 @@ class Mage_Backend_Block_Widget_GridTest extends PHPUnit_Framework_TestCase $this->_block->setNameInLayout('grid'); } + protected function tearDown() + { + $this->_block = null; + $this->_layoutMock = null; + $this->_columnSetMock = null; + } + /** - * List of block constructor arguments + * Retrieve the mocked column set block instance * - * @return array + * @return Mage_Backend_Block_Widget_Grid_ColumnSet|PHPUnit_Framework_MockObject_MockObject */ - protected function _prepareConstructorArguments() + protected function _getColumnSetMock() { - $arguments = array(); - foreach ($this->_blockInjections as $injectionClass) { - $arguments[] = Mage::getModel($injectionClass); - } - return $arguments; + return $this->getMock('Mage_Backend_Block_Widget_Grid_ColumnSet', array(), array( + Mage::getModel('Mage_Core_Controller_Request_Http'), + Mage::getModel('Mage_Core_Model_Layout'), + Mage::getModel('Mage_Core_Model_Event_Manager'), + Mage::getModel('Mage_Backend_Model_Url'), + Mage::getModel('Mage_Core_Model_Translate'), + Mage::getModel('Mage_Core_Model_Cache'), + Mage::getModel('Mage_Core_Model_Design_Package'), + Mage::getModel('Mage_Core_Model_Session'), + Mage::getModel('Mage_Core_Model_Store_Config'), + Mage::getModel('Mage_Core_Controller_Varien_Front'), + Mage::getModel('Mage_Core_Model_Factory_Helper'), + new Mage_Core_Model_Dir(__DIR__), + Mage::getModel('Mage_Core_Model_Logger'), + new Magento_Filesystem(new Magento_Filesystem_Adapter_Local), + Mage::getModel('Mage_Backend_Helper_Data'), + Mage::getModel('Mage_Backend_Model_Widget_Grid_Row_UrlGeneratorFactory'), + Mage::getModel('Mage_Backend_Model_Widget_Grid_SubTotals'), + Mage::getModel('Mage_Backend_Model_Widget_Grid_Totals'), + )); } public function testToHtmlPreparesColumns() diff --git a/dev/tests/integration/testsuite/Mage/Backend/Block/_files/backend_theme.php b/dev/tests/integration/testsuite/Mage/Backend/Block/_files/backend_theme.php new file mode 100644 index 00000000000..12d81526658 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Backend/Block/_files/backend_theme.php @@ -0,0 +1,29 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** @var $registration Mage_Core_Model_Theme_Registration */ +$registration = Mage::getModel('Mage_Core_Model_Theme_Registration'); +$registration->register( + __DIR__ . DIRECTORY_SEPARATOR . 'design', + implode(DIRECTORY_SEPARATOR, array('*', '*', '*', 'theme.xml')) +); diff --git a/dev/tests/integration/testsuite/Mage/Backend/Model/Config/Backend/BaseurlTest.php b/dev/tests/integration/testsuite/Mage/Backend/Model/Config/Backend/BaseurlTest.php new file mode 100644 index 00000000000..400449e2146 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Backend/Model/Config/Backend/BaseurlTest.php @@ -0,0 +1,148 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Backend_Model_Config_Backend_BaseurlTest extends PHPUnit_Framework_TestCase +{ + /** + * @param string $path + * @param string $value + * @magentoDbIsolation enabled + * @dataProvider validationDataProvider + */ + public function testValidation($path, $value) + { + /** @var $model Mage_Backend_Model_Config_Backend_Baseurl */ + $model = Mage::getModel('Mage_Backend_Model_Config_Backend_Baseurl'); + $model->setPath($path)->setValue($value)->save(); + $this->assertNotEmpty((int)$model->getId()); + } + + /** + * @return array + */ + public function validationDataProvider() + { + $basePlaceholder = '{{base_url}}'; + $unsecurePlaceholder = '{{unsecure_base_url}}'; + $unsecureSuffix = '{{unsecure_base_url}}test/'; + $securePlaceholder = '{{secure_base_url}}'; + $secureSuffix = '{{secure_base_url}}test/'; + + return array( + // any fully qualified URLs regardless of path + array('any/path', 'http://example.com/'), + array('any/path', 'http://example.com/uri/'), + + // unsecure base URLs + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL, $basePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LINK_URL, $unsecurePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LINK_URL, $unsecureSuffix), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, $unsecurePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, $unsecureSuffix), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LIB_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LIB_URL, $unsecurePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LIB_URL, $unsecureSuffix), + + // secure base URLs + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL, $basePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL, $securePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL, $secureSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL, $securePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL, $secureSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL, $securePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL, $secureSuffix), + + // secure base URLs - in addition can use unsecure + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL, $unsecurePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL, $unsecurePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL, $unsecureSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL, $unsecurePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL, $unsecureSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL, $unsecurePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL, $unsecureSuffix), + ); + } + + /** + * @param string $path + * @param string $value + * @magentoDbIsolation enabled + * @expectedException Mage_Core_Exception + * @dataProvider validationExceptionDataProvider + */ + public function testValidationException($path, $value) + { + /** @var $model Mage_Backend_Model_Config_Backend_Baseurl */ + $model = Mage::getModel('Mage_Backend_Model_Config_Backend_Baseurl'); + $model->setPath($path)->setValue($value)->save(); + } + + /** + * @return array + */ + public function validationExceptionDataProvider() + { + $baseSuffix = '{{base_url}}test/'; + $unsecurePlaceholder = '{{unsecure_base_url}}'; + $unsecureSuffix = '{{unsecure_base_url}}test/'; + $unsecureWrongSuffix = '{{unsecure_base_url}}test'; + $securePlaceholder = '{{secure_base_url}}'; + $secureSuffix = '{{secure_base_url}}test/'; + $secureWrongSuffix = '{{secure_base_url}}test'; + + return array( + // not a fully qualified URLs regardless path + array('', 'not a valid URL'), + array('', 'example.com'), + array('', 'http://example.com'), + array('', 'http://example.com/uri'), + + // unsecure base URLs + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL, ''), // breaks cache + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL, $baseSuffix), // creates redirect loops + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL, $unsecureSuffix), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_URL, $unsecurePlaceholder), // creates endless recursion + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LINK_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LINK_URL, $baseSuffix), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LINK_URL, $unsecureWrongSuffix), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, $unsecureWrongSuffix), + array(Mage_Core_Model_Store::XML_PATH_UNSECURE_BASE_LIB_URL, $unsecureWrongSuffix), + + // secure base URLs + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL, $baseSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL, $secureSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_URL, $securePlaceholder), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL, ''), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL, $baseSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LINK_URL, $secureWrongSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_MEDIA_URL, $secureWrongSuffix), + array(Mage_Core_Model_Store::XML_PATH_SECURE_BASE_LIB_URL, $secureWrongSuffix), + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Backend/Utility/Controller.php b/dev/tests/integration/testsuite/Mage/Backend/Utility/Controller.php index b0191c39f97..e9faf4626c7 100644 --- a/dev/tests/integration/testsuite/Mage/Backend/Utility/Controller.php +++ b/dev/tests/integration/testsuite/Mage/Backend/Utility/Controller.php @@ -46,7 +46,7 @@ class Mage_Backend_Utility_Controller extends Magento_Test_TestCase_ControllerAb { parent::setUp(); - Mage::app()->loadDiConfiguration(Mage_Core_Model_App_Area::AREA_ADMINHTML); + Mage::app()->getConfig()->loadDiConfiguration(Mage_Core_Model_App_Area::AREA_ADMINHTML); Mage::getSingleton('Mage_Backend_Model_Url')->turnOffSecretKey(); $this->_auth = Mage::getModel('Mage_Backend_Model_Auth'); diff --git a/dev/tests/integration/testsuite/Mage/Captcha/Model/ObserverTest.php b/dev/tests/integration/testsuite/Mage/Captcha/Model/ObserverTest.php index 3e0dfd76b43..5ab09150d0c 100644 --- a/dev/tests/integration/testsuite/Mage/Captcha/Model/ObserverTest.php +++ b/dev/tests/integration/testsuite/Mage/Captcha/Model/ObserverTest.php @@ -37,7 +37,9 @@ class Mage_Captcha_Model_ObserverTest extends Magento_Test_TestCase_ControllerAb */ public function testBackendLoginActionWithInvalidCaptchaReturnsError() { - $this->markTestIncomplete('MAGETWO-1662'); + if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { + $this->markTestIncomplete('MAGETWO-1662'); + } Mage::getSingleton('Mage_Backend_Model_Url')->turnOffSecretKey(); $post = array( @@ -50,21 +52,23 @@ class Mage_Captcha_Model_ObserverTest extends Magento_Test_TestCase_ControllerAb ) ); $this->getRequest()->setPost($post); - $this->dispatch('/admin'); + $this->dispatch('backend/admin'); $this->assertContains(Mage::helper('Mage_Captcha')->__('Incorrect CAPTCHA.'), $this->getResponse()->getBody()); } /** - * @magentoConfigFixture current_store admin/captcha/enable 1 - * @magentoConfigFixture current_store admin/captcha/forms backend_login - * @magentoConfigFixture current_store admin/captcha/mode after_fail - * @magentoConfigFixture current_store admin/captcha/failed_attempts_login 1 + * @magentoConfigFixture admin_store admin/captcha/enable 1 + * @magentoConfigFixture admin_store admin/captcha/forms backend_login + * @magentoConfigFixture admin_store admin/captcha/mode after_fail + * @magentoConfigFixture admin_store admin/captcha/failed_attempts_login 1 * @magentoDbIsolation enabled * @magentoAppIsolation enabled */ public function testCaptchaIsRequiredAfterFailedLoginAttempts() { - $this->markTestIncomplete('MAGETWO-1662'); + if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { + $this->markTestIncomplete('MAGETWO-1662'); + } Mage::app()->setCurrentStore(0); $captchaModel = Mage::helper('Mage_Captcha_Helper_Data')->getCaptcha('backend_login'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Api/V2Test.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Api/V2Test.php new file mode 100644 index 00000000000..8907b50e2cc --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Api/V2Test.php @@ -0,0 +1,79 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Catalog + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Test class for Mage_Catalog_Model_Category_Api_V2. + */ +class Mage_Catalog_Model_Category_Api_V2Test extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Category_Api_V2 + */ + protected $_model; + + protected function setUp() + { + $this->_model = Mage::getModel('Mage_Catalog_Model_Category_Api_V2'); + Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); + } + + protected function tearDown() + { + $this->_model = null; + } + + public function testCRUD() + { + // @codingStandardsIgnoreStart + $category = new stdClass(); + $category->name = 'test category'; + $category->available_sort_by = 'name'; + $category->default_sort_by = 'name'; + $category->is_active = 1; + $category->include_in_menu = 1; + // @codingStandardsIgnoreEnd + + $categoryId = $this->_model->create(1, $category); + $this->assertNotEmpty($categoryId); + $data = $this->_model->info($categoryId); + $this->assertNotEmpty($data); + $this->assertEquals($category->name, $data['name']); + // @codingStandardsIgnoreStart + $this->assertEquals($category->default_sort_by, $data['default_sort_by']); + $this->assertEquals($category->is_active, $data['is_active']); + // @codingStandardsIgnoreEnd + + $category->name = 'new name'; + $this->_model->update($categoryId, $category); + $data = $this->_model->info($categoryId); + $this->assertNotEmpty($data); + $this->assertEquals($category->name, $data['name']); + + $this->assertTrue($this->_model->delete($categoryId)); + } + +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/ApiTest.php new file mode 100644 index 00000000000..6de32d1bfb7 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/ApiTest.php @@ -0,0 +1,502 @@ +<?php +/** + * Test class for Mage_Catalog_Model_Category_Api. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Catalog/_files/categories.php + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Category_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Category_Api + */ + protected $_model; + + /** + * Fixture data + * + * @var array + */ + protected $_fixtureData; + + protected function setUp() + { + $this->_model = Mage::getModel('Mage_Catalog_Model_Category_Api'); + Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); + } + + protected function tearDown() + { + $this->_model = null; + } + + public function testLevel() + { + $default = $this->_model->level(); + $this->assertNotEmpty($default); + + $forWebsite = $this->_model->level(1); + $this->assertNotEmpty($forWebsite); + + $this->assertEquals($default, $forWebsite); + $this->assertEquals( + $default, + array( + array( + 'category_id' => 2, + 'parent_id' => 1, + 'name' => 'Default Category', + 'is_active' => 1, + 'position' => 1, + 'level' => 1 + ) + ) + ); + + } + + public function testTree() + { + $tree = $this->_model->tree(); + $this->assertNotEmpty($tree); + $this->assertArrayHasKey('category_id', $tree); + $this->assertArrayHasKey('name', $tree); + $this->assertEquals(Mage_Catalog_Model_Category::TREE_ROOT_ID, $tree['category_id']); + } + + public function testCRUD() + { + $categoryId = $this->_model->create(1, array( + 'name' => 'test category', + 'available_sort_by' => 'name', + 'default_sort_by' => 'name', + 'is_active' => 1, + 'include_in_menu' => 1 + )); + $this->assertNotEmpty($categoryId); + $data = $this->_model->info($categoryId); + $this->assertNotEmpty($data); + $this->assertEquals('test category', $data['name']); + + $this->_model->update($categoryId, array( + 'name' => 'new name', + 'available_sort_by' => 'name', + 'default_sort_by' => 'name', + 'is_active' => 1, + 'include_in_menu' => 1 + )); + $data = $this->_model->info($categoryId); + $this->assertEquals('new name', $data['name']); + + $this->_model->delete($categoryId); + } + + public function testMove() + { + $this->assertTrue($this->_model->move(7, 6, 0)); + } + + public function testAssignedProducts() + { + $this->assertEmpty($this->_model->assignedProducts(1)); + $this->assertEquals( + array(array( + 'product_id' => 1, + 'type' => 'simple', + 'set' => 4, + 'sku' => 'simple', + 'position' => '1', + )), + $this->_model->assignedProducts(3) + ); + } + + /** + * @param int $categoryId + * @param int|string $productId + * @param string|null $identifierType + * @dataProvider assignProductDataProvider + */ + public function testAssignProduct($categoryId, $productId, $identifierType = null) + { + $this->assertEmpty($this->_model->assignedProducts($categoryId)); + $this->assertTrue($this->_model->assignProduct($categoryId, $productId, null, $identifierType)); + $this->assertNotEmpty($this->_model->assignedProducts($categoryId)); + } + + public function assignProductDataProvider() + { + return array( + 'product id' => array(1, 1), + 'product sku implicit' => array(6, 'simple'), + 'product sku explicit' => array(7, 12345, 'sku'), + ); + } + + /** + * @depends testAssignProduct + */ + public function testUpdateProduct() + { + $this->assertTrue($this->_model->updateProduct(6, 1, 2)); + $this->assertEquals( + array(array( + 'product_id' => 1, + 'type' => 'simple', + 'set' => 4, + 'sku' => 'simple', + 'position' => '2', + )), + $this->_model->assignedProducts(6) + ); + } + + /** + * @depends testAssignProduct + */ + public function testRemoveProduct() + { + $this->assertNotEmpty($this->_model->assignedProducts(6)); + $this->assertTrue($this->_model->removeProduct(6, 1)); + $this->assertEmpty($this->_model->assignedProducts(6)); + } + + /** + * Get formatter design date + * + * @param string $date + * @return string + */ + protected function _formatActiveDesignDate($date) + { + list($month, $day, $year) = explode('/', $date); + return "$year-$month-$day 00:00:00"; + } + + /** + * Get fixture data + * + * @return array + */ + protected function _getFixtureData() + { + if (null === $this->_fixtureData) { + $this->_fixtureData = require dirname(__FILE__) . '/_files/category_data.php'; + } + return $this->_fixtureData; + } + + /** + * Test category CRUD + */ + public function testCrudViaHandler() + { + $categoryFixture = $this->_getFixtureData(); + + $categoryId = $this->_testCreate($categoryFixture); + $this->_testUpdate($categoryId, $categoryFixture); + $this->_testRead($categoryId, $categoryFixture); + $this->_testDelete($categoryId); + } + + /** + * Test category create. + * + * @param array $categoryFixture + * @return int + */ + protected function _testCreate($categoryFixture) + { + $categoryId = Magento_Test_Helper_Api::call( + $this, + 'catalogCategoryCreate', + array( + $categoryFixture['create']['parentId'], + (object)$categoryFixture['create']['categoryData'], + $categoryFixture['create']['store'] + ) + ); + + $this->assertEquals( + $categoryId, + (int)$categoryId, + 'Result of a create method is not an integer.' + ); + + $category = Mage::getModel('Mage_Catalog_Model_Category'); + $category->load($categoryId); + + //check created data + $this->assertEquals( + $categoryId, + $category->getId(), + 'Category ID is not same like from API result.' + ); + + $this->assertEquals( + $category['custom_design_from'], + $this->_formatActiveDesignDate( + $categoryFixture['create']['categoryData']->custom_design_from + ), + 'Category active design date is not the same like sent to API on create.' + ); + + $this->assertEquals( + $category['custom_design_to'], + $this->_formatActiveDesignDate( + $categoryFixture['create']['categoryData']->custom_design_to + ), + 'Category active design date is not the same like sent to API on create.' + ); + + $this->assertNotEmpty( + $category['position'], + 'Category position is empty.' + ); + $this->assertFalse( + array_key_exists('custom_design_apply', $category->getData()), + 'Category data item "custom_design_apply" is deprecated.' + ); + + foreach ($categoryFixture['create']['categoryData'] as $name => $value) { + if (in_array($name, $categoryFixture['create_skip_to_check'])) { + continue; + } + $this->assertEquals( + $value, + $category[$name], + sprintf( + 'Category "%s" is "%s" and not the same like sent to create "%s".', + $name, + $category[$name], + $value + ) + ); + } + + return $categoryId; + } + + /** + * Test category read + * + * @param int $categoryId + * @param array $categoryFixture + */ + protected function _testRead($categoryId, $categoryFixture) + { + $categoryRead = Magento_Test_Helper_Api::call( + $this, + 'catalogCategoryInfo', + array('categoryId' => $categoryId, $categoryFixture['update']['storeView']) + ); + + $this->assertEquals( + $categoryRead['custom_design_from'], + $this->_formatActiveDesignDate( + $categoryFixture['update']['categoryData']->custom_design_from + ), + 'Category active design date is not the same like sent to API on update.' + ); + + $this->assertFalse( + array_key_exists('custom_design_apply', $categoryRead), + 'Category data item "custom_design_apply" is deprecated.' + ); + + foreach ($categoryFixture['update']['categoryData'] as $name => $value) { + if (in_array($name, $categoryFixture['update_skip_to_check'])) { + continue; + } + $this->assertEquals( + $value, + $categoryRead[$name], + sprintf('Category data with name "%s" is not the same like sent to update.', $name) + ); + } + } + + /** + * Test category update + * + * @param int $categoryId + * @param array $categoryFixture + */ + protected function _testUpdate($categoryId, $categoryFixture) + { + $categoryFixture['update']['categoryId'] = $categoryId; + $resultUpdated = Magento_Test_Helper_Api::call($this, 'catalogCategoryUpdate', $categoryFixture['update']); + $this->assertTrue($resultUpdated); + + $category = Mage::getModel('Mage_Catalog_Model_Category'); + $category->load($categoryId); + + //check updated data + $this->assertEquals( + $category['custom_design_from'], + $this->_formatActiveDesignDate( + $categoryFixture['update']['categoryData']->custom_design_from + ), + 'Category active design date is not the same like sent to API on update.' + ); + + foreach ($categoryFixture['update']['categoryData'] as $name => $value) { + if (in_array($name, $categoryFixture['update_skip_to_check'])) { + continue; + } + $this->assertEquals( + $value, + $category[$name], + sprintf('Category data with name "%s" is not the same like sent to update.', $name) + ); + } + } + + /** + * Test category delete + * + * @param int $categoryId + */ + protected function _testDelete($categoryId) + { + $categoryDelete = Magento_Test_Helper_Api::call( + $this, + 'catalogCategoryDelete', + array('categoryId' => $categoryId) + ); + $this->assertTrue($categoryDelete); + + $category = Mage::getModel('Mage_Catalog_Model_Category'); + $category->load($categoryId); + $this->assertEmpty($category->getId()); + } + + /** + * Test category bad request + * + * Test fault requests and vulnerability requests + */ + public function testBadRequestViaHandler() + { + $categoryFixture = $this->_getFixtureData(); + $params = $categoryFixture['create']; + + /** + * Test vulnerability SQL injection in is_active + */ + $params['categoryData']->is_active = $categoryFixture['vulnerability']['categoryData']->is_active; + + $categoryId = Magento_Test_Helper_Api::call($this, 'catalogCategoryCreate', $params); + $this->assertEquals( + $categoryId, + (int)$categoryId, + 'Category cannot created with vulnerability in is_active field' + ); + + $category = Mage::getModel('Mage_Catalog_Model_Category'); + $category->load($categoryId); + + $this->assertEquals( + $category['is_active'], + (int)$categoryFixture['vulnerability']['categoryData']->is_active + ); + + /** + * Test update with empty category ID + */ + $params = $categoryFixture['update']; + $params['categoryId'] = 9999; + try { + $result = Magento_Test_Helper_Api::call($this, 'catalogCategoryUpdate', $params); + } catch (SoapFault $e) { + //make result like in response + $result = array( + 'faultcode' => $e->faultcode, + 'faultstring' => $e->faultstring + ); + } + + $category->load($categoryId); + //name must has old value + $this->assertEquals( + $category['name'], + $categoryFixture['create']['categoryData']->name, + 'Category updated with empty ID.' + ); + //"102" is code error when category is not found on update + $this->assertInternalType('array', $result); + $this->assertEquals(102, $result['faultcode'], 'Fault code is not right.'); + + /** + * Test vulnerability with helper usage in custom layout update + */ + $params['categoryId'] = $categoryId; + $params['categoryData']->custom_layout_update = + $categoryFixture['vulnerability']['categoryData']->custom_layout_update; + try { + $result = Magento_Test_Helper_Api::call($this, 'catalogCategoryUpdate', $params); + } catch (SoapFault $e) { + //make result like in response + $result = array( + 'faultcode' => $e->faultcode, + 'faultstring' => $e->faultstring + ); + } + $category->load($categoryId); + + //"103" is code error when data validation is not passed + $this->assertInternalType('array', $result); + $this->assertEquals(103, $result['faultcode'], 'Fault code is not right.'); + + } + + /** + * Test delete root category + */ + public function testRootCategoryDeleteViaHandler() + { + try { + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogCategoryDelete', + array('categoryId' => Mage_Catalog_Model_Category::TREE_ROOT_ID) + ); + } catch (SoapFault $e) { + $result = array( + 'faultcode' => $e->faultcode, + 'faultstring' => $e->faultstring + ); + } + + $this->assertInternalType('array', $result); + $this->assertEquals(105, $result['faultcode'], 'Fault code is not right.'); + $this->assertEquals( + 'Cannot remove the system category.', + $result['faultstring'], + 'Exception message is not right.' + ); + + $category = Mage::getModel('Mage_Catalog_Model_Category'); + $this->assertNotNull($category->load(Mage_Catalog_Model_Category::TREE_ROOT_ID)->getId()); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Attribute/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Attribute/ApiTest.php new file mode 100644 index 00000000000..786e21ab45f --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/Attribute/ApiTest.php @@ -0,0 +1,104 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Catalog + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Test class for Mage_Catalog_Model_Category_Attribute_Api. + */ +class Mage_Catalog_Model_Category_Attribute_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Category_Attribute_Api + */ + protected $_model; + + protected function setUp() + { + $this->_model = Mage::getModel('Mage_Catalog_Model_Category_Attribute_Api'); + } + + protected function tearDown() + { + $this->_model = null; + } + + public function testItems() + { + $attributes = $this->_model->items(); + $this->assertNotEmpty($attributes); + $attribute = array_shift($attributes); + $this->assertContains('attribute_id', array_keys($attribute)); + $this->assertContains('code', array_keys($attribute)); + } + + /** + * Internal assert that validate options structure + * + * @param array $options + */ + protected function _assertOptionsStructure(array $options) + { + $first = current($options); + $this->assertArrayHasKey('value', $first); + $this->assertArrayHasKey('label', $first); + } + + public function testLayoutOptions() + { + $options = $this->_model->options('page_layout'); + $this->assertNotEmpty($options); + $this->_assertOptionsStructure($options); + } + + public function testModeOptions() + { + $options = $this->_model->options('display_mode'); + $this->assertNotEmpty($options); + $this->_assertOptionsStructure($options); + } + + public function testPageOptions() + { + $options = $this->_model->options('landing_page'); + $this->assertNotEmpty($options); + $this->_assertOptionsStructure($options); + } + + public function testSortByOptions() + { + $options = $this->_model->options('available_sort_by'); + $this->assertNotEmpty($options); + $this->_assertOptionsStructure($options); + } + + /** + * @expectedException Mage_Api_Exception + */ + public function testFault() + { + $this->_model->options('not_exists'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/_files/category_data.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/_files/category_data.php new file mode 100644 index 00000000000..a9c6f18f57f --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Category/_files/category_data.php @@ -0,0 +1,104 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** + * Api data + * + * @return array + */ +return array( + 'create' => array( + 'parentId' => 2, + 'categoryData' => (object)array( + 'name' => 'Category Test Created ' . uniqid(), + 'is_active' => 1, + 'is_anchor' => 1, + 'landing_page' => 1, //ID of CMS block + 'position' => 100, + 'description' => 'some description', + 'default_sort_by' => 'name', + 'available_sort_by' => array('name'), + 'display_mode' => Mage_Catalog_Model_Category::DM_PRODUCT, + 'include_in_menu' => 1, + 'page_layout' => 'one_column', + 'custom_design' => 'default/default', + 'custom_design_apply' => 'someValue', //deprecated attribute, should be empty + 'custom_design_from' => '11/16/2011', //date of start use design + 'custom_design_to' => '11/21/2011', //date of finish use design + 'custom_layout_update' => '<block type="core/text_list" name="content" output="toHtml"/>', + 'meta_description' => 'Meta description', + 'meta_keywords' => 'Meta keywords', + 'meta_title' => 'Meta title', + 'url_key' => 'url-key', + ), + 'store' => '0', + ), + 'update' => array( + 'categoryId' => null, + 'categoryData' => (object)array( + 'name' => 'Category Test updated ' . uniqid(), + 'is_active' => 0, + 'is_anchor' => 0, + 'position' => 200, + 'description' => 'some description Update', + 'default_sort_by' => 'position', + 'available_sort_by' => array('position', 'name'), + 'display_mode' => Mage_Catalog_Model_Category::DM_MIXED, + 'landing_page' => 2, //ID of static block + 'include_in_menu' => 0, + 'page_layout' => 'one_column', + 'custom_design' => 'base/default', + 'custom_design_apply' => 'someValueUpdate', //deprecated attribute, should be empty + 'custom_design_from' => '11/21/2011', //date of start use design + 'custom_design_to' => '', //date of finish use design + 'custom_layout_update' => '<block type="core/text_list" name="content" output="toHtml"> + <block type="core/text_list" name="content" output="toHtml"/> + </block>', + 'meta_description' => 'Meta description update', + 'meta_keywords' => 'Meta keywords update', + 'meta_title' => 'Meta title update', + 'url_key' => 'url-key-update', + ), + 'store' => '1', + ), + //skip test keys list. + 'create_skip_to_check' => array('custom_design_apply', 'custom_design_from', 'custom_design_to', 'position'), + 'update_skip_to_check' => array('custom_design_apply', 'custom_design_from', 'available_sort_by'), + 'vulnerability' => array( + 'categoryData' => (object)array( + 'is_active' => '8-1', + 'custom_layout_update' => '<block type="core/text_list" name="contentDdd" output="toHtml"> + <block type="core/text_tag_debug" name="test111"> + <action method="setValue"> + <arg helper="core/data/mergeFiles"> + <src><file>app/etc/local.xml</file></src> + <trg>tested11.php</trg> + <must>true</must> + </arg> + </action> + </block> + </block>' + ) + ) +); + diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Layer/Filter/Price/AlgorithmAdvancedTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Layer/Filter/Price/AlgorithmAdvancedTest.php index 356f3e4d4ee..d3cd274b353 100644 --- a/dev/tests/integration/testsuite/Mage/Catalog/Model/Layer/Filter/Price/AlgorithmAdvancedTest.php +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Layer/Filter/Price/AlgorithmAdvancedTest.php @@ -53,7 +53,6 @@ class Mage_Catalog_Model_Layer_Filter_Price_AlgorithmAdvancedTest extends PHPUni * Prepare price filter model * * @param Magento_Test_Request|null $request - * @return void */ protected function _prepareFilter($request = null) { diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Attribute/TierPriceTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Attribute/TierPriceTest.php new file mode 100644 index 00000000000..e2c450e66f4 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Attribute/TierPriceTest.php @@ -0,0 +1,87 @@ +<?php +/** + * Product tier price attribute API test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Product_Api_Attribute_TierPriceTest extends PHPUnit_Framework_TestCase +{ + /** @var Mage_Catalog_Model_Product */ + protected $_product; + + /** + * Set up product fixture + */ + protected function setUp() + { + $productData = require realpath(dirname(__FILE__) . '/../_files/ProductData.php'); + $product = Mage::getModel('Mage_Catalog_Model_Product'); + + $product->setData($productData['create_full_fledged']); + $product->save(); + + $this->_product = $product; + + parent::setUp(); + } + + /** + * Test product tier price attribute update + */ + public function testUpdate() + { + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeTierPriceUpdate', + array( + 'productId' => $this->_product->getId(), + 'tierPrices' => array( + (object)array( + 'customer_group_id' => Mage_Customer_Model_Group::CUST_GROUP_ALL, + 'qty' => 3, + 'price' => 0.88, + ), + (object)array( + 'customer_group_id' => Mage_Customer_Model_Group::CUST_GROUP_ALL, + 'qty' => 5, + 'price' => 0.77, + ) + ), + ) + ); + + $this->assertTrue((bool)$result, 'Product tier price attribute update API failed'); + // Reload product to check tier prices were applied + $this->_product->load($this->_product->getId()); + $this->assertEquals( + $this->_product->getTierPrice(3), + 0.88, + 'Product tier price (3) attribute update was not applied' + ); + $this->assertEquals( + $this->_product->getTierPrice(5), + 0.77, + 'Product tier price (5) attribute update was not applied' + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeSetCRUDTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeSetCRUDTest.php new file mode 100644 index 00000000000..fefe0d38dcb --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeSetCRUDTest.php @@ -0,0 +1,235 @@ +<?php +/** + * Product attribute set API model test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Catalog_Model_Product_Api_AttributeSetCRUDTest extends PHPUnit_Framework_TestCase +{ + /** + * Remove attribute set + * + * @param int $attrSetId + */ + protected function _removeAttrSet($attrSetId) + { + /** @var $attrSet Mage_Eav_Model_Entity_Attribute_Set */ + $attrSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set'); + + $attrSet->setId($attrSetId); + $attrSet->delete(); + } + + /** + * Remove attributes + * + * @param array $attrIds + */ + protected function _removeAttributes($attrIds) + { + /** @var $attr Mage_Eav_Model_Entity_Attribute */ + $attr = Mage::getModel('Mage_Eav_Model_Entity_Attribute'); + + if (!is_array($attrIds)) { + $attrIds = array($attrIds); + } + foreach ($attrIds as $attrId) { + $attr->setId($attrId); + $attr->delete(); + } + } + + /** + * Test Attribute set CRUD + * + * @magentoDbIsolation enabled + */ + public function testAttributeSetCRUD() + { + $attributeSetFixture = simplexml_load_file(dirname(__FILE__) . '/_files/_data/xml/AttributeSet.xml'); + $data = Magento_Test_Helper_Api::simpleXmlToArray($attributeSetFixture->create); + $data['attributeSetName'] = $data['attributeSetName'] . ' ' . mt_rand(1000, 9999); + + // create test + $createdAttrSetId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetCreate', + array($data['attributeSetName'], $data['skeletonSetId']) + ); + $this->assertGreaterThan(0, $createdAttrSetId); + + // Duplicate name exception test + try { + Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetCreate', + array($data['attributeSetName'], $data['skeletonSetId']) + ); + $this->fail("Didn't receive exception!"); + } catch (Exception $e) { + } + + // items list test + $attrSetList = Magento_Test_Helper_Api::call($this, 'catalogProductAttributeSetList'); + $completeFlag = false; + foreach ($attrSetList as $attrSet) { + if ($attrSet['set_id'] == $createdAttrSetId) { + $this->assertEquals($data['attributeSetName'], $attrSet['name']); + $completeFlag = true; + break; + } + } + $this->assertTrue($completeFlag, "Can't find added attribute set in list"); + + // Remove AttrSet with related products + $productData = Magento_Test_Helper_Api::simpleXmlToArray($attributeSetFixture->relatedProduct); + $productData['sku'] = $productData['sku'] . '_' . mt_rand(1000, 9999); + $productId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCreate', + array( + 'type' => $productData['typeId'], + 'set' => $createdAttrSetId, + 'sku' => $productData['sku'], + 'productData' => $productData['productData'] + ) + ); + + try { + Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetRemove', + array('attributeSetId' => $createdAttrSetId) + ); + $this->fail("Didn't receive exception!"); + } catch (Exception $e) { + } + + Magento_Test_Helper_Api::call($this, 'catalogProductDelete', array('productId' => $productId)); + + // delete test + $attributeSetDelete = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetRemove', + array('attributeSetId' => $createdAttrSetId) + ); + $this->assertTrue((bool)$attributeSetDelete, "Can't delete added attribute set"); + + // Test delete undefined attribute set and check successful delete in previous call + try { + Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetRemove', + array('attributeSetId' => $createdAttrSetId) + ); + $this->fail("Didn't receive exception!"); + } catch (Exception $e) { + } + + } + + /** + * Test attribute CRUD in attribute set + * + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/AttributeSet.php + */ + public function testAttributeSetAttrCRUD() + { + $testAttributeSetId = Mage::registry('testAttributeSetId'); + $attrIdsArray = Mage::registry('testAttributeSetAttrIdsArray'); + + // add attribute test + $addResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetAttributeAdd', + array('attributeId' => $attrIdsArray[0], 'attributeSetId' => $testAttributeSetId) + ); + $this->assertTrue((bool)$addResult); + + // delete attribute test + $removeResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetAttributeRemove', + array('attributeId' => $attrIdsArray[0], 'attributeSetId' => $testAttributeSetId) + ); + $this->assertTrue((bool)$removeResult); + } + + /** + * Test group of attribute sets CRUD + * + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/AttributeSet.php + */ + public function testAttributeSetGroupCRUD() + { + $testAttributeSetId = Mage::registry('testAttributeSetId'); + $attributeSetFixture = simplexml_load_file(dirname(__FILE__) . '/_files/_data/xml/AttributeSet.xml'); + $data = Magento_Test_Helper_Api::simpleXmlToArray($attributeSetFixture->groupAdd); + + // add group test + $attrSetGroupId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetGroupAdd', + array('attributeSetId' => $testAttributeSetId, 'groupName' => $data['groupName']) + ); + $this->assertGreaterThan(0, $attrSetGroupId); + + // add already exist group exception test + try { + $attrSetGroupId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetGroupAdd', + array('attributeSetId' => $testAttributeSetId, 'groupName' => $data['existsGroupName']) + ); + $this->fail("Didn't receive exception!"); + } catch (Exception $e) { + } + + // rename group test + $groupName = $data['groupName'] . ' ' . mt_rand(1000, 9999); + $renameResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetGroupRename', + array('groupId' => $attrSetGroupId, 'groupName' => $groupName) + ); + $this->assertTrue((bool)$renameResult); + + // remove group test + $removeResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetGroupRemove', + array('attributeGroupId' => $attrSetGroupId) + ); + $this->assertTrue((bool)$removeResult); + + $this->_removeAttrSet($testAttributeSetId); + $this->_removeAttributes(Mage::registry('testAttributeSetAttrIdsArray')); + + // remove undefined group exception test + $this->setExpectedException('SoapFault'); + Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeSetGroupRemove', + array('attributeGroupId' => $attrSetGroupId) + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeTest.php new file mode 100644 index 00000000000..2b40d645214 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/AttributeTest.php @@ -0,0 +1,57 @@ +<?php +/** + * Test API getting orders list method + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Product_Api_AttributeTest extends PHPUnit_Framework_TestCase +{ + /** + * Tests attribute creation with invalid characters in attribute code (possible SQL injection) + */ + public function testCreateWithInvalidCode() + { + $attributeData = array( + 'attribute_code' => 'mytest1.entity_id = e.entity_id); DROP TABLE aaa_test;', + 'scope' => 'global', + 'frontend_input' => 'select', + 'frontend_label' => array( + array('store_id' => 0, 'label' => 'My Attribute With SQL Injection') + ) + ); + + try { + Magento_Test_Helper_Api::call($this, 'catalogProductAttributeCreate', array('data' => $attributeData)); + + $this->fail('Exception with message like "invalid attribute code" expected but not thrown'); + } catch (Exception $e) { + $this->assertEquals(103, $e->faultcode, 'Unexpected fault code'); + $this->assertEquals( + 'Attribute code is invalid. Please use only letters (a-z), numbers (0-9), ' + . 'or underscore(_) in this field. First character should be a letter.', + $e->getMessage(), + 'Unexpected exception messsage' + ); + } + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/BackorderStatusTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/BackorderStatusTest.php new file mode 100644 index 00000000000..0d0c49a9d8f --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/BackorderStatusTest.php @@ -0,0 +1,77 @@ +<?php +/** + * Test updating product back-order status through API + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Product_Api_BackorderStatusTest extends PHPUnit_Framework_TestCase +{ + /** @var Mage_Catalog_Model_Product */ + protected $_product; + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + $productData = require dirname(__FILE__) . '/_files/ProductData.php'; + $product = Mage::getModel('Mage_Catalog_Model_Product'); + + $product->setData($productData['create_full_fledged']); + $product->save(); + + $this->_product = $product; + + parent::setUp(); + } + + /** + * Test updating product back-order status + */ + public function testBackorderStatusUpdate() + { + $newProductData = array( + 'use_config_manage_stock' => 0, + 'manage_stock' => 1, + 'is_in_stock' => 0, + 'use_config_backorders' => 0, + 'backorders' => 1, + ); + + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogInventoryStockItemUpdate', + array( + 'productId' => $this->_product->getSku(), + 'data' => $newProductData + ) + ); + + $this->assertEquals(1, $result); + // have to re-load product for stock item set + $this->_product->load($this->_product->getId()); + $this->assertEquals(1, $this->_product->getStockItem()->getBackorders()); + $this->assertEquals(0, $this->_product->getStockItem()->getUseConfigBackorders()); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ConfigurableTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ConfigurableTest.php new file mode 100644 index 00000000000..ceb45e7096c --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ConfigurableTest.php @@ -0,0 +1,62 @@ +<?php +/** + * Test configurable product API + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @method Mage_Catalog_Model_Product_Api_Helper_Configurable _getHelper() + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Product_Api_ConfigurableTest extends Mage_Catalog_Model_Product_Api_TestCaseAbstract +{ + /** + * Default helper for current test suite + * + * @var string + */ + protected $_defaultHelper = 'Mage_Catalog_Model_Product_Api_Helper_Configurable'; + + /** + * Test successful configurable product create. + * Scenario: + * 1. Create EAV attributes and attribute set usable for configurable. + * 2. Send request to create product with type 'configurable' and all valid attributes data. + * Expected result: + * Load product and assert it was created correctly. + */ + public function testCreate() + { + $productData = $this->_getHelper()->getValidCreateData(); + $productId = $this->_createProductWithApi($productData); + // Validate outcome + /** @var $actual Mage_Catalog_Model_Product */ + $actual = Mage::getModel('Mage_Catalog_Model_Product')->load($productId); + $this->_getHelper()->checkConfigurableAttributesData( + $actual, + $productData['configurable_attributes'], + false + ); + unset($productData['configurable_attributes']); + $expected = Mage::getModel('Mage_Catalog_Model_Product'); + $expected->setData($productData); + $this->assertProductEquals($expected, $actual); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/DownloadableLinkCRUDTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/DownloadableLinkCRUDTest.php new file mode 100644 index 00000000000..ce268a4b1c8 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/DownloadableLinkCRUDTest.php @@ -0,0 +1,127 @@ +<?php +/** + * Downloadable product links API model test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Catalog_Model_Product_Api_DownloadableLinkCRUDTest extends PHPUnit_Framework_TestCase +{ + /** + * Test downloadable link create + * + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/LinkCRUD.php + */ + public function testDownloadableLinkCreate() + { + $tagFixture = simplexml_load_file(dirname(__FILE__) . '/_files/_data/xml/LinkCRUD.xml'); + $items = Magento_Test_Helper_Api::simpleXmlToArray($tagFixture->items); + + $productId = Mage::registry('productData')->getId(); + + foreach ($items as $item) { + foreach ($item as $key => $value) { + if ($value['type'] == 'file') { + $filePath = dirname(__FILE__) . '/_files/_data/files/' . $value['file']['filename']; + $value['file'] = array( + 'name' => str_replace('/', '_', $value['file']['filename']), + 'base64_content' => base64_encode(file_get_contents($filePath)), + 'type' => $value['type'] + ); + } + if ($key == 'link' && $value['sample']['type'] == 'file') { + $filePath = dirname(__FILE__) . '/_files/_data/files/' . $value['sample']['file']['filename']; + $value['sample']['file'] = array( + 'name' => str_replace('/', '_', $value['sample']['file']['filename']), + 'base64_content' => base64_encode(file_get_contents($filePath)) + ); + } + + $resultId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductDownloadableLinkAdd', + array( + 'productId' => $productId, + 'resource' => $value, + 'resourceType' => $key + ) + ); + $this->assertGreaterThan(0, $resultId); + } + } + } + + /** + * Test get downloadable link items + * + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks.php + */ + public function testDownloadableLinkItems() + { + /** @var Mage_Catalog_Model_Product $product */ + $product = Mage::registry('downloadable'); + $productId = $product->getId(); + + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductDownloadableLinkList', + array('productId' => $productId) + ); + /** @var Mage_Downloadable_Model_Product_Type $downloadable */ + $downloadable = $product->getTypeInstance(); + $links = $downloadable->getLinks($product); + + $this->assertEquals(count($links), count($result['links'])); + foreach ($result['links'] as $actualLink) { + foreach ($links as $expectedLink) { + if ($actualLink['link_id'] == $expectedLink) { + $this->assertEquals($expectedLink->getData('title'), $actualLink['title']); + $this->assertEquals($expectedLink->getData('price'), $actualLink['price']); + } + } + } + } + + /** + * Remove downloadable link + * + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks.php + */ + public function testDownloadableLinkRemove() + { + /** @var Mage_Catalog_Model_Product $product */ + $product = Mage::registry('downloadable'); + /** @var Mage_Downloadable_Model_Product_Type $downloadable */ + $downloadable = $product->getTypeInstance(); + $links = $downloadable->getLinks($product); + foreach ($links as $link) { + $removeResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductDownloadableLinkRemove', + array( + 'linkId' => $link->getId(), + 'resourceType' => 'link' + ) + ); + $this->assertTrue((bool)$removeResult); + } + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Configurable.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Configurable.php new file mode 100644 index 00000000000..fa5c87197d3 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Configurable.php @@ -0,0 +1,192 @@ +<?php +/** + * Helper for configurable product tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Catalog_Model_Product_Api_Helper_Configurable extends PHPUnit_Framework_TestCase +{ + /** + * Retrieve valid configurable data + * + * @return array + */ + public function getValidCreateData() + { + require __DIR__ . '/../_files/attribute_set_with_configurable.php'; + // Prepare fixture + $productData = $this->_getValidProductPostData(); + /** @var Mage_Eav_Model_Entity_Attribute_Set $attributeSet */ + $attributeSet = Mage::registry('attribute_set_with_configurable'); + /** @var Mage_Catalog_Model_Resource_Eav_Attribute $attributeOne */ + $attributeOne = Mage::registry('eav_configurable_attribute_1'); + /** @var Mage_Catalog_Model_Resource_Eav_Attribute $attributeTwo */ + $attributeTwo = Mage::registry('eav_configurable_attribute_2'); + $productData['attribute_set_id'] = $attributeSet->getId(); + /** @var Mage_Eav_Model_Entity_Attribute_Source_Table $attributeOneSource */ + $attributeOneSource = $attributeOne->getSource(); + $attributeOnePrices = array(); + foreach ($attributeOneSource->getAllOptions(false) as $option) { + $attributeOnePrices[] = array( + 'option_value' => $option['value'], + 'price' => rand(1, 50), + 'price_type' => rand(0, 1) ? 'percent' : 'fixed' // is percentage used + ); + } + $productData['configurable_attributes'] = array( + array( + 'attribute_code' => $attributeOne->getAttributeCode(), + 'prices' => $attributeOnePrices, + 'frontend_label' => "Must not be used", + 'frontend_label_use_default' => 1, + 'position' => 2 + ), + array( + 'attribute_code' => $attributeTwo->getAttributeCode(), + 'frontend_label' => "Custom Label", + 'position' => '4' + ) + ); + return $productData; + } + + /** + * Check if the configurable attributes' data was saved correctly during create + * + * @param Mage_Catalog_Model_Product $configurable + * @param array $expectedAttributes + * @param bool $validatePrices + */ + public function checkConfigurableAttributesData( + $configurable, + $expectedAttributes, + $validatePrices = true + ) { + /** @var Mage_Catalog_Model_Product_Type_Configurable $configurableType */ + $configurableType = $configurable->getTypeInstance(); + $actualAttributes = $configurableType->getConfigurableAttributesAsArray($configurable); + foreach ($expectedAttributes as $expectedAttribute) { + $attributeCode = $expectedAttribute['attribute_code']; + $attributeDataFound = false; + foreach ($actualAttributes as $actualAttribute) { + if ($actualAttribute['attribute_code'] == $attributeCode) { + $this->_assetAttributes($expectedAttribute, $actualAttribute); + if ($validatePrices && isset($expectedAttribute['prices']) + && is_array($expectedAttribute['prices']) + ) { + $this->_assertPrices($actualAttribute['values'], $expectedAttribute['prices']); + } + $attributeDataFound = true; + break; + } + } + $this->assertTrue( + $attributeDataFound, + "Attribute with code $attributeCode is not used as a configurable one." + ); + } + } + + protected function _assetAttributes($expectedAttribute, $actualAttribute) + { + if (isset($expectedAttribute['position'])) { + $this->assertEquals( + $expectedAttribute['position'], + $actualAttribute['position'], + "Position is invalid." + ); + } + if (isset($expectedAttribute['frontend_label_use_default']) + && $expectedAttribute['frontend_label_use_default'] == 1 + ) { + $this->assertEquals( + $expectedAttribute['frontend_label_use_default'], + $actualAttribute['use_default'], + "The value of 'use default frontend label' is invalid." + ); + if (isset($expectedAttribute['frontend_label'])) { + $this->assertNotEquals( + $expectedAttribute['frontend_label'], + $actualAttribute['label'], + "Default frontend label must be used." + ); + } + } else { + if (isset($expectedAttribute['frontend_label'])) { + $this->assertEquals( + $expectedAttribute['frontend_label'], + $actualAttribute['label'], + "Frontend label is invalid." + ); + } + } + } + + /** + * Validate prices + * + * @param $actualValues + * @param $expectedPrices + */ + protected function _assertPrices($actualValues, $expectedPrices) + { + $values = array(); + foreach ($actualValues as $value) { + $values[$value['value_index']] = $value; + } + foreach ($expectedPrices as $expectedValue) { + if (isset($expectedValue['option_value'])) { + $this->assertArrayHasKey( + $expectedValue['option_value'], + $values, + 'Expected price value not found in actual values.' + ); + $actualValue = $values[$expectedValue['option_value']]; + if (isset($expectedValue['price'])) { + $this->assertEquals( + $expectedValue['price'], + $actualValue['pricing_value'], + 'Option price does not match.' + ); + } + if (isset($expectedValue['price_type'])) { + $isPercent = ($expectedValue['price_type'] == 'percent') ? 1 : 0; + $this->assertEquals( + $isPercent, + $actualValue['is_percent'], + 'Option price type does not match.' + ); + } + } + } + } + + /** + * Get valid data for configurable product POST + * + * @return array + */ + protected function _getValidProductPostData() + { + return require __DIR__ . '/../_files/_data/product_configurable_all_fields.php'; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Simple.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Simple.php new file mode 100644 index 00000000000..5865fbd4391 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/Helper/Simple.php @@ -0,0 +1,124 @@ +<?php +/** + * Simple product tests helper. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Catalog_Model_Product_Api_Helper_Simple extends PHPUnit_Framework_TestCase +{ + /** + * Load simple product fixture data + * + * @param string $fixtureName + * @return array + */ + public function loadSimpleProductFixtureData($fixtureName) + { + return require '_fixture/_data/Catalog/Product/Simple/' . $fixtureName . '.php'; + } + + /** + * Check simple product attributes + * + * @param Mage_Catalog_Model_Product $product + * @param array $expectedProductData + * @param array $skipAttributes + * @param array $skipStockItemAttrs + */ + public function checkSimpleAttributesData( + $product, + $expectedProductData, + $skipAttributes = array(), + $skipStockItemAttrs = array() + ) { + $expectedProductData = array_diff_key($expectedProductData, array_flip($skipAttributes)); + + $dateAttributes = array( + 'news_from_date', + 'news_to_date', + 'special_from_date', + 'special_to_date', + 'custom_design_from', + 'custom_design_to' + ); + foreach ($dateAttributes as $attribute) { + if (isset($expectedProductData[$attribute])) { + $this->assertEquals( + strtotime($expectedProductData[$attribute]), + strtotime($product->getData($attribute)) + ); + } + } + + $exclude = array_merge( + $dateAttributes, + array( + 'group_price', + 'tier_price', + 'stock_data', + 'url_key', + 'url_key_create_redirect' + ) + ); + // Validate URL Key - all special chars should be replaced with dash sign + $this->assertEquals('123-abc', $product->getUrlKey()); + $productAttributes = array_diff_key($expectedProductData, array_flip($exclude)); + foreach ($productAttributes as $attribute => $value) { + $this->assertEquals($value, $product->getData($attribute), 'Invalid attribute "' . $attribute . '"'); + } + + if (isset($expectedProductData['stock_data'])) { + $stockItem = $product->getStockItem(); + $expectedStock = array_diff_key($expectedProductData['stock_data'], array_flip($skipStockItemAttrs)); + foreach ($expectedStock as $attribute => $value) { + $this->assertEquals( + $value, + $stockItem->getData($attribute), + 'Invalid stock_data attribute "' . $attribute . '"' + ); + } + } + } + + /** + * Check stock item use default flags + * + * @param Mage_Catalog_Model_Product $product + */ + public function checkStockItemDataUseDefault($product) + { + $stockItem = $product->getStockItem(); + $this->assertNotNull($stockItem); + $fields = array( + 'use_config_min_qty', + 'use_config_min_sale_qty', + 'use_config_max_sale_qty', + 'use_config_backorders', + 'use_config_notify_stock_qty', + 'use_config_enable_qty_inc' + ); + foreach ($fields as $field) { + $this->assertEquals(1, $stockItem->getData($field), $field . ' is not set to 1'); + } + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ImageTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ImageTest.php new file mode 100644 index 00000000000..82ac6d66290 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/ImageTest.php @@ -0,0 +1,185 @@ +<?php +/** + * Test API work with product images + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Product_Api_ImageTest extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Product + */ + protected $_product; + + protected $_requestData; + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + $productFixture = require dirname(__FILE__) . '/_files/ProductData.php'; + $product = Mage::getModel('Mage_Catalog_Model_Product'); + + $product->setData($productFixture['create_full_fledged']); + $product->save(); + + $this->_product = $product; + $this->_requestData = array( + 'label' => 'My Product Image', + 'position' => 2, + 'types' => array('small_image', 'image', 'thumbnail'), + 'exclude' => 1, + 'remove' => 0, + 'file' => array( + 'name' => 'my_image_file', + 'content' => null, + 'mime' => 'image/jpeg' + ) + ); + + parent::setUp(); + } + + /** + * Tests valid image for product creation + * + * @dataProvider validImageProvider + * @param string $validImgPath Absolute path to valid image file + */ + public function testCreateValidImage($validImgPath) + { + $product = $this->_product; + $requestData = $this->_requestData; + + // valid JPG image file + $requestData['file']['content'] = base64_encode(file_get_contents($validImgPath)); + + $imagePath = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeMediaCreate', + array('productId' => $product->getSku(), 'data' => $requestData) + ); + $this->assertInternalType('string', $imagePath, 'String type of response expected but not received'); + + // reload product to reflect changes done by API request + $product->load($product->getId()); + + // retrieve saved image + $attributes = $product->getTypeInstance()->getSetAttributes($product); + $imageParams = $attributes['media_gallery']->getBackend()->getImage($product, $imagePath); + + $this->assertInternalType('array', $imageParams, 'Image not found'); + $this->assertEquals($requestData['label'], $imageParams['label'], 'Label does not match'); + $this->assertEquals($requestData['position'], $imageParams['position'], 'Position does not match'); + $this->assertEquals($requestData['exclude'], $imageParams['disabled'], 'Disabled does not match'); + } + + /** + * Tests not an image for product creation + */ + public function testCreateNotAnImage() + { + $product = $this->_product; + $requestData = $this->_requestData; + + // TXT file + $requestData['file']['content'] = base64_encode( + file_get_contents(dirname(__FILE__) . '/_files/_data/files/test.txt') + ); + + try { + Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeMediaCreate', + array('productId' => $product->getSku(), 'data' => $requestData) + ); + } catch (Exception $e) { + $this->assertEquals('Unsupported image format.', $e->getMessage(), 'Invalid exception message'); + } + // reload product to reflect changes done by API request + $product->load($product->getId()); + + $mediaData = $product->getData('media_gallery'); + + $this->assertCount(0, $mediaData['images'], 'Invalid image file has been saved'); + } + + /** + * Tests an invalid image for product creation + * + * @dataProvider invalidImageProvider + * @param strign $invalidImgPath Absolute path to invalid image file + */ + public function testCreateInvalidImage($invalidImgPath) + { + $product = $this->_product; + $requestData = $this->_requestData; + + // Not an image file with JPG extension + $requestData['file']['content'] = base64_encode(file_get_contents($invalidImgPath)); + + try { + Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeMediaCreate', + array('productId' => $product->getSku(), 'data' => $requestData) + ); + } catch (Exception $e) { + $this->assertEquals('Unsupported image format.', $e->getMessage(), 'Invalid exception message'); + } + // reload product to reflect changes done by API request + $product->load($product->getId()); + + $mediaData = $product->getData('media_gallery'); + + $this->assertCount(0, $mediaData['images'], 'Invalid image file has been saved'); + } + + /** + * Data provider + * + * @return array + */ + public function invalidImageProvider() + { + return array( + array(dirname(__FILE__) . '/_files/_data/files/images/test.bmp.jpg'), + array(dirname(__FILE__) . '/_files/_data/files/images/test.php.jpg') + ); + } + + /** + * Data provider + * + * @return array + */ + public function validImageProvider() + { + return array( + array(dirname(__FILE__) . '/_files/_data/files/images/test.jpg.jpg'), + array(dirname(__FILE__) . '/_files/_data/files/images/test.png.jpg') + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/SimpleTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/SimpleTest.php new file mode 100644 index 00000000000..bfbd8bca2db --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/SimpleTest.php @@ -0,0 +1,458 @@ +<?php +/** + * Test Product CRUD operations + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @method Mage_Catalog_Model_Product_Api_Helper_Simple _getHelper() + */ +class Mage_Catalog_Model_Product_Api_SimpleTest extends Mage_Catalog_Model_Product_Api_TestCaseAbstract +{ + /** + * Default helper for current test suite + * + * @var string + */ + protected $_defaultHelper = 'Mage_Catalog_Model_Product_Api_Helper_Simple'; + + /** + * Test product resource post + * @magentoDbIsolation enabled + */ + public function testCreateSimpleRequiredFieldsOnly() + { + $productData = require '_files/_data/simple_product_data.php'; + $productId = $this->_createProductWithApi($productData); + + $actualProduct = Mage::getModel('Mage_Catalog_Model_Product'); + $actualProduct->load($productId); + $this->assertNotNull($actualProduct->getId()); + $expectedProduct = Mage::getModel('Mage_Catalog_Model_Product'); + $expectedProduct->setData($productData); + + $this->assertProductEquals($expectedProduct, $actualProduct); + } + + /** + * Test product resource post with all fields + * + * @param array $productData + * @dataProvider dataProviderTestCreateSimpleAllFieldsValid + * @magentoDbIsolation enabled + */ + public function testCreateSimpleAllFieldsValid($productData) + { + $productId = $this->_createProductWithApi($productData); + + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + $this->assertNotNull($product->getId()); + $skipAttributes = array( + 'news_from_date', + 'news_to_date', + 'custom_design_from', + 'custom_design_to', + 'msrp_enabled', + 'msrp_display_actual_price_type', + 'msrp', + 'meta_title', + 'meta_keyword', + 'meta_description', + 'page_layout', + 'gift_wrapping_available', + 'gift_wrapping_price' + ); + $skipStockItemAttrs = array('min_qty'); + + $this->_getHelper()->checkSimpleAttributesData( + $product, + $productData, + $skipAttributes, + $skipStockItemAttrs + ); + } + + /** + * Data provider for testCreateSimpleAllFieldsValid + * + * @magentoDbIsolation enabled + * @return array + */ + public function dataProviderTestCreateSimpleAllFieldsValid() + { + $productData = require '_files/_data/simple_product_all_fields_data.php'; + // Fix for tests, because in current soap version this field has "int" type in WSDL + // @TODO: fix WSDL in new soap version when implemented + $productData['stock_data']['notify_stock_qty'] = 2; + $specialCharsData = require '_files/_data/simple_product_special_chars_data.php'; + + return array( + array($specialCharsData), + array($productData), + ); + } + + /** + * Test product resource post using config values in inventory + * + * @magentoDbIsolation enabled + */ + public function testCreateInventoryUseConfigValues() + { + $productData = require '_files/_data/simple_product_inventory_use_config.php'; + $productId = $this->_createProductWithApi($productData); + + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + $this->assertNotNull($product->getId()); + + $this->_getHelper()->checkStockItemDataUseDefault($product); + } + + /** + * Test product resource post using config values in inventory manage stock field + * + * @magentoConfigFixture current_store cataloginventory/item_options/manage_stock 0 + * @magentoDbIsolation enabled + */ + public function testCreateInventoryManageStockUseConfig() + { + $productData = require '_files/_data/simple_product_manage_stock_use_config.php'; + + $productId = $this->_createProductWithApi($productData); + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + $this->assertNotNull($product->getId()); + + $stockItem = $product->getStockItem(); + $this->assertNotNull($stockItem); + $this->assertEquals(0, $stockItem->getManageStock()); + } + + /** + * Test for set special price for product + * + * @magentoDbIsolation enabled + */ + public function testSetSpecialPrice() + { + $productData = require dirname(__FILE__) . '/_files/ProductData.php'; + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $specialPrice = 1.99; + $specialFrom = '2011-12-22 00:00:00'; + $specialTo = '2011-12-25 00:00:00'; + + $product->setData($productData['create_full_fledged']); + $product->save(); + + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductSetSpecialPrice', + array( + 'productId' => $product->getSku(), + 'specialPrice' => $specialPrice, + 'fromDate' => $specialFrom, + 'toDate' => $specialTo, + 'store' => Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID + ) + ); + + $this->assertEquals(true, $result, 'Response is not true casted value'); + + // reload product to reflect changes done by API request + $product->load($product->getId()); + + $this->assertEquals($specialPrice, $product->getSpecialPrice(), 'Special price not changed'); + $this->assertEquals($specialFrom, $product->getSpecialFromDate(), 'Special price from not changed'); + $this->assertEquals($specialTo, $product->getSpecialToDate(), 'Special price to not changed'); + } + + /** + * Test get product info by numeric SKU + * + * @magentoDbIsolation enabled + */ + public function testProductInfoByNumericSku() + { + $data = require dirname(__FILE__) . '/_files/ProductData.php'; + + //generate numeric sku + $data['create_with_attributes_soapv2']->sku = rand(1000000, 99999999); + + $productId = Magento_Test_Helper_Api::call($this, 'catalogProductCreate', $data['create']); + + $this->assertEquals( + $productId, + (int)$productId, + 'Result of a create method is not an integer.' + ); + + //test new product exists in DB + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + $this->assertNotNull($product->getId(), 'Tested product not found.'); + + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductInfo', + array( + 'productId' => $data['create']['sku'], + 'store' => 0, //default 0 + 'attributes' => '', + 'identifierType' => 'sku', + ) + ); + + $this->assertInternalType('array', $result, 'Response is not an array'); + $this->assertArrayHasKey('product_id', $result, 'Response array does not have "product_id" key'); + $this->assertEquals($productId, $result['product_id'], 'Product cannot be load by SKU which is numeric'); + } + + /** + * Test product CRUD + * + * @magentoDbIsolation enabled + */ + public function testProductCrud() + { + $data = require dirname(__FILE__) . '/_files/ProductData.php'; + + // create product for test + $productId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCreate', + $data['create_with_attributes_soapv2'] + ); + + // test new product id returned + $this->assertGreaterThan(0, $productId); + + //test new product exists in DB + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + $this->assertNotNull($product->getId()); + + //update product + $data['create_with_attributes_soapv2'] = array('productId' => $productId) + $data['update']; + + $isOk = Magento_Test_Helper_Api::call($this, 'catalogProductUpdate', $data['create_with_attributes_soapv2']); + + //test call response is true + $this->assertTrue($isOk, 'Call returned false'); + + //test product exists in DB after update and product data changed + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + $this->assertNotNull($product->getId()); + $this->assertEquals($data['update']['productData']->name, $product->getName()); + + //delete product + $isOk = Magento_Test_Helper_Api::call($this, 'catalogProductDelete', array('productId' => $productId)); + + //test call response is true + $this->assertTrue((bool)$isOk, 'Call returned false'); //in SOAP v2 it's integer:1 + + //test product not exists in DB after delete + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + $this->assertNull($product->getId()); + } + + /** + * Test product CRUD with custom options + * + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud.php + * @magentoDbIsolation enabled + */ + public function testProductWithOptionsCrud() + { + $this->markTestSkipped("TODO: Fix test"); + $optionValueApi = Mage::registry('optionValueApi'); + $optionValueInstaller = Mage::registry('optionValueInstaller'); + $data = require dirname(__FILE__) . '/_files/ProductData.php'; + + $singleData = & $data['create_with_attributes_soapv2']['productData']->additional_attributes->singleData; + $singleData[1]->value = $optionValueApi; + $singleData[3]->value = $optionValueInstaller; + $attributes = $data['create_with_attributes_soapv2']['productData']->additional_attributes; + + // create product for test + $productId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCreate', + $data['create_with_attributes_soapv2'] + ); + + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + + // test new product id returned + $this->assertGreaterThan(0, $productId); + + //test new product attributes + $this->assertEquals($attributes->singleData[0]->value, $product->getData('a_text_api')); + $this->assertEquals($attributes->singleData[1]->value, $product->getData('a_select_api')); + $this->assertEquals($attributes->singleData[2]->value, $product->getData('a_text_ins')); + $this->assertEquals($attributes->singleData[3]->value, $product->getData('a_select_ins')); + + } + + /** + * Test create product with invalid attribute set + * + * @magentoDbIsolation enabled + */ + public function testProductCreateWithInvalidAttributeSet() + { + $productData = require dirname(__FILE__) . '/_files/ProductData.php'; + $productData = $productData['create_full']['soap']; + $productData['set'] = 9999; + + try { + Magento_Test_Helper_Api::call($this, 'catalogProductCreate', $productData); + } catch (Exception $e) { + $this->assertEquals('Product attribute set does not exist.', $e->getMessage(), 'Invalid exception message'); + } + + // find not product (category) attribute set identifier to try other error message + /** @var $entity Mage_Eav_Model_Entity_Type */ + $entity = Mage::getModel('Mage_Eav_Model_Entity_Type'); + $entityTypeId = $entity->loadByCode('catalog_category')->getId(); + + /** @var $attrSet Mage_Eav_Model_Entity_Attribute_Set */ + $attrSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set'); + + /** @var $attrSetCollection Mage_Eav_Model_Resource_Entity_Attribute_Set_Collection */ + $attrSetCollection = $attrSet->getCollection(); + $categoryAtrrSets = $attrSetCollection->setEntityTypeFilter($entityTypeId)->toOptionHash(); + $categoryAttrSetId = key($categoryAtrrSets); + + $productData['set'] = $categoryAttrSetId; + + try { + Magento_Test_Helper_Api::call($this, 'catalogProductCreate', $productData); + } catch (Exception $e) { + $this->assertEquals( + 'Product attribute set does not belong to catalog product entity type.', + $e->getMessage(), + 'Invalid exception message' + ); + } + } + + /** + * Test product attributes update in custom store view + * + * @magentoDbIsolation enabled + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/store_on_new_website.php + */ + public function testProductUpdateCustomStore() + { + /** @var Mage_Core_Model_Store $store */ + $store = Mage::registry('store_on_new_website'); + + $data = require dirname(__FILE__) . '/_files/ProductData.php'; + // create product for test + $productId = Magento_Test_Helper_Api::call($this, 'catalogProductCreate', $data['create_full']['soap']); + $this->assertGreaterThan(0, $productId, 'Product was not created'); + + // update product on test store + $data['update_custom_store'] = array('productId' => $productId) + $data['update_custom_store']; + $data['update_custom_store']['store'] = $store->getCode(); + $isOk = Magento_Test_Helper_Api::call($this, 'catalogProductUpdate', $data['update_custom_store']); + $this->assertTrue($isOk, 'Can not update product on test store'); + + // Load product in test store + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->setStoreId($store->getId())->load($productId); + $this->assertNotNull($product->getId()); + $this->assertEquals( + $data['update_custom_store']['productData']->name, + $product->getName(), + 'Product name was not updated' + ); + + // update product attribute in default store + $data['update_default_store'] = array('productId' => $productId) + $data['update_default_store']; + $isOk = Magento_Test_Helper_Api::call($this, 'catalogProductUpdate', $data['update_default_store']); + $this->assertTrue($isOk, 'Can not update product on default store'); + + // Load product in default store + $productDefault = Mage::getModel('Mage_Catalog_Model_Product'); + $productDefault->load($productId); + $this->assertEquals( + $data['update_default_store']['productData']->description, + $productDefault->getDescription(), + 'Description attribute was not updated for default store' + ); + $this->assertEquals( + $data['create_full']['soap']['productData']->name, + $productDefault->getName(), + 'Product name attribute should not have been changed' + ); + + // Load product in test store + $productTestStore = Mage::getModel('Mage_Catalog_Model_Product'); + $productTestStore->setStoreId($store->getId())->load($productId); + $this->assertEquals( + $data['update_default_store']['productData']->description, + $productTestStore->getDescription(), + 'Description attribute was not updated for test store' + ); + $this->assertEquals( + $data['update_custom_store']['productData']->name, + $productTestStore->getName(), + 'Product name attribute should not have been changed for test store' + ); + } + + /** + * Test create product to test default values for media attributes + * + * @magentoDbIsolation enabled + */ + public function testProductCreateForTestMediaAttributesDefaultValue() + { + $productData = require dirname(__FILE__) . '/_files/ProductData.php'; + $productData = $productData['create']; + + // create product for test + $productId = Magento_Test_Helper_Api::call($this, 'catalogProductCreate', $productData); + + // test new product id returned + $this->assertGreaterThan(0, $productId); + + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($productId); + + $found = false; + foreach ($product->getMediaAttributes() as $mediaAttribute) { + $mediaAttrCode = $mediaAttribute->getAttributeCode(); + $this->assertEquals( + $product->getData($mediaAttrCode), + 'no_selection', + 'Attribute "' . $mediaAttrCode . '" has no default value' + ); + $found = true; + } + $this->assertTrue($found, 'Media attrributes not found'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TagCRUDTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TagCRUDTest.php new file mode 100644 index 00000000000..6d7cd6945c3 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TagCRUDTest.php @@ -0,0 +1,103 @@ +<?php +/** + * Product tag API model test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/TagCRUD.php + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Product_Api_TagCRUDTest extends PHPUnit_Framework_TestCase +{ + /** + * Test tag CRUD + */ + public function testTagCRUD() + { + $tagFixture = simplexml_load_file(dirname(__FILE__) . '/_files/_data/xml/TagCRUD.xml'); + $data = Magento_Test_Helper_Api::simpleXmlToArray($tagFixture->tagData); + $expected = Magento_Test_Helper_Api::simpleXmlToArray($tagFixture->expected); + + $data['product_id'] = Mage::registry('productData')->getId(); + $data['customer_id'] = Mage::registry('customerData')->getId(); + + // create test + $createdTags = Magento_Test_Helper_Api::call($this, 'catalogProductTagAdd', array('data' => $data)); + + $this->assertCount(3, $createdTags); + + // Invalid product ID exception test + try { + $data['product_id'] = mt_rand(10000, 99999); + Magento_Test_Helper_Api::call($this, 'catalogProductTagAdd', array('data' => $data)); + $this->fail("Didn't receive exception!"); + } catch (Exception $e) { + $this->assertEquals('Requested product does not exist.', $e->getMessage()); + } + + // Invalid customer ID exception test + try { + $data['product_id'] = Mage::registry('productData')->getId(); + $data['customer_id'] = mt_rand(10000, 99999); + Magento_Test_Helper_Api::call($this, 'catalogProductTagAdd', array('data' => $data)); + $this->fail("Didn't receive exception!"); + } catch (Exception $e) { + $this->assertEquals('Requested customer does not exist.', $e->getMessage()); + } + + // Invalid store ID exception test + try { + $data['product_id'] = Mage::registry('productData')->getId(); + $data['customer_id'] = Mage::registry('customerData')->getId(); + $data['store'] = mt_rand(10000, 99999); + Magento_Test_Helper_Api::call($this, 'catalogProductTagAdd', array('data' => $data)); + $this->fail("Didn't receive exception!"); + } catch (Exception $e) { + $this->assertEquals('Requested store does not exist.', $e->getMessage()); + } + + // items list test + $tagsList = Magento_Test_Helper_Api::call( + $this, + 'catalogProductTagList', + array( + 'productId' => Mage::registry('productData')->getId(), + 'store' => 0 + ) + ); + $this->assertInternalType('array', $tagsList); + $this->assertNotEmpty($tagsList, "Can't find added tag in list"); + $this->assertCount((int)$expected['created_tags_count'], $tagsList, "Can't find added tag in list"); + + // delete test + $tagToDelete = (array)array_shift($tagsList); + $tagDelete = Magento_Test_Helper_Api::call( + $this, + 'catalogProductTagRemove', + array('tagId' => $tagToDelete['tag_id']) + ); + $this->assertTrue((bool)$tagDelete, "Can't delete added tag"); + + // Delete exception test + $this->setExpectedException('SoapFault', 'Requested tag does not exist.'); + Magento_Test_Helper_Api::call($this, 'catalogProductTagRemove', array('tagId' => $tagToDelete['tag_id'])); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TestCaseAbstract.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TestCaseAbstract.php new file mode 100644 index 00000000000..bbee1550e19 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/TestCaseAbstract.php @@ -0,0 +1,182 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** + * Abstract class for products resource tests + */ +abstract class Mage_Catalog_Model_Product_Api_TestCaseAbstract extends PHPUnit_Framework_TestCase +{ + /** + * Default helper for current test suite + * + * @var string + */ + protected $_defaultHelper = 'Helper_Catalog_Product_Simple'; + + /** @var array */ + protected $_helpers = array(); + + /** + * Map common fixtures keys to soap wsdl. + * + * @var array + */ + protected $_attributesArrayMap = array( + 'tier_price' => array( + 'website_id' => 'website', + 'cust_group' => 'customer_group_id', + 'price_qty' => 'qty' + ) + ); + + /** + * Get current test suite helper if class name not specified. + * + * @param string|null $helperClass + * @return mixed + */ + protected function _getHelper($helperClass = null) + { + if (is_null($helperClass)) { + $helperClass = $this->_defaultHelper; + } + + if (!isset($this->_helpers[$helperClass])) { + $this->_helpers[$helperClass] = new $helperClass; + } + + return $this->_helpers[$helperClass]; + } + + /** + * Try to create product using API and check received error messages + * + * @param array $productData + * @param array|string $expectedMessages + */ + protected function _createProductWithErrorMessagesCheck($productData, $expectedMessages) + { + try { + $this->_tryToCreateProductWithApi($productData); + $this->fail('SoapFault exception was expected to be raised.'); + } catch (SoapFault $e) { + $this->_checkErrorMessagesInResponse($e, $expectedMessages); + } + } + + /** + * Create product with API + * + * @param array $productData + * @return int + */ + protected function _createProductWithApi($productData) + { + $productId = (int)$this->_tryToCreateProductWithApi($productData); + $this->assertGreaterThan(0, $productId, 'Response does not contain valid product ID.'); + return $productId; + } + + /** + * Try to create product with API request + * + * @param array $productData + * @return int + */ + protected function _tryToCreateProductWithApi($productData) + { + $formattedData = $this->_prepareProductDataForSoap($productData); + $response = Magento_Test_Helper_Api::call($this, 'catalogProductCreate', $formattedData); + return $response; + } + + /** + * Map array keys in accordance to soap wsdl. + * + * @param array $productData + * @return array + */ + protected function _prepareProductDataForSoap($productData) + { + $formattedData = array( + 'type' => $productData['type_id'], + 'set' => $productData['attribute_set_id'], + 'sku' => $productData['sku'], + 'productData' => array_diff_key( + $productData, + array_flip(array('type_id', 'attribute_set_id', 'sku')) + ) + ); + foreach ($formattedData['productData'] as $attrCode => &$attrValue) { + if (in_array($attrCode, array_keys($this->_attributesArrayMap)) && is_array($attrValue)) { + $map = $this->_attributesArrayMap[$attrCode]; + foreach ($attrValue as &$arrayItem) { + foreach ($map as $arrayKey => $keyMapValue) { + if (in_array($arrayKey, $arrayItem)) { + $arrayItem[$keyMapValue] = $arrayItem[$arrayKey]; + unset($arrayItem[$arrayKey]); + } + } + } + unset($arrayItem); + } + } + if (isset($formattedData['productData']['tier_price'])) { + foreach ($formattedData['productData']['tier_price'] as &$tierPriceItem) { + $tierPriceItem = (object)$tierPriceItem; + } + } + $formattedData['productData'] = (object)$formattedData['productData']; + return $formattedData; + } + + /** + * Check if expected messages contained in the SoapFault exception + * + * @param SoapFault $exception + * @param array|string $expectedMessages + */ + protected function _checkErrorMessagesInResponse(SoapFault $exception, $expectedMessages) + { + $expectedMessages = is_array($expectedMessages) ? $expectedMessages : array($expectedMessages); + $receivedMessages = explode("\n", $exception->getMessage()); + $this->assertMessagesEqual($expectedMessages, $receivedMessages); + } + + /** + * Assert that two products are equal. + * + * @param Mage_Catalog_Model_Product $expected + * @param Mage_Catalog_Model_Product $actual + */ + public function assertProductEquals(Mage_Catalog_Model_Product $expected, Mage_Catalog_Model_Product $actual) + { + foreach ($expected->getData() as $attribute => $value) { + $this->assertEquals( + $value, + $actual->getData($attribute), + sprintf('Attribute "%s" value does not equal to expected "%s".', $attribute, $value) + ); + } + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet.php new file mode 100644 index 00000000000..b3c09c8ba1a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet.php @@ -0,0 +1,40 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var Mage_Catalog_Model_Product_Attribute_Set_Api $attrSetApi */ +$attrSetApi = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Set_Api'); +Mage::register( + 'testAttributeSetId', + $attrSetApi->create('Test Attribute Set Fixture ' . mt_rand(1000, 9999), 4) +); + +$attributeSetFixture = simplexml_load_file(__DIR__ . '/_data/xml/AttributeSet.xml'); +$data = Magento_Test_Helper_Api::simpleXmlToArray($attributeSetFixture->attributeEntityToCreate); +$data['attribute_code'] = $data['attribute_code'] . '_' . mt_rand(1000, 9999); + +$testAttributeSetAttrIdsArray = array(); + +$attrApi = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Api'); +$testAttributeSetAttrIdsArray[0] = $attrApi->create($data); +Mage::register('testAttributeSetAttrIdsArray', $testAttributeSetAttrIdsArray); diff --git a/index.php.sample b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet_rollback.php similarity index 64% rename from index.php.sample rename to dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet_rollback.php index 4070e1621e4..b834c5119e3 100644 --- a/index.php.sample +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/AttributeSet_rollback.php @@ -18,13 +18,9 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Mage - * @package Mage - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -require_once __DIR__ . '/app/bootstrap.php'; - -$appOptions = new Mage_Core_Model_App_Options($_SERVER); -Mage::run($appOptions->getRunCode(), $appOptions->getRunType(), $appOptions->getRunOptions()); +Mage::unregister('testAttributeSetId'); +Mage::unregister('testAttributeSetAttrIdsArray'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption.php new file mode 100644 index 00000000000..5bf7d8d24ed --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption.php @@ -0,0 +1,34 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +$fixture = simplexml_load_file(__DIR__ . '/_data/xml/CustomOption.xml'); + +//Create new simple product +$productData = Magento_Test_Helper_Api::simpleXmlToArray($fixture->fixtureProduct); +$productData['sku'] = $productData['sku'] . mt_rand(1000, 9999); +$productData['name'] = $productData['name'] . ' ' . mt_rand(1000, 9999); + +$product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->setData($productData)->setStoreId(1)->save(); +Mage::register('productData', $product); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue.php new file mode 100644 index 00000000000..d703eba4c3a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue.php @@ -0,0 +1,44 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +$fixture = simplexml_load_file(__DIR__ . '/_data/xml/CustomOptionValue.xml'); + +//Create new simple product +$productData = Magento_Test_Helper_Api::simpleXmlToArray($fixture->fixtureProduct); +$productData['sku'] = $productData['sku'] . mt_rand(1000, 9999); +$productData['name'] = $productData['name'] . ' ' . mt_rand(1000, 9999); + +$product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->setData($productData)->save(); +Mage::register('productData', $product); + +$customOptionApi = Mage::getModel('Mage_Catalog_Model_Product_Option_Api'); +$data = Magento_Test_Helper_Api::simpleXmlToArray($fixture->fixtureCustomOption); +// unsetOptions() call helps to prevent duplicate options add +// during the sequence of $customOptionApi->add() calls in unit test suite +Mage::getSingleton('Mage_Catalog_Model_Product_Option')->unsetOptions(); +$customOptionApi->add($product->getId(), $data); +$customOptionsList = $customOptionApi->items($product->getId()); + +Mage::register('customOptionId', $customOptionsList[0]['option_id']); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue_rollback.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue_rollback.php new file mode 100644 index 00000000000..62cd96c4b32 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOptionValue_rollback.php @@ -0,0 +1,26 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('productData'); +Mage::unregister('customOptionId'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption_rollback.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption_rollback.php new file mode 100644 index 00000000000..53d97011fbb --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/CustomOption_rollback.php @@ -0,0 +1,25 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('productData'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks.php new file mode 100644 index 00000000000..cf81d0703e9 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks.php @@ -0,0 +1,66 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +$fixture = simplexml_load_file(__DIR__ . '/_data/xml/LinkCRUD.xml'); + +//Create new downloadable product +$productData = Magento_Test_Helper_Api::simpleXmlToArray($fixture->product); +$productData['sku'] = $productData['sku'] . mt_rand(1000, 9999); +$productData['name'] = $productData['name'] . ' ' . mt_rand(1000, 9999); +$linksData = array( + array( + 'title' => 'Test Link 1', + 'price' => '1', + 'is_unlimited' => '1', + 'number_of_downloads' => '0', + 'is_shareable' => '0', + 'sample' => array( + 'type' => 'url', + 'url' => 'http://www.magentocommerce.com/img/logo.gif', + ), + 'type' => 'url', + 'link_url' => 'http://www.magentocommerce.com/img/logo.gif', + ), + array( + 'title' => 'Test Link 2', + 'price' => '2', + 'is_unlimited' => '0', + 'number_of_downloads' => '10', + 'is_shareable' => '1', + 'sample' => + array( + 'type' => 'url', + 'url' => 'http://www.magentocommerce.com/img/logo.gif', + ), + 'type' => 'url', + 'link_url' => 'http://www.magentocommerce.com/img/logo.gif', + ), +); + +$product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->setData($productData) + ->setStoreId(0) + ->setDownloadableData(array('link' => $linksData)) + ->save(); +Mage::register('downloadable', $product); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks_rollback.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks_rollback.php new file mode 100644 index 00000000000..61dbcecbae6 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/DownloadableWithLinks_rollback.php @@ -0,0 +1,25 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('downloadable'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD.php new file mode 100644 index 00000000000..a2aaa61c628 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD.php @@ -0,0 +1,41 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +//Add customer +$fixture = simplexml_load_file(__DIR__ . '/_data/xml/LinkCRUD.xml'); +$customerData = Magento_Test_Helper_Api::simpleXmlToArray($fixture->customer); +$customerData['email'] = mt_rand(1000, 9999) . '.' . $customerData['email']; + +$customer = Mage::getModel('Mage_Customer_Model_Customer'); +$customer->setData($customerData)->save(); +Mage::register('customerData', $customer); + +//Create new downloadable product +$productData = Magento_Test_Helper_Api::simpleXmlToArray($fixture->product); +$productData['sku'] = $productData['sku'] . mt_rand(1000, 9999); +$productData['name'] = $productData['name'] . ' ' . mt_rand(1000, 9999); + +$product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->setData($productData)->save(); +Mage::register('productData', $product); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD_rollback.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD_rollback.php new file mode 100644 index 00000000000..599c7468b4e --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/LinkCRUD_rollback.php @@ -0,0 +1,26 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('customerData'); +Mage::unregister('productData'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductAttributeData.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductAttributeData.php new file mode 100644 index 00000000000..f969fbe5305 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductAttributeData.php @@ -0,0 +1,148 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +return array( + 'create_text_api' => array( + 'attribute_code' => 'a_text_api', + 'scope' => 'store', + 'frontend_input' => 'text', + 'default_value' => '', + 'is_unique' => '0', + 'is_required' => '0', + 'apply_to' => array( + 'simple', + 'grouped', + ), + 'is_configurable' => '0', + 'is_searchable' => '1', + 'is_visible_in_advanced_search' => '0', + 'is_comparable' => '1', + 'is_used_for_promo_rules' => '0', + 'is_visible_on_front' => '1', + 'used_in_product_listing' => '0', + //'label' => 'a_text_api', + 'frontend_label' => array( + array( + 'store_id' => 0, + 'label' => 'a_text_api' + ), + array( + 'store_id' => 1, + 'label' => 'a_text_api' + ), + ), + ), + 'create_select_api' => array( + 'attribute_code' => 'a_select_api', + 'scope' => 'store', + 'frontend_input' => 'select', + 'default_value' => '', + 'is_unique' => '0', + 'is_required' => '0', + 'apply_to' => array( + 'simple', + 'grouped', + ), + 'is_configurable' => '0', + 'is_searchable' => '1', + 'is_visible_in_advanced_search' => '0', + 'is_comparable' => '1', + 'is_used_for_promo_rules' => '0', + 'is_visible_on_front' => '1', + 'used_in_product_listing' => '0', + //'label' => 'a_select_api', + 'frontend_label' => array( + array( + 'store_id' => 0, + 'label' => 'a_select_api' + ), + array( + 'store_id' => 1, + 'label' => 'a_select_api' + ), + ), + ), + 'create_text_installer' => array( + 'code' => 'a_text_ins', + 'attributeData' => array( + 'type' => 'varchar', + 'input' => 'text', + 'label' => 'a_text_ins', + 'required' => 0, + 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE, + 'user_defined' => true, + + ), + ), + 'create_select_installer' => array( + 'code' => 'a_select_ins', + 'attributeData' => array( + 'type' => 'int', + 'input' => 'select', + 'label' => 'a_select_ins', + 'required' => 0, + 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE, + 'user_defined' => true, + 'option' => array( + 'values' => array( + 'option1', + 'option2', + 'option3', + ), + ) + ), + ), + 'create_select_api_options' => array( + array( + 'label' => array( + array( + 'store_id' => 0, + 'value' => 'option1' + ), + array( + 'store_id' => 1, + 'value' => 'option1' + ), + ), + 'order' => 0, + 'is_default' => 1 + ), + array( + 'label' => array( + array( + 'store_id' => 0, + 'value' => 'option2' + ), + array( + 'store_id' => 1, + 'value' => 'option2' + ), + ), + 'order' => 0, + 'is_default' => 1 + ), + ), +); + diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductData.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductData.php new file mode 100644 index 00000000000..57b8ad59b14 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductData.php @@ -0,0 +1,147 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + + +return array( + 'create' => array( + 'type' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'set' => 4, + 'sku' => 'simple' . uniqid(), + 'productData' => (object)array( + 'name' => 'test', + 'description' => 'description', + 'short_description' => 'short description', + 'weight' => 1, + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => 9.99, + 'tax_class_id' => 2, + 'stock_data' => array( + 'manage_stock' => 1, + 'qty' => 10, + 'backorders' => 1, + 'is_in_stock' => '1', + ) + ) + ), + 'update' => array( + 'productData' => (object)array( + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, //required to see product on backend + 'name' => 'Simple Product Updated', //test update method + ) + ), + 'update_custom_store' => array( + 'productData' => (object)array( + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, //required to see product on backend + 'name' => 'Simple Product Updated Custom Store', //test update method + ), + 'store' => 'test_store' + ), + 'update_default_store' => array( + 'productData' => (object)array( + 'description' => 'Updated description' + ) + ), + 'create_with_attributes_soapv2' => array( + 'type' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'set' => 4, + 'sku' => 'simple' . uniqid(), + 'productData' => (object)array( + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, //required to see product on backend + 'name' => 'Product with attributes', + 'description' => 'description', + 'short_description' => 'short description', + 'weight' => 1, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => 9.99, + 'tax_class_id' => 2, + 'additional_attributes' => (object)array( + 'singleData' => array( + (object)array( + 'key' => 'a_text_api', + 'value' => 'qqq123' + ), + (object)array( + 'key' => 'a_select_api', + 'value' => '__PLACEHOLDER__' + ), + (object)array( + 'key' => 'a_text_ins', + 'value' => 'qqq123' + ), + (object)array( + 'key' => 'a_select_ins', + 'value' => '__PLACEHOLDER__' + ), + ), + 'multi_data' => array() + ) + ) + ), + 'create_full_fledged' => array( + 'sku' => 'simple' . uniqid(), + 'attribute_set_id' => 4, + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'name' => 'Simple Product', + 'website_ids' => array(Mage::app()->getStore()->getWebsiteId()), + 'description' => '...', + 'short_description' => '...', + 'price' => 0.99, + 'tax_class_id' => 2, + 'weight' => 1, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'special_from_date' => false, // to avoid set this attr to '' which leads to unpredictable bugs + 'stock_data' => array( + 'manage_stock' => 1, + 'qty' => 10, + 'backorders' => 1, + 'is_in_stock' => '1', + ) + ), + 'create_full' => array( + 'soap' => array( + 'type' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'set' => 4, + 'sku' => 'simple' . uniqid(), + 'productData' => (object)array( + 'name' => 'Simple Product', + 'website_ids' => array(Mage::app()->getStore()->getWebsiteId()), + 'description' => '...', + 'short_description' => '...', + 'price' => 0.99, + 'tax_class_id' => 2, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'weight' => 1, + 'stock_data' => array( + 'manage_stock' => 1, + 'qty' => 10, + 'backorders' => 1, + 'is_in_stock' => '1', + ) + ) + ) + ) +); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud.php new file mode 100644 index 00000000000..471627dbe2a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud.php @@ -0,0 +1,71 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +$data = require dirname(__FILE__) . '/ProductAttributeData.php'; +// add product attributes via installer +$installer = new Mage_Catalog_Model_Resource_Setup('core_setup'); +$installer->addAttribute( + 'catalog_product', + $data['create_text_installer']['code'], + $data['create_text_installer']['attributeData'] +); +$installer->addAttribute( + 'catalog_product', + $data['create_select_installer']['code'], + $data['create_select_installer']['attributeData'] +); + +//add attributes to default attribute set via installer +$installer->addAttributeToSet('catalog_product', 4, 'Default', $data['create_text_installer']['code']); +$installer->addAttributeToSet('catalog_product', 4, 'Default', $data['create_select_installer']['code']); + +$attribute = Mage::getModel('Mage_Eav_Model_Entity_Attribute'); +$attribute->loadByCode('catalog_product', $data['create_select_installer']['code']); +$collection = Mage::getResourceModel('Mage_Eav_Model_Resource_Entity_Attribute_Option_Collection') + ->setAttributeFilter($attribute->getId()) + ->load(); +$options = $collection->toOptionArray(); +$optionValueInstaller = $options[1]['value']; + +//add product attributes via api model +$model = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Api'); +$response1 = $model->create($data['create_text_api']); +$response2 = $model->create($data['create_select_api']); + +//add options +$model = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Api'); +$model->addOption($response2, $data['create_select_api_options'][0]); +$model->addOption($response2, $data['create_select_api_options'][1]); +$options = $model->options($response2); +$optionValueApi = $options[1]['value']; + +//add attributes to default attribute set via api model +$model = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Set_Api'); +$model->attributeAdd($response1, 4); +$model->attributeAdd($response2, 4); + +$attributes = array($response1, $response2); +Mage::register('attributes', $attributes); +Mage::register('optionValueApi', $optionValueApi); +Mage::register('optionValueInstaller', $optionValueInstaller); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud_rollback.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud_rollback.php new file mode 100644 index 00000000000..1752cdc13f7 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/ProductWithOptionCrud_rollback.php @@ -0,0 +1,27 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('attributes'); +Mage::unregister('optionValueApi'); +Mage::unregister('optionValueInstaller'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD.php new file mode 100644 index 00000000000..591a77187d5 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD.php @@ -0,0 +1,41 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +//Add customer +$tagFixture = simplexml_load_file(__DIR__ . '/_data/xml/TagCRUD.xml'); +$customerData = Magento_Test_Helper_Api::simpleXmlToArray($tagFixture->customer); +$customerData['email'] = mt_rand(1000, 9999) . '.' . $customerData['email']; + +$customer = Mage::getModel('Mage_Customer_Model_Customer'); +$customer->setData($customerData)->save(); +Mage::register('customerData', $customer); + +//Create new simple product +$productData = Magento_Test_Helper_Api::simpleXmlToArray($tagFixture->product); +$productData['sku'] = $productData['sku'] . mt_rand(1000, 9999); +$productData['name'] = $productData['name'] . ' ' . mt_rand(1000, 9999); + +$product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->setData($productData)->save(); +Mage::register('productData', $product); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD_rollback.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD_rollback.php new file mode 100644 index 00000000000..599c7468b4e --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/TagCRUD_rollback.php @@ -0,0 +1,26 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('customerData'); +Mage::unregister('productData'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/book.pdf b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/book.pdf new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/image.jpg b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d0e160eef48d9c7463e232c2ba44bd4f9663b5a1 GIT binary patch literal 157486 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 H-j@C!JvO;X literal 0 HcmV?d00001 diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.bmp.jpg b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.bmp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0c7e587766e481fedade831d2b35bb64aeb401a9 GIT binary patch literal 6966 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 literal 0 HcmV?d00001 diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.jpg.jpg b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..880a5fc50b998e6450c7dc168fa65ddc4f992877 GIT binary patch literal 1621 zcmex=<Nrg3ldct+X$%aWo>~kX3=9nH3_^^|42(b)2um@tg6Sk6TN=vF0<txrYM6j* zLq;YBQ6OCe#70222#{_E;>>myu-@4~c9MTliU*JenF*r<GV)9E-7<4Zic%GVOG;BR z^A#c(j0_A7tqhH<42=~GO|4AKfeZ#_28Idj3@kvc21bSkObZ~+GXV0Lk=XxlGdMFa zGckb>5U>CdD+enp3kxe3J3AW(4;K#)Hy1ZIFQ1SAFP|VEH@AS8fS|C5sHi9pzqo{$ zh=h=cs0hdqMrNQM7FJGHR!$LKZe9_R!T$pcf*cG63<k`MN(@YbjLd?J|Bo=p1AWiR z2nIlxg8?HG(2Z>D9GqO-Km}U`7?>EDnVDFaL9Pa>t_8|7un4jWDH=Mm2?r*!D;0_u zHBMZ}q3pErplHy=4=Tn<MNOPsV&W2#QmSg|8k$-rre@|AmR8O#u5Rugo?gKrp<&?> zkx|JhscGpMnOVgprDf$6l~v6xt!?ccon4bAPnkMx`iz;g7A;<~blLJ1D_3pWyk+aQ z?K^hvI&}ER(PPI?oIG{u@|COCuHU$M>*1rvPo6$|{^I4UkDoq&`TFhqkDtFl{$gZc zhIk7|V)d6G&|gd}EX*wIAb&A3l>;%eAPcLaA)An6AbVn=u#!<Dhlta}g&PlYDjNrV z5KSt&$R(y?@=*07$ZKGq5$CZcvU~>j7{Xt-7<iZ&fsw~7$Y9U#Q!?kC?`^@^S<`bD zTLfO2@Ay8D!<lCt$5+uW^>2zFW$QClygwTC_KB~>rVm$-baG9Q3jWreARv4|=crqC z+T`Q<#UH&xwqL1n{_xJ8J1T2CCvV@@<u~@OKJh7KVVa)HVTSoL#kC}Q1VsLA*SfP+ zChB6Ty<)3fg{JyyyF#-s_myvL{}a0~=7;hT;Y_JbmBEVEYR7~eU)kDCjbiELmQ?!e z=p@eDBV=Ls<IB3Knc7DV`300sYh~-Y{@a$pbKl)(lg{s{tczn~h)FLiPkAnJT$FLs z<Wrw(wtf1%z0TtNvf6AfYkwnGpH=S^@{${DPcF&0qdtAdn{#g$e4HOuv*=s<f*RwG zvi&VJ$(eR*mTrlDao^_(L(=k-GjdNTFXR*4d^<1ut$%y`X1N|yUG2!7A5FjQUm9U_ zetG6+-j&jNTw>N;bC)nNY4I6;FIxT}x7^Qsmg^O-ok=Y#zA8`rv-*~On*MDs{dTF4 zI{A;Kd%ymj6X6}b+B8yyd6Us*{sYZlWnZ_;`YkG7^8L<z{W)6B_v5*3&A(mvp_yO% z(APPx$+Rz<<JR*!!$Un2fAm~GR3~?JmUPRuncJP7XHEX2zWrg`?cW}C*X>k)T&~ya zPRv(peAw~i)~>40winr(t@-xtW<O>9PC@E{{vSn|70J6dO!nUI*r}9pCdlRQ)hUlz z<c_5E$XZS8o%ig<sV$dcPP<>3cibn}>63O!#iC5<jLN5i3w~`*VEnr3*!^2ulD8#F zwJXkHoMb(VcmLL^Kg-YmcFC2lPmU4W`Y`<B*44F6EcyxRktz)Jt9~|Gep~Nv_NDFK z_PMI2E1zFD>eapL=DXY)$&bG6hxNOD@prG=GCS7)jZwpE8^xOeA7YI!USBnDPpRbk zrS-Y*TXxm$T%I{!tj1ua+58p9CH7~ypSs=f>DfQ8`UiGjKb7D7cp?0z{Koe^YwHv$ z_>ahQ**G1lP}yF#SxByC+rugKyZqd*RE78VFZ=Mh&usq9OL2w&85(!KPS9TCquRLQ zpMLu(@BIDAkMuYH4))!@we+9qhtlg!HIb`cgm<|f?LF+|DRGDKXY@x2``*ObIaT4C R)~d{URdFs)cUk@an*i-xbQJ&q literal 0 HcmV?d00001 diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.php.jpg b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.php.jpg new file mode 100644 index 00000000000..da4a98d54c1 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.php.jpg @@ -0,0 +1,41 @@ +<?php +try { + $soap = new SoapClient('http://apia.com/api/soap/?wsdl=1', array('trace' => true)); + + $sessionId = $soap->login('admin', '123123q'); + + /*$soap->call( + $sessionId, + 'product_attribute.create', + array( + array( + 'attribute_code' => 'mytest1', + 'scope' => 'global', + 'frontend_input' => 'select', + 'is_used_for_promo_rules' => true, + 'frontend_label' => array( + array('store_id' => 0, 'label' => 'My Test Attribute 1') + ) + ) + ) + );*/ + $soap->call( + $sessionId, + 'product_attribute.create', + array( + array( + 'attribute_code' => 'mytest1.entity_id = e.entity_id); DROP TABLE aaa_test;', + 'scope' => 'global', + 'frontend_input' => 'select', + 'is_used_for_promo_rules' => true, + 'frontend_label' => array( + array('store_id' => 0, 'label' => 'My Attribute With SQL Injection') + ) + ) + ) + ); +} catch (Exception $e) { + echo $e; +} +var_dump($soap->__getLastResponseHeaders()); +var_dump($soap->__getLastResponse()); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.png.jpg b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/images/test.png.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d753cf35add75cc57c5dfc2cbff891945e00020 GIT binary patch literal 2801 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 D+Hptq literal 0 HcmV?d00001 diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/song.mp3 b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/song.mp3 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/test.txt b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/test.txt new file mode 100644 index 00000000000..77e2760d439 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/files/test.txt @@ -0,0 +1 @@ +This is a content of test file. diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/product_configurable_all_fields.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/product_configurable_all_fields.php new file mode 100644 index 00000000000..a08752ada3a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/product_configurable_all_fields.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +$taxClasses = Mage::getResourceModel('Mage_Tax_Model_Resource_Class_Collection')->toArray(); +$taxClass = reset($taxClasses['items']); + +return array( + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE, + 'sku' => 'configurable_' . uniqid(), + 'name' => 'Test Configurable ' . uniqid(), + 'description' => 'Test description', + 'short_description' => 'Test short description', + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => 25.50, + 'tax_class_id' => $taxClass['class_id'] +); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_all_fields_data.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_all_fields_data.php new file mode 100644 index 00000000000..c51ef75ab5a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_all_fields_data.php @@ -0,0 +1,82 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var $entityType Mage_Eav_Model_Entity_Type */ +$entityType = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode('catalog_product'); +$taxClasses = Mage::getResourceModel('Mage_Tax_Model_Resource_Class_Collection')->toArray(); +$taxClass = reset($taxClasses['items']); + +return array( + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'attribute_set_id' => $entityType->getDefaultAttributeSetId(), + 'sku' => 'simple' . uniqid(), + 'name' => 'Test', + 'description' => 'Test description', + 'short_description' => 'Test short description', + 'weight' => 125, + 'news_from_date' => '02/16/2012', + 'news_to_date' => '16.02.2012', + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'url_key' => '123!"â„–;%:?*()_+{}[]\|<>,.?/abc', + 'url_key_create_redirect' => 1, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => 25.50, + 'special_price' => 11.2, + 'special_from_date' => '02/16/2012', + 'special_to_date' => '03/17/2012', + 'group_price' => array( + array('website_id' => 0, 'cust_group' => 1, 'price' => 11) + ), + 'tier_price' => array( + array('website_id' => 0, 'cust_group' => 1, 'price_qty' => 5.5, 'price' => 11.054) + ), + 'msrp_enabled' => 1, + 'msrp_display_actual_price_type' => 1, + 'msrp' => 11.015, + 'enable_googlecheckout' => 1, + 'tax_class_id' => $taxClass['class_id'], + 'meta_title' => 'Test title', + 'meta_keyword' => 'Test keyword', + 'meta_description' => str_pad('', 85, 'a4b'), + 'custom_design' => 'default/default/blank', + 'custom_design_from' => date('Y-m-d'), + 'custom_design_to' => date('Y-m-d', time() + 24 * 3600), + 'custom_layout_update' => '<xml><layout>Test Custom Layout Update</layout></xml>', + 'page_layout' => 'one_column', + 'gift_message_available' => 1, + 'gift_wrapping_available' => 1, + 'gift_wrapping_price' => 0.99, + 'stock_data' => array( + 'manage_stock' => 1, + 'qty' => 1, + 'min_qty' => 1.56, + 'min_sale_qty' => 1, + 'max_sale_qty' => 1, + 'is_qty_decimal' => 0, + 'backorders' => 1, + 'notify_stock_qty' => -50.99, + 'enable_qty_increments' => 0, + 'is_in_stock' => 0 + ) +); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_data.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_data.php new file mode 100644 index 00000000000..2497818c49e --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_data.php @@ -0,0 +1,42 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var $entityType Mage_Eav_Model_Entity_Type */ +$entityType = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode('catalog_product'); +$taxClasses = Mage::getResourceModel('Mage_Tax_Model_Resource_Class_Collection')->toArray(); +$taxClass = reset($taxClasses['items']); + +return array( + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'attribute_set_id' => $entityType->getDefaultAttributeSetId(), + 'sku' => 'simple' . uniqid(), + 'weight' => 1, + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'name' => 'Simple Product', + 'description' => 'Simple Description', + 'short_description' => 'Simple Short Description', + 'price' => 99.95, + 'tax_class_id' => $taxClass['class_id'], +); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_inventory_use_config.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_inventory_use_config.php new file mode 100644 index 00000000000..1a350b9be4c --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_inventory_use_config.php @@ -0,0 +1,63 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var $entityType Mage_Eav_Model_Entity_Type */ +$entityType = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode('catalog_product'); +$taxClasses = Mage::getResourceModel('Mage_Tax_Model_Resource_Class_Collection')->toArray(); +$taxClass = reset($taxClasses['items']); + +return array( + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'attribute_set_id' => $entityType->getDefaultAttributeSetId(), + 'sku' => 'simple' . uniqid(), + 'name' => 'Test', + 'description' => 'Test description', + 'short_description' => 'Test short description', + 'weight' => 125, + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => 25.50, + 'tax_class_id' => $taxClass['class_id'], + // Field should not be validated if "Use Config Settings" checkbox is set + // thus invalid value should not raise error + 'stock_data' => array( + 'manage_stock' => 1, + 'use_config_manage_stock' => 0, + 'qty' => 1, + 'min_qty' => -1, + 'use_config_min_qty' => 1, + 'min_sale_qty' => -1, + 'use_config_min_sale_qty' => 1, + 'max_sale_qty' => -1, + 'use_config_max_sale_qty' => 1, + 'is_qty_decimal' => 0, + 'backorders' => -1, + 'use_config_backorders' => 1, + 'notify_stock_qty' => 'text', + 'use_config_notify_stock_qty' => 1, + 'enable_qty_increments' => -100, + 'use_config_enable_qty_inc' => 1, + 'is_in_stock' => 0 + ) +); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_manage_stock_use_config.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_manage_stock_use_config.php new file mode 100644 index 00000000000..8c0f08a63a7 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_manage_stock_use_config.php @@ -0,0 +1,59 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var $entityType Mage_Eav_Model_Entity_Type */ +$entityType = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode('catalog_product'); +$taxClasses = Mage::getResourceModel('Mage_Tax_Model_Resource_Class_Collection')->toArray(); +$taxClass = reset($taxClasses['items']); + +return array( + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'attribute_set_id' => $entityType->getDefaultAttributeSetId(), + 'sku' => 'simple' . uniqid(), + 'name' => 'Test', + 'description' => 'Test description', + 'short_description' => 'Test short description', + 'weight' => 125, + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => 25.50, + 'tax_class_id' => $taxClass['class_id'], + // Field should not be validated if "Use Config Settings" checkbox is set + // thus invalid value should not raise error + 'stock_data' => array( + 'manage_stock' => -1, + 'use_config_manage_stock' => 1, + 'qty' => 1, + 'min_qty' => -1, + 'min_sale_qty' => -1, + 'use_config_min_sale_qty' => -1, + 'max_sale_qty' => -1, + 'use_config_max_sale_qty' => -1, + 'is_qty_decimal' => -1, + 'backorders' => -1, + 'notify_stock_qty' => 'text', + 'enable_qty_increments' => -100, + 'is_in_stock' => -1 + ) +); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_special_chars_data.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_special_chars_data.php new file mode 100644 index 00000000000..1264f891ed6 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/simple_product_special_chars_data.php @@ -0,0 +1,65 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var $entityType Mage_Eav_Model_Entity_Type */ +$entityType = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode('catalog_product'); +$taxClasses = Mage::getResourceModel('Mage_Tax_Model_Resource_Class_Collection')->toArray(); +$taxClass = reset($taxClasses['items']); + +return array( + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'attribute_set_id' => $entityType->getDefaultAttributeSetId(), + 'name' => '!";%:?*()_+{}[]\|<>,.?/', + 'description' => '!";%:?*()_+{}[]\|<>,.?/', + 'short_description' => '!";%:?*()_+{}[]\|<>,.?/', + 'sku' => '!";%:?*()_+{}[]\|<>,.?/' . uniqid(), + 'weight' => 125, + 'news_from_date' => '02/16/2012', + 'news_to_date' => '16.02.2012', + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'url_key' => '123!";%:?*()_+{}[]\|<>,.?/abc', + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => 25.50, + 'special_price' => 11.2, + 'special_from_date' => '02/16/2012', + 'special_to_date' => '03/17/2012', + 'group_price' => array( + array('website_id' => 0, 'cust_group' => 1, 'price' => 11) + ), + 'tier_price' => array( + array('website_id' => 0, 'cust_group' => 1, 'price_qty' => 5.5, 'price' => 11.054) + ), + 'msrp_enabled' => 1, + 'msrp_display_actual_price_type' => 1, + 'msrp' => 11.015, + 'enable_googlecheckout' => 1, + 'tax_class_id' => $taxClass['class_id'], + 'meta_title' => '!";%:?*()_+{}[]\|<>,.?/', + 'meta_keyword' => '!";%:?*()_+{}[]\|<>,.?/', + 'meta_description' => str_pad('', 8, '!";%:?*_+{}[]\|<>,.?'), + 'custom_design' => 'default/default/blank', + 'custom_design_from' => date('Y-m-d'), + 'custom_design_to' => date('Y-m-d', time() + 24 * 3600), + 'page_layout' => 'one_column', +); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/AttributeSet.xml b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/AttributeSet.xml new file mode 100644 index 00000000000..94849ef8abe --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/AttributeSet.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <create> + <attributeSetName>Test Attribute Set</attributeSetName> + <skeletonSetId>4</skeletonSetId> + </create> + <attributeEntityToCreate> + <attribute_code>a_test_attr_textarea</attribute_code> + <scope>store</scope> + <frontend_input>textarea</frontend_input> + <default_value></default_value> + <is_unique>0</is_unique> + <is_required>0</is_required> + <apply_to>simple</apply_to> + <apply_to>grouped</apply_to> + <is_configurable>0</is_configurable> + <is_searchable>1</is_searchable> + <is_visible_in_advanced_search>0</is_visible_in_advanced_search> + <is_comparable>1</is_comparable> + <is_used_for_promo_rules>0</is_used_for_promo_rules> + <is_visible_on_front>1</is_visible_on_front> + <used_in_product_listing>0</used_in_product_listing> + <additional_fields> + <is_html_allowed_on_front>1</is_html_allowed_on_front> + <is_wysiwyg_enabled>1</is_wysiwyg_enabled> + </additional_fields> + <frontend_label> + <store_id>0</store_id> + <label>aaa</label> + </frontend_label> + <frontend_label> + <store_id>1</store_id> + <label>bbb</label> + </frontend_label> + </attributeEntityToCreate> + <groupAdd> + <groupName>Test Group</groupName> + <existsGroupName>General</existsGroupName> + </groupAdd> + <relatedProduct> + <typeId>simple</typeId> + <sku>test_attribute_set_product</sku> + <productData> + <name>Test attribute set product</name> + <websites>1</websites> + <short_description>short description</short_description> + <description>description</description> + <price>222</price> + <weight>1</weight> + <status>1</status> + <visibility>4</visibility> + <tax_class_id>2</tax_class_id> + <stock_data> + <qty>100</qty> + <manage_stock>1</manage_stock> + <backorders>1</backorders> + <is_in_stock>1</is_in_stock> + </stock_data> + </productData> + </relatedProduct> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOption.xml b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOption.xml new file mode 100644 index 00000000000..b4d8961fd3a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOption.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <store>default</store> + <customOptionsToAdd> + <field> + <title>Test custom option Text Field</title> + <type>field</type> + <is_require>1</is_require> + <additional_fields> + <price>10</price> + <price_type>fixed</price_type> + <sku>test_custom_option_field_sku</sku> + <max_characters>9</max_characters> + </additional_fields> + </field> + <date> + <title>Test custom option Date</title> + <type>date</type> + <is_require>0</is_require> + <sort_order>3</sort_order> + <additional_fields> + <price>10</price> + <price_type>percent</price_type> + <sku>test_custom_option_date_sku</sku> + </additional_fields> + </date> + <file> + <title>Test custom option File</title> + <type>file</type> + <additional_fields> + <price>10</price> + <price_type>percent</price_type> + <sku>test_custom_option_file_sku</sku> + <file_extension>jpg</file_extension> + <image_size_x>600</image_size_x> + <image_size_y>300</image_size_y> + </additional_fields> + </file> + <multiple> + <title>Test custom option Multiselect</title> + <type>multiple</type> + <is_require>1</is_require> + <additional_fields> + <title>Test custom option Multiselect Row_1</title> + <price>10</price> + <price_type>fixed</price_type> + <sku>test_custom_option_multiselect_sku_row_1</sku> + </additional_fields> + <additional_fields> + <title>Test custom option Multiselect Row_2</title> + <price>20</price> + <price_type>fixed</price_type> + <sku>test_custom_option_multiselect_sku_row_2</sku> + <sort_order>6</sort_order> + </additional_fields> + </multiple> + <checkbox> + <title>Test custom option Checkbox</title> + <type>checkbox</type> + <additional_fields> + <title>Test custom option Checkbox Row_1</title> + <price_type>fixed</price_type> + </additional_fields> + </checkbox> + <area> + <title>Test custom option Text Area</title> + <type>area</type> + <is_require>1</is_require> + <sort_order>10</sort_order> + <additional_fields> + <price>10</price> + <price_type>fixed</price_type> + <sku>test_custom_option_area_with_store_id_sku</sku> + <max_characters>7</max_characters> + </additional_fields> + </area> + </customOptionsToAdd> + <customOptionsToUpdate> + <field> + <title>Test custom option Text Field Updated</title> + <additional_fields> + <price>100</price> + </additional_fields> + </field> + <date> + <title>Test custom option Date Updated</title> + <sort_order>100</sort_order> + <additional_fields> + <sku>test_custom_option_date_sku_2</sku> + </additional_fields> + </date> + <area> + <title>Test custom option Text Area Updated</title> + <is_require>0</is_require> + <sort_order>20</sort_order> + <additional_fields> + <max_characters>20</max_characters> + </additional_fields> + </area> + </customOptionsToUpdate> + <fixtureProduct> + <sku>sku</sku> + <attribute_set_id>4</attribute_set_id> + <type_id>simple</type_id> + <name>Simple Product with Custom Options</name> + <description>Simple Product</description> + <short_description>Simple Product</short_description> + <weight>1</weight> + <status>1</status> + <visibility>1</visibility> + <price>100.00</price> + <tax_class_id>0</tax_class_id> + <meta_title>Simple Product</meta_title> + <meta_keyword>Simple Product</meta_keyword> + <meta_description>Simple Product</meta_description> + <stock_data> + <qty>100</qty> + <manage_stock>1</manage_stock> + <backorders>1</backorders> + <is_in_stock>1</is_in_stock> + </stock_data> + </fixtureProduct> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionTypes.xml b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionTypes.xml new file mode 100644 index 00000000000..3c8461c576b --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionTypes.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <customOptionTypes> + <types> + <label>Field</label> + <value>field</value> + </types> + <types> + <label>Area</label> + <value>area</value> + </types> + <types> + <label>File</label> + <value>file</value> + </types> + <types> + <label>Drop-down</label> + <value>drop_down</value> + </types> + <types> + <label>Radio Buttons</label> + <value>radio</value> + </types> + <types> + <label>Checkbox</label> + <value>checkbox</value> + </types> + <types> + <label>Multiple Select</label> + <value>multiple</value> + </types> + <types> + <label>Date</label> + <value>date</value> + </types> + <types> + <label>Date & Time</label> + <value>date_time</value> + </types> + <types> + <label>Time</label> + <value>time</value> + </types> + </customOptionTypes> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionValue.xml b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionValue.xml new file mode 100644 index 00000000000..30b854f93b8 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/CustomOptionValue.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <store>default</store> + <customOptionValues> + <value_1> + <title>Test custom option value</title> + <price>50.00</price> + <price_type>fixed</price_type> + <sku>test_custom_option_value_sku</sku> + <sort_order>0</sort_order> + </value_1> + </customOptionValues> + <customOptionValuesToUpdate> + <value_1> + <title>Updated test custom option value</title> + <price>1000.00</price> + <price_type>fixed</price_type> + <sku>test_custom_option_value_sku_2222</sku> + <sort_order>10</sort_order> + </value_1> + </customOptionValuesToUpdate> + <fixtureCustomOption> + <title>Test custom option Multiselect</title> + <type>multiple</type> + <is_require>1</is_require> + <additional_fields> + <title>Test custom option Multiselect Row_1</title> + <price>10</price> + <price_type>fixed</price_type> + <sku>test_custom_option_multiselect_sku_row_1</sku> + </additional_fields> + <additional_fields> + <title>Test custom option Multiselect Row_2</title> + <price>20</price> + <price_type>fixed</price_type> + <sku>test_custom_option_multiselect_sku_row_2</sku> + <sort_order>6</sort_order> + </additional_fields> + </fixtureCustomOption> + <fixtureProduct> + <sku>sku</sku> + <attribute_set_id>4</attribute_set_id> + <type_id>simple</type_id> + <name>Simple Product with Custom Options</name> + <description>Simple Product</description> + <short_description>Simple Product</short_description> + <weight>1</weight> + <status>1</status> + <visibility>1</visibility> + <price>100.00</price> + <tax_class_id>0</tax_class_id> + <meta_title>Simple Product</meta_title> + <meta_keyword>Simple Product</meta_keyword> + <meta_description>Simple Product</meta_description> + <stock_data> + <qty>100</qty> + <manage_stock>1</manage_stock> + <backorders>1</backorders> + <is_in_stock>1</is_in_stock> + </stock_data> + </fixtureProduct> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/LinkCRUD.xml b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/LinkCRUD.xml new file mode 100644 index 00000000000..7ea2bb2b332 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/LinkCRUD.xml @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <product_id>qwe_downloadable_qwe</product_id> + <items> + <small> + <link> + <title>Test file</title> + <price>123</price> + <is_unlimited>1</is_unlimited> + <number_of_downloads>111</number_of_downloads> + <is_shareable>0</is_shareable> + <sample> + <type>file</type> + <file> + <filename>test.txt</filename> + </file> + <url>http://www.magentocommerce.com/img/logo.gif</url> + </sample> + <type>file</type> + <file> + <filename>test.txt</filename> + </file> + <link_url>http://www.magentocommerce.com/img/logo.gif</link_url> + </link> + <sample> + <title>Test sample file</title> + <type>file</type> + <file> + <filename>image.jpg</filename> + </file> + <sample_url>http://www.magentocommerce.com/img/logo.gif</sample_url> + <sort_order>3</sort_order> + </sample> + </small> + <big> + <link> + <title>Test url</title> + <price>123</price> + <is_unlimited>0</is_unlimited> + <number_of_downloads>111</number_of_downloads> + <is_shareable>1</is_shareable> + <sample> + <type>url</type> + <file> + <filename>book.pdf</filename> + </file> + <url>http://www.magentocommerce.com/img/logo.gif</url> + </sample> + <type>url</type> + <file> + <filename>song.mp3</filename> + </file> + <link_url>http://www.magentocommerce.com/img/logo.gif</link_url> + </link> + <sample> + <title>Test sample url</title> + <type>url</type> + <file> + <filename>image.jpg</filename> + </file> + <sample_url>http://www.magentocommerce.com/img/logo.gif</sample_url> + <sort_order>3</sort_order> + </sample> + </big> + </items> + <customer> + <created_at>2010-01-01 01:01:01</created_at> + <store_id>1</store_id> + <website_id>1</website_id> + <confirmation></confirmation> + <created_in>Default Store View</created_in> + <default_billing>1</default_billing> + <default_shipping>1</default_shipping> + <dob></dob> + <email>mr.test@test.com</email> + <gender></gender> + <firstname>Test</firstname> + <lastname>Test</lastname> + <middlename>Test</middlename> + <group_id>1</group_id> + <password_hash>a8b291d2f4aaf60d138d3e7ee0c20b1b48e48395cea59ed0c94de6b139a0cd86:4M</password_hash> + <prefix></prefix> + <reward_update_notification>1</reward_update_notification> + <reward_warning_notification>1</reward_warning_notification> + <suffix></suffix> + <taxvat></taxvat> + </customer> + <product> + <sku>sku_downloadable</sku> + <attribute_set_id>4</attribute_set_id> + <type_id>downloadable</type_id> + <name>Downloadable Product</name> + <description>Downloadable Product</description> + <short_description>Downloadable Product</short_description> + <weight>1</weight> + <status>1</status> + <visibility>1</visibility> + <price>100.00</price> + <tax_class_id>0</tax_class_id> + <meta_title>Downloadable Product</meta_title> + <meta_keyword>Downloadable Product</meta_keyword> + <meta_description>Downloadable Product</meta_description> + <stock_data> + <qty>100</qty> + <manage_stock>1</manage_stock> + <backorders>1</backorders> + <is_in_stock>1</is_in_stock> + </stock_data> + </product> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/TagCRUD.xml b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/TagCRUD.xml new file mode 100644 index 00000000000..fb82f993d4a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/_data/xml/TagCRUD.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <tagData> + <product_id></product_id> + <customer_id></customer_id> + <store>1</store> + <tag>First 'Second tag' Third</tag> + </tagData> + <customer> + <created_at>2010-01-01 01:01:01</created_at> + <store_id>1</store_id> + <website_id>1</website_id> + <confirmation></confirmation> + <created_in>Default Store View</created_in> + <default_billing>1</default_billing> + <default_shipping>1</default_shipping> + <dob></dob> + <email>mr.test@test.com</email> + <gender></gender> + <firstname>Test</firstname> + <lastname>Test</lastname> + <middlename>Test</middlename> + <group_id>1</group_id> + <password_hash>a8b291d2f4aaf60d138d3e7ee0c20b1b48e48395cea59ed0c94de6b139a0cd86:4M</password_hash> + <prefix></prefix> + <reward_update_notification>1</reward_update_notification> + <reward_warning_notification>1</reward_warning_notification> + <suffix></suffix> + <taxvat></taxvat> + </customer> + <product> + <sku>sku</sku> + <attribute_set_id>4</attribute_set_id> + <type_id>simple</type_id> + <name>Simple Product</name> + <description>Simple Product</description> + <short_description>Simple Product</short_description> + <weight>1</weight> + <status>1</status> + <visibility>1</visibility> + <price>100.00</price> + <tax_class_id>0</tax_class_id> + <meta_title>Simple Product</meta_title> + <meta_keyword>Simple Product</meta_keyword> + <meta_description>Simple Product</meta_description> + <stock_data> + <qty>100</qty> + <manage_stock>1</manage_stock> + <backorders>1</backorders> + <is_in_stock>1</is_in_stock> + </stock_data> + </product> + <expected> + <created_tags_count>3</created_tags_count> + </expected> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/attribute_set_with_configurable.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/attribute_set_with_configurable.php new file mode 100644 index 00000000000..af79574338f --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/attribute_set_with_configurable.php @@ -0,0 +1,83 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +if (!Mage::registry('attribute_set_with_configurable')) { + define('ATTRIBUTES_COUNT', 2); + define('ATTRIBUTE_OPTIONS_COUNT', 3); + + /** @var $entityType Mage_Eav_Model_Entity_Type */ + $entityType = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode('catalog_product'); + + /** @var $attributeSet Mage_Eav_Model_Entity_Attribute_Set */ + $attributeSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set'); + $attributeSet->setEntityTypeId($entityType->getEntityTypeId()) + ->setAttributeSetName('Test Attribute Set ' . uniqid()); + + $attributeSet->save(); + /** @var $entityType Mage_Eav_Model_Entity_Type */ + $entityType = Mage::getModel('Mage_Eav_Model_Entity_Type')->loadByCode('catalog_product'); + $attributeSet->initFromSkeleton($entityType->getDefaultAttributeSetId())->save(); + Mage::register('attribute_set_with_configurable', $attributeSet); + + /** @var $attributeFixture Mage_Catalog_Model_Resource_Eav_Attribute */ + $attributeFixture = Mage::getModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + + $attributeFixture->setEntityTypeId(Mage::getModel('Mage_Eav_Model_Entity')->setType('catalog_product')->getTypeId()) + ->setAttributeCode('test_attr_' . uniqid()) + ->setIsUserDefined(true) + ->setIsVisibleOnFront(false) + ->setIsRequired(false) + ->setFrontendLabel(array(0 => 'Test Attr ' . uniqid())) + ->setApplyTo(array()); + + for ($attributeCount = 1; $attributeCount <= ATTRIBUTES_COUNT; $attributeCount++) { + $attribute = clone $attributeFixture; + $attribute->setAttributeCode('test_attr_' . uniqid()) + ->setFrontendLabel(array(0 => 'Test Attr ' . uniqid())) + ->setIsGlobal(true) + ->setIsConfigurable(true) + ->setIsRequired(true) + ->setFrontendInput('select') + ->setBackendType('int') + ->setAttributeSetId($attributeSet->getId()) + ->setAttributeGroupId($attributeSet->getDefaultGroupId()); + + $options = array(); + for ($optionCount = 0; $optionCount < ATTRIBUTE_OPTIONS_COUNT; $optionCount++) { + $options['option_' . $optionCount] = array( + 0 => 'Test Option #' . $optionCount + ); + } + $attribute->setOption( + array( + 'value' => $options + ) + ); + $attribute->save(); + Mage::register('eav_configurable_attribute_' . $attributeCount, $attribute); + unset($attribute); + } +} + + diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website.php new file mode 100644 index 00000000000..00bcf6de816 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website.php @@ -0,0 +1,64 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +if (!Mage::registry('website')) { + $website = Mage::getModel('Mage_Core_Model_Website'); + $website->setData( + array( + 'code' => 'test_' . uniqid(), + 'name' => 'test website', + 'default_group_id' => 1, + ) + ); + $website->save(); + Mage::register('website', $website); +} + +if (!Mage::registry('store_group')) { + $defaultCategoryId = 2; + $storeGroup = Mage::getModel('Mage_Core_Model_Store_Group'); + $storeGroup->setData( + array( + 'website_id' => Mage::registry('website')->getId(), + 'name' => 'Test Store' . uniqid(), + 'code' => 'store_group_' . uniqid(), + 'root_category_id' => $defaultCategoryId + ) + )->save(); + Mage::register('store_group', $storeGroup); +} + +if (!Mage::registry('store_on_new_website')) { + $store = Mage::getModel('Mage_Core_Model_Store'); + $store->setData( + array( + 'group_id' => Mage::registry('store_group')->getId(), + 'name' => 'Test Store View', + 'code' => 'store_' . uniqid(), + 'is_active' => true, + 'website_id' => Mage::registry('website')->getId() + ) + )->save(); + Mage::register('store_on_new_website', $store); + Mage::app()->reinitStores(); +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website_rollback.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website_rollback.php new file mode 100644 index 00000000000..a6b4c2c5801 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Api/_files/store_on_new_website_rollback.php @@ -0,0 +1,27 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('website'); +Mage::unregister('store_group'); +Mage::unregister('store_on_new_website'); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/ApiTest.php new file mode 100644 index 00000000000..04a67f94663 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/ApiTest.php @@ -0,0 +1,116 @@ +<?php +/** + * Product API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Catalog_Model_Product_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @magentoDataFixture Mage/Catalog/_files/product_special_price.php + */ + public function testGetSpecialPrice() + { + /** Retrieve the product data. */ + $productId = 1; + $actualProductData = Magento_Test_Helper_Api::call( + $this, + 'catalogProductGetSpecialPrice', + array('productId' => $productId) + ); + /** Assert returned product data. */ + $this->assertNotEmpty($actualProductData, 'Missing special price response data.'); + + /** @var Mage_Catalog_Model_Product $expectedProduct */ + $expectedProduct = Mage::getModel('Mage_Catalog_Model_Product'); + $expectedProduct->load($productId); + $fieldsToCompare = array( + 'entity_id' => 'product_id', + 'sku', + 'attribute_set_id' => 'set', + 'type_id' => 'type', + 'category_ids' => 'categories', + 'special_price' + ); + /** Assert response product equals to actual product data. */ + Magento_Test_Helper_Api::checkEntityFields( + $this, + $expectedProduct->getData(), + $actualProductData, + $fieldsToCompare + ); + } + + /** + * @magentoDataFixture Mage/Catalog/_files/multiple_products.php + */ + public function testItems() + { + /** Retrieve the list of products. */ + $actualProductsData = Magento_Test_Helper_Api::call( + $this, + 'catalogProductList' + ); + /** Assert that products quantity equals to 3. */ + $this->assertCount(3, $actualProductsData, 'Products quantity is invalid.'); + + /** Loading expected product from fixture. */ + $expectedProduct = Mage::getModel('Mage_Catalog_Model_Product'); + $expectedProduct->load(10); + $fieldsToCompare = array( + 'entity_id' => 'product_id', + 'sku', + 'attribute_set_id' => 'set', + 'type_id' => 'type', + 'category_ids', + ); + /** Assert first product from response equals to actual product data. */ + Magento_Test_Helper_Api::checkEntityFields( + $this, + $expectedProduct->getData(), + reset($actualProductsData), + $fieldsToCompare + ); + } + + /** + * Test retrieving the list of attributes which are not in default create/update list via API. + */ + public function testGetAdditionalAttributes() + { + $attributesList = Magento_Test_Helper_Api::call( + $this, + 'catalogProductListOfAdditionalAttributes', + array('simple', 4) + ); + $this->assertGreaterThan(20, count($attributesList), "Attributes quantity seems to be incorrect."); + $oldIdAttributeData = reset($attributesList); + $oldIdExpectedData = array( + 'attribute_id' => '89', + 'code' => 'old_id', + 'type' => 'text', + 'required' => '0', + 'scope' => 'global' + ); + $this->assertEquals($oldIdExpectedData, $oldIdAttributeData, "Attribute data from the list is incorrect."); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/ApiTest.php new file mode 100644 index 00000000000..996e4cd2f34 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/ApiTest.php @@ -0,0 +1,343 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Catalog + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Test class for Mage_Catalog_Model_Product_Attribute_Api. + */ +class Mage_Catalog_Model_Product_Attribute_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Product_Attribute_Api + */ + protected $_model; + + protected function setUp() + { + $this->_model = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Api'); + } + + protected function tearDown() + { + $this->_model = null; + } + + public function testItems() + { + $items = $this->_model->items(4); /* default product attribute set after installation */ + $this->assertInternalType('array', $items); + $element = current($items); + $this->assertArrayHasKey('attribute_id', $element); + $this->assertArrayHasKey('code', $element); + $this->assertArrayHasKey('type', $element); + $this->assertArrayHasKey('required', $element); + $this->assertArrayHasKey('scope', $element); + foreach ($items as $item) { + if ($item['code'] == 'status') { + return $item['attribute_id']; + } + } + return false; + } + + /** + * @depends testItems + */ + public function testOptions($attributeId) + { + if (!$attributeId) { + $this->fail('Invalid attribute ID.'); + } + $options = $this->_model->options($attributeId); + $this->assertInternalType('array', $options); + $element = current($options); + $this->assertArrayHasKey('value', $element); + $this->assertArrayHasKey('label', $element); + } + + /** + * Test types method + */ + public function testTypes() + { + $expectedTypes = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Source_Inputtype')->toOptionArray(); + $types = Magento_Test_Helper_Api::call($this, 'catalogProductAttributeTypes'); + $this->assertEquals($expectedTypes, $types); + } + + /** + * Test attribute creation. + * + * @magentoDbIsolation enabled + */ + public function testCreate() + { + $attributeCode = "test_attribute"; + $dataToCreate = array( + "attribute_code" => $attributeCode, + "frontend_input" => "text", + "scope" => "store", + "default_value" => "1", + "is_unique" => 0, + "is_required" => 0, + "apply_to" => array("simple"), + "is_configurable" => 0, + "is_searchable" => 0, + "is_visible_in_advanced_search" => 0, + "is_comparable" => 0, + "is_used_for_promo_rules" => 0, + "is_visible_on_front" => 0, + "used_in_product_listing" => 0, + "frontend_label" => array( + array( + "store_id" => "0", + "label" => "some label", + ) + ) + ); + $attributeId = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeCreate', + array( + 'data' => (object)$dataToCreate + ) + ); + $this->assertGreaterThan(0, $attributeId, 'Attribute create was not successful.'); + + $this->_verifyAttribute($attributeCode, $dataToCreate); + } + + /** + * Test attribute update. + * + * @magentoDataFixture Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php + */ + public function testUpdate() + { + $attributeCode = 'select_attribute'; + $dataToUpdate = array( + "scope" => "global", + "default_value" => "2", + "is_unique" => 1, + "is_required" => 1, + "apply_to" => array("simple", "configurable"), + "is_configurable" => 1, + "is_searchable" => 1, + "is_visible_in_advanced_search" => 1, + "is_comparable" => 1, + "is_visible_on_front" => 1, + "used_in_product_listing" => 1, + "frontend_label" => array( + array( + "store_id" => "0", + "label" => "Label Updated" + ) + ) + ); + + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeUpdate', + array( + 'attribute' => $attributeCode, + 'data' => (object)$dataToUpdate, + ) + ); + $this->assertTrue($result, 'Attribute update was not successful.'); + + $this->_verifyAttribute($attributeCode, $dataToUpdate); + } + + /** + * Test attribute info. + * + * @magentoDataFixture Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php + */ + public function testInfo() + { + $attributeCode = 'select_attribute'; + $attributeInfo = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeInfo', + array( + 'attribute' => $attributeCode, + ) + ); + $this->assertNotEmpty($attributeInfo, 'Attribute info was not retrieved.'); + + $fieldsToCompare = array( + 'attribute_id', + 'attribute_code', + 'frontend_input', + 'is_unique', + 'is_required', + 'is_configurable', + 'is_searchable', + 'is_visible_in_advanced_search', + 'is_comparable', + 'is_used_for_promo_rules', + 'is_visible_on_front', + 'used_in_product_listing', + ); + $this->_verifyAttribute($attributeCode, $attributeInfo, $fieldsToCompare); + } + + /** + * Verify given attribute data. + * + * @param string $attributeCode + * @param array $actualData + * @param array $fieldsToCompare + */ + protected function _verifyAttribute($attributeCode, array $actualData, array $fieldsToCompare = array()) + { + /** @var Mage_Catalog_Model_Resource_Eav_Attribute $expectedAttribute */ + $expectedAttribute = Mage::getResourceModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + $expectedAttribute->loadByCode('catalog_product', $attributeCode); + $expectedIsGlobal = $actualData['scope'] == 'global' ? 1 : 0; + $this->assertEquals($expectedIsGlobal, $expectedAttribute->getIsGlobal(), 'Attribute scope is incorrect.'); + $this->assertEquals( + $expectedAttribute->getApplyTo(), + $actualData['apply_to'], + 'Attribute "Apply To" is incorrect.' + ); + + $frontendLabels = $actualData['frontend_label']; + $frontendLabel = reset($frontendLabels); + $this->assertEquals( + $expectedAttribute->getFrontendLabel(), + $frontendLabel['label'], + 'Attribute fronted label is incorrect.' + ); + unset($actualData['scope']); + unset($actualData['apply_to']); + unset($actualData['frontend_label']); + if (empty($fieldsToCompare)) { + $fieldsToCompare = array_keys($actualData); + } + + Magento_Test_Helper_Api::checkEntityFields( + $this, + $expectedAttribute->getData(), + $actualData, + $fieldsToCompare + ); + } + + /** + * Test attribute removal. + * + * @magentoDataFixture Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php + */ + public function testRemove() + { + $attributeCode = 'select_attribute'; + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeRemove', + array( + 'attribute' => $attributeCode, + ) + ); + $this->assertTrue($result, 'Attribute was not removed.'); + + // Verify that attribute was deleted + /** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = Mage::getResourceModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + $attribute->loadByCode('catalog_product', $attributeCode); + $this->assertNull($attribute->getId(), 'Attribute was not deleted from storage.'); + } + + /** + * Test adding an option to an attribute. + * + * @magentoDataFixture Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php + */ + public function testAddOption() + { + $attributeCode = 'select_attribute'; + $optionLabel = "Option Label"; + + $data = (object)array( + "label" => array( + (object)array( + "store_id" => array("0"), + "value" => $optionLabel + ) + ), + "order" => "10", + "is_default" => "1" + ); + + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeAddOption', + array( + 'attribute' => $attributeCode, + 'data' => $data, + ) + ); + $this->assertTrue($result, 'Attribute option was not added.'); + /** @var Mage_Catalog_Model_Resource_Eav_Attribute $expectedAttribute */ + $expectedAttribute = Mage::getModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + $expectedAttribute->loadByCode('catalog_product', $attributeCode); + $options = $expectedAttribute->getSource()->getAllOptions(); + $this->assertCount(3, $options, 'Exactly 3 options should be in attribute.'); + $option = end($options); + $this->assertEquals($optionLabel, $option['label'], 'Incorrect option label saved.'); + } + + /** + * Test removing an option from an attribute. + * + * @magentoDataFixture Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php + */ + public function testRemoveOption() + { + $attributeCode = 'select_attribute'; + /** @var Mage_Catalog_Model_Resource_Eav_Attribute $attribute */ + $attribute = Mage::getModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + $attribute->loadByCode('catalog_product', $attributeCode); + $options = $attribute->getSource()->getAllOptions(); + $this->assertCount(2, $options, 'Incorrect options count in fixture.'); + $optionToDelete = end($options); + $result = Magento_Test_Helper_Api::call( + $this, + 'catalogProductAttributeRemoveOption', + array( + 'attribute' => $attributeCode, + 'optionId' => $optionToDelete['value'], + ) + ); + $this->assertTrue($result, 'Attribute option was not removed.'); + // Verify option was removed from storage. + /** @var Mage_Catalog_Model_Resource_Eav_Attribute $attrAfterRemove */ + $attrAfterRemove = Mage::getModel('Mage_Catalog_Model_Resource_Eav_Attribute'); + $attrAfterRemove->loadByCode('catalog_product', $attributeCode); + $optionsAfterRemove = $attrAfterRemove->getSource()->getAllOptions(); + $this->assertCount(1, $optionsAfterRemove, 'Attribute option was not removed from storage.'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php index 9f405eecb96..e07a5d69221 100644 --- a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php @@ -52,11 +52,12 @@ class Mage_Catalog_Model_Product_Attribute_Backend_MediaTest extends PHPUnit_Fra $fixtureDir = realpath(dirname(__FILE__).'/../../../../_files'); self::$_mediaDir = Mage::getSingleton('Mage_Catalog_Model_Product_Media_Config')->getBaseMediaPath(); + $ioFile = new Varien_Io_File(); if (!is_dir(self::$_mediaTmpDir)) { - mkdir(self::$_mediaTmpDir, 0777, true); + $ioFile->mkdir(self::$_mediaTmpDir, 0777, true); } if (!is_dir(self::$_mediaDir)) { - mkdir(self::$_mediaDir, 0777, true); + $ioFile->mkdir(self::$_mediaDir, 0777, true); } copy($fixtureDir . "/magento_image.jpg", self::$_mediaTmpDir . "/magento_image.jpg"); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Media/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Media/ApiTest.php new file mode 100644 index 00000000000..10dc22865f0 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Media/ApiTest.php @@ -0,0 +1,176 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Catalog + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Test class for Mage_Catalog_Model_Product_Attribute_Media_Api. + * + * @magentoDataFixture Mage/Catalog/_files/product_simple.php + * @magentoDataFixture productMediaFixture + */ +class Mage_Catalog_Model_Product_Attribute_Media_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Product_Attribute_Media_Api + */ + protected $_model; + + /** + * @var string + */ + protected static $_filesDir; + + /** + * @var string + */ + protected static $_mediaTmpDir; + + protected function setUp() + { + $this->_model = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Media_Api'); + } + + protected function tearDown() + { + $this->_model = null; + } + + public static function setUpBeforeClass() + { + self::$_filesDir = realpath(__DIR__ . '/../../../../_files'); + self::$_mediaTmpDir = Mage::getSingleton('Mage_Catalog_Model_Product_Media_Config')->getBaseTmpMediaPath(); + $ioFile = new Varien_Io_File(); + $ioFile->mkdir(self::$_mediaTmpDir . "/m/a", 0777, true); + copy(self::$_filesDir . '/magento_image.jpg', self::$_mediaTmpDir . '/m/a/magento_image.jpg'); + } + + public static function tearDownAfterClass() + { + Varien_Io_File::rmdirRecursive(self::$_mediaTmpDir . "/m/a"); + /** @var $config Mage_Catalog_Model_Product_Media_Config */ + $config = Mage::getSingleton('Mage_Catalog_Model_Product_Media_Config'); + Varien_Io_File::rmdirRecursive($config->getBaseMediaPath()); + } + + public static function productMediaFixture() + { + /** @var $product Mage_Catalog_Model_Product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load(1); + $product->setTierPrice(array()); + $product->setData('media_gallery', array('images' => array(array('file' => '/m/a/magento_image.jpg',),))); + $product->save(); + } + + /** + * @covers Mage_Catalog_Model_Product_Attribute_Media_Api::items + * @covers Mage_Catalog_Model_Product_Attribute_Media_Api::info + */ + public function testItemsAndInfo() + { + $items = $this->_model->items(1); + $this->assertNotEmpty($items); + $this->assertEquals(1, count($items)); + $item = current($items); + $this->assertArrayHasKey('file', $item); + $this->assertArrayHasKey('label', $item);; + $this->assertArrayHasKey('url', $item); + + $info = $this->_model->info(1, $item['file']); + $this->assertArrayHasKey('file', $info); + $this->assertArrayHasKey('label', $info);; + $this->assertArrayHasKey('url', $info); + return $item['file']; + } + + /** + * @depends testItemsAndInfo + */ + public function testCreate() + { + $data = array( + 'file' => array( + 'mime' => 'image/jpeg', + 'content' => base64_encode(file_get_contents(self::$_filesDir.'/magento_small_image.jpg')) + ) + ); + $this->_model->create(1, $data); + $items = $this->_model->items(1); + $this->assertEquals(2, count($items)); + } + + public function createFaultDataProvider() + { + return array( + array('floor' => 'ceiling'), + array('file' => array('mime' => 'test')), + array('file' => array('mime' => 'image/jpeg', 'content' => 'not valid')) + ); + } + + /** + * @dataProvider createFaultDataProvider + * @expectedException Mage_Api_Exception + */ + public function testCreateFault($data) + { + $this->_model->create(1, $data); + } + + /** + * @depends testItemsAndInfo + */ + public function testUpdate($file) + { + $data = array( + 'file' => array( + 'mime' => 'image/jpeg', + 'content' => base64_encode(file_get_contents(self::$_filesDir.'/magento_small_image.jpg')) + ) + ); + $this->assertTrue($this->_model->update(1, $file, $data)); + } + + /** + * @depends testItemsAndInfo + * @expectedException Mage_Api_Exception + */ + public function testRemove($file) + { + $this->assertTrue($this->_model->remove(1, $file)); + $this->_model->info(1, $file); + } + + public function testTypes() + { + $types = $this->_model->types(4); + $this->assertNotEmpty($types); + $this->assertInternalType('array', $types); + $type = current($types); + $this->assertArrayHasKey('code', $type); + $this->assertArrayHasKey('scope', $type); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2Test.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2Test.php new file mode 100644 index 00000000000..fbcc8b53921 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/Api/V2Test.php @@ -0,0 +1,84 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Catalog + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Test class for Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2. + */ +class Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2Test extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2 + */ + protected $_model; + + protected function setUp() + { + $this->_model = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2'); + } + + protected function tearDown() + { + $this->_model = null; + } + + /** + * @expectedException Mage_Api_Exception + */ + public function testPrepareTierPricesInvalidData() + { + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $this->_model->prepareTierPrices($product, array(1)); + } + + public function testPrepareTierPricesInvalidWebsite() + { + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $data = $this->_model->prepareTierPrices( + $product, + array((object) array('qty' => 3, 'price' => 8, 'website' => 100)) + ); + $this->assertEquals( + array(array('website_id' => 0, 'cust_group' => 32000, 'price_qty' => 3, 'price' => 8)), + $data + ); + } + + public function testPrepareTierPrices() + { + $product = Mage::getModel('Mage_Catalog_Model_Product'); + + $this->assertNull($this->_model->prepareTierPrices($product)); + + $data = $this->_model->prepareTierPrices($product, + array((object) array('qty' => 3, 'price' => 8)) + ); + $this->assertEquals( + array(array('website_id' => 0, 'cust_group' => 32000, 'price_qty' => 3, 'price' => 8)), + $data + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/ApiTest.php new file mode 100644 index 00000000000..3bf9a21046f --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/Tierprice/ApiTest.php @@ -0,0 +1,103 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Catalog + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Test class for Mage_Catalog_Model_Product_Attribute_Tierprice_Api + * + * @magentoDataFixture Mage/Catalog/_files/product_simple.php + */ +class Mage_Catalog_Model_Product_Attribute_Tierprice_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @var Mage_Catalog_Model_Product_Attribute_Tierprice_Api + */ + protected $_model; + + protected function setUp() + { + $this->_model = Mage::getModel('Mage_Catalog_Model_Product_Attribute_Tierprice_Api'); + } + + protected function tearDown() + { + $this->_model = null; + } + + public function testInfo() + { + $info = $this->_model->info(1); + $this->assertInternalType('array', $info); + $this->assertEquals(2, count($info)); + $element = current($info); + $this->assertArrayHasKey('customer_group_id', $element); + $this->assertArrayHasKey('website', $element); + $this->assertArrayHasKey('qty', $element); + $this->assertArrayHasKey('price', $element); + } + + public function testUpdate() + { + Mage::app()->setCurrentStore(Mage::app()->getStore(Mage_Core_Model_App::ADMIN_STORE_ID)); + $this->_model->update(1, array(array('qty' => 3, 'price' => 8))); + $info = $this->_model->info(1); + $this->assertEquals(1, count($info)); + } + + /** + * @expectedException Mage_Api_Exception + */ + public function testPrepareTierPricesInvalidData() + { + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $this->_model->prepareTierPrices($product, array(1)); + } + + public function testPrepareTierPricesInvalidWebsite() + { + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $data = $this->_model->prepareTierPrices($product, array(array('qty' => 3, 'price' => 8, 'website' => 100))); + $this->assertEquals( + array(array('website_id' => 0, 'cust_group' => 32000, 'price_qty' => 3, 'price' => 8)), + $data + ); + } + + public function testPrepareTierPrices() + { + $product = Mage::getModel('Mage_Catalog_Model_Product'); + + $this->assertNull($this->_model->prepareTierPrices($product)); + + $data = $this->_model->prepareTierPrices($product, + array(array('qty' => 3, 'price' => 8)) + ); + $this->assertEquals( + array(array('website_id' => 0, 'cust_group' => 32000, 'price_qty' => 3, 'price' => 8)), + $data + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php new file mode 100644 index 00000000000..e02ee451fb4 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Attribute/_files/select_attribute.php @@ -0,0 +1,55 @@ +<?php +/** + * "dropdown" fixture of product EAV attribute. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var Mage_Eav_Model_Entity_Type $entityType */ +$entityType = Mage::getModel('Mage_Eav_Model_Entity_Type'); +$entityType->loadByCode('catalog_product'); +$defaultSetId = $entityType->getDefaultAttributeSetId(); +/** @var Mage_Eav_Model_Entity_Attribute_Set $defaultSet */ +$defaultSet = Mage::getModel('Mage_Eav_Model_Entity_Attribute_Set'); +$defaultSet->load($defaultSetId); +$defaultGroupId = $defaultSet->getDefaultGroupId(); +$optionData = array( + 'value' => array( + 'option_1' => array(0 => 'Fixture Option'), + ), + 'order' => array( + 'option_1' => 1, + ) +); + +/** @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ +$attribute = Mage::getResourceModel('Mage_Catalog_Model_Resource_Eav_Attribute'); +$attribute->setAttributeCode('select_attribute') + ->setEntityTypeId($entityType->getEntityTypeId()) + ->setAttributeGroupId($defaultGroupId) + ->setAttributeSetId($defaultSetId) + ->setFrontendInput('select') + ->setFrontendLabel('Select Attribute') + ->setBackendType('int') + ->setIsUserDefined(1) + ->setOption($optionData) + ->save(); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Link/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Link/ApiTest.php new file mode 100644 index 00000000000..749d2262ea3 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Link/ApiTest.php @@ -0,0 +1,208 @@ +<?php +/** + * Catalog product link API test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Catalog/_files/multiple_products.php + */ +class Mage_Catalog_Model_Product_Link_ApiTest extends PHPUnit_Framework_TestCase +{ + const LINK_TYPE_UP_SELL = 'up_sell'; + const LINK_TYPE_RELATED = 'related'; + + protected $_mainProductId = 10; + protected $_upSellProductId = 11; + protected $_relatedProductId = 12; + + /** + * Test 'types' method of catalog product link API. + */ + public function testTypes() + { + /** Add up-sell and related products. */ + $types = Magento_Test_Helper_Api::call($this, 'catalogProductLinkTypes'); + $expectedTypes = array('related', 'up_sell', 'cross_sell', 'grouped'); + $this->assertEquals($expectedTypes, $types); + } + + /** + * Test 'attributes' method of catalog product link API. + */ + public function testAttributes() + { + $attributes = Magento_Test_Helper_Api::call( + $this, + 'catalogProductLinkAttributes', + array(self::LINK_TYPE_UP_SELL) + ); + $this->assertEquals( + array(array('code' => 'position', 'type' => 'int')), + $attributes, + "Attributes list is invalid." + ); + } + + /** + * Test 'assign' method of catalog product link API. + */ + public function testAssign() + { + /** Add up-sell and related products. */ + $upSellResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductLinkAssign', + array( + self::LINK_TYPE_UP_SELL, + $this->_mainProductId, + $this->_upSellProductId + ) + ); + $this->assertTrue($upSellResult, "Up-sell link creation was unsuccessful."); + $relatedResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductLinkAssign', + array( + self::LINK_TYPE_RELATED, + $this->_mainProductId, + $this->_relatedProductId + ) + ); + $this->assertTrue($relatedResult, "Related link creation was unsuccessful."); + /** @var Mage_Catalog_Model_Product $product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($this->_mainProductId); + + /** Check created 'related' product link */ + $actualRelated = $product->getRelatedLinkCollection()->getItems(); + $this->assertCount(1, $actualRelated, "One link of 'related' type must exist."); + /** @var Mage_Catalog_Model_Product_Link $relatedProductLink */ + $relatedProductLink = reset($actualRelated); + $this->assertEquals( + $this->_relatedProductId, + $relatedProductLink->getLinkedProductId(), + 'Related product ID is invalid' + ); + + /** Check created 'up-sell' product link */ + $actualUpSell = $product->getUpSellLinkCollection()->getItems(); + $this->assertCount(1, $actualUpSell, "One link of 'up-sell' type must exist."); + /** @var Mage_Catalog_Model_Product_Link $upSellProductLink */ + $upSellProductLink = reset($actualUpSell); + $this->assertEquals( + $this->_upSellProductId, + $upSellProductLink->getLinkedProductId(), + 'Up-sell product ID is invalid' + ); + } + + /** + * Test 'items' method of catalog product API. + * + * @depends testAssign + */ + public function testList() + { + $upSellProducts = Magento_Test_Helper_Api::call( + $this, + 'catalogProductLinkList', + array( + self::LINK_TYPE_UP_SELL, + $this->_mainProductId + ) + ); + $this->assertCount(1, $upSellProducts, "One link of 'up-sell' type must exist."); + $expectedFields = array('product_id', 'type', 'set', 'sku', 'position'); + $productData = reset($upSellProducts); + $missingFields = array_diff($expectedFields, array_keys($productData)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in response: %s.", implode(', ', $missingFields)) + ); + $this->assertEquals($this->_upSellProductId, $productData['product_id'], "Up-sell product ID is invalid."); + } + + /** + * Test 'update' method of catalog product API. + * + * @depends testList + */ + public function testUpdate() + { + $positionForUpdate = 5; + $isUpdated = Magento_Test_Helper_Api::call( + $this, + 'catalogProductLinkUpdate', + array( + self::LINK_TYPE_RELATED, + $this->_mainProductId, + $this->_relatedProductId, + (object)array('position' => $positionForUpdate) + ) + ); + $this->assertTrue($isUpdated, "Related link update was unsuccessful."); + + /** Check created 'related' product link */ + /** @var Mage_Catalog_Model_Product $product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($this->_mainProductId); + $actualRelated = $product->getRelatedLinkCollection()->getItems(); + $this->assertCount(1, $actualRelated, "One link of 'related' type must exist."); + /** @var Mage_Catalog_Model_Product_Link $relatedProductLink */ + $relatedProductLink = reset($actualRelated); + $this->assertEquals( + $positionForUpdate, + $relatedProductLink->getPosition(), + 'Product link position was not updated.' + ); + } + + /** + * Test for 'remove' method of catalog product API + * + * @depends testUpdate + */ + public function testRemove() + { + $isRemoved = Magento_Test_Helper_Api::call( + $this, + 'catalogProductLinkRemove', + array( + self::LINK_TYPE_UP_SELL, + $this->_mainProductId, + $this->_upSellProductId + ) + ); + $this->assertTrue($isRemoved, "Related link remove was unsuccessful."); + + /** @var Mage_Catalog_Model_Product $product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load($this->_mainProductId); + + /** Check that 'related' product link was not removed */ + $actualRelated = $product->getRelatedLinkCollection()->getItems(); + $this->assertCount(1, $actualRelated, "One link of 'related' type must exist."); + + /** Check that 'up-sell' product link was actually removed from DB */ + $actualUpSell = $product->getUpSellLinkCollection()->getItems(); + $this->assertCount(0, $actualUpSell, "No links of 'up-sell' type must exist."); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Option/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Option/ApiTest.php new file mode 100644 index 00000000000..e5c70c11fc6 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Option/ApiTest.php @@ -0,0 +1,407 @@ +<?php +/** + * Product custom options API model test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Catalog/Model/Product/Api/_files/CustomOption.php + * @magentoDbIsolation enabled + */ +class Mage_Catalog_Model_Product_Option_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @var array + */ + protected static $_createdOptionAfter; + + /** @var SimpleXmlElement */ + protected static $_customOptionFixture; + + public static function setUpBeforeClass() + { + self::$_customOptionFixture = self::_loadXmlFixture('CustomOption.xml'); + } + + /** + * Product Custom Option CRUD test + */ + public function testCustomOptionCRUD() + { + $customOptions = Magento_Test_Helper_Api::simpleXmlToArray(self::$_customOptionFixture->customOptionsToAdd); + $store = (string)self::$_customOptionFixture->store; + + $this->_testCreate($store, $customOptions); + $this->_testRead($store, $customOptions); + $optionsToUpdate = Magento_Test_Helper_Api::simpleXmlToArray( + self::$_customOptionFixture->customOptionsToUpdate + ); + $this->_testUpdate($optionsToUpdate); + } + + /** + * Test creating custom options + * + * @param string $store + * @param array $customOptions + */ + protected function _testCreate($store, $customOptions) + { + $fixtureProductId = Mage::registry('productData')->getId(); + $createdOptionBefore = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionList', + array( + 'productId' => $fixtureProductId, + 'store' => $store + ) + ); + $this->assertEmpty($createdOptionBefore); + + foreach ($customOptions as $option) { + if (isset($option['additional_fields']) + and !is_array(reset($option['additional_fields'])) + ) { + $option['additional_fields'] = array($option['additional_fields']); + } + + $addedOptionResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionAdd', + array( + 'productId' => $fixtureProductId, + 'data' => (object)$option, + 'store' => $store + ) + ); + $this->assertTrue((bool)$addedOptionResult); + } + } + + /** + * Test reading custom options + * + * @param string $store + * @param array $customOptions + */ + protected function _testRead($store, $customOptions) + { + $fixtureProductId = Mage::registry('productData')->getId(); + self::$_createdOptionAfter = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionList', + array( + 'productId' => $fixtureProductId, + 'store' => $store + ) + ); + + $this->assertTrue(is_array(self::$_createdOptionAfter)); + $this->assertEquals(count($customOptions), count(self::$_createdOptionAfter)); + + foreach (self::$_createdOptionAfter as $option) { + $this->assertEquals($customOptions[$option->type]['title'], $option->title); + } + } + + /** + * Test updating custom option + * + * @param array $optionsToUpdate + */ + protected function _testUpdate($optionsToUpdate) + { + $updateCounter = 0; + foreach (self::$_createdOptionAfter as $option) { + $option = (array)$option; + $optionInfo = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionInfo', + array( + 'optionId' => $option['option_id'] + ) + ); + + $this->assertTrue(is_array($optionInfo)); + $this->assertGreaterThan(3, count($optionInfo)); + + if (isset($optionsToUpdate[$option['type']])) { + $toUpdateValues = $optionsToUpdate[$option['type']]; + if (isset($toUpdateValues['additional_fields']) + and !is_array(reset($toUpdateValues['additional_fields'])) + ) { + $toUpdateValues['additional_fields'] = array($toUpdateValues['additional_fields']); + } + + $updateOptionResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionUpdate', + array( + 'optionId' => $option['option_id'], + 'data' => $toUpdateValues + ) + ); + $this->assertTrue((bool)$updateOptionResult); + $updateCounter++; + + $this->_testOptionsAfterUpdate($option['option_id'], $toUpdateValues); + } + } + + $this->assertCount($updateCounter, $optionsToUpdate); + } + + /** + * Check that options has been updated correctly + * + * @param int $optionId + * @param array $toUpdateValues + */ + protected function _testOptionsAfterUpdate($optionId, $toUpdateValues) + { + $optionAfterUpdate = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionInfo', + array( + 'optionId' => $optionId + ) + ); + + foreach ($toUpdateValues as $key => $value) { + if (is_string($value)) { + self::assertEquals($value, $optionAfterUpdate[$key]); + } + } + + if (isset($toUpdateValues['additional_fields'])) { + $updateFields = reset($toUpdateValues['additional_fields']); + $actualFields = reset($optionAfterUpdate['additional_fields']); + foreach ($updateFields as $key => $value) { + if (is_string($value)) { + self::assertEquals($value, $actualFields[$key]); + } + } + } + } + + /** + * Product Custom Option ::types() method test + */ + public function testCustomOptionTypes() + { + $attributeSetFixture = $this->_loadXmlFixture('CustomOptionTypes.xml'); + $customOptionsTypes = Magento_Test_Helper_Api::simpleXmlToArray($attributeSetFixture); + + $optionTypes = Magento_Test_Helper_Api::call($this, 'catalogProductCustomOptionTypes', array()); + $this->assertEquals($customOptionsTypes['customOptionTypes']['types'], $optionTypes); + } + + /** + * Update custom option + * + * @param int $optionId + * @param array $option + * @param int $store + * + * @return boolean + */ + protected function _updateOption($optionId, $option, $store = null) + { + if (isset($option['additional_fields']) + and !is_array(reset($option['additional_fields'])) + ) { + $option['additional_fields'] = array($option['additional_fields']); + } + + return Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionUpdate', + array( + 'optionId' => $optionId, + 'data' => $option, + 'store' => $store + ) + ); + } + + /** + * Test option add exception: product_not_exists + */ + public function testCustomOptionAddExceptionProductNotExists() + { + $customOptions = Magento_Test_Helper_Api::simpleXmlToArray(self::$_customOptionFixture->customOptionsToAdd); + + $option = reset($customOptions); + if (isset($option['additional_fields']) + and !is_array(reset($option['additional_fields'])) + ) { + $option['additional_fields'] = array($option['additional_fields']); + } + $this->setExpectedException('SoapFault'); + Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionAdd', + array( + 'productId' => 'invalid_id', + 'data' => $option + ) + ); + } + + /** + * Test option add without additional fields exception: invalid_data + */ + public function testCustomOptionAddExceptionAdditionalFieldsNotSet() + { + $fixtureProductId = Mage::registry('productData')->getId(); + $customOptions = Magento_Test_Helper_Api::simpleXmlToArray(self::$_customOptionFixture->customOptionsToAdd); + + $option = $customOptions['field']; + $option['additional_fields'] = array(); + + $this->setExpectedException('SoapFault', 'Provided data is invalid.'); + Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionAdd', + array('productId' => $fixtureProductId, 'data' => $option) + ); + } + + /** + * Test option date_time add with store id exception: store_not_exists + */ + public function testCustomOptionDateTimeAddExceptionStoreNotExist() + { + $fixtureProductId = Mage::registry('productData')->getId(); + $customOptions = Magento_Test_Helper_Api::simpleXmlToArray(self::$_customOptionFixture->customOptionsToAdd); + + $option = reset($customOptions); + if (isset($option['additional_fields']) + and !is_array(reset($option['additional_fields'])) + ) { + $option['additional_fields'] = array($option['additional_fields']); + } + $this->setExpectedException('SoapFault'); + Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionAdd', + array( + 'productId' => $fixtureProductId, + 'data' => $option, + 'store' => 'some_store_name' + ) + ); + } + + /** + * Test product custom options list exception: product_not_exists + */ + public function testCustomOptionListExceptionProductNotExists() + { + $store = (string)self::$_customOptionFixture->store; + + $this->setExpectedException('SoapFault'); + Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionList', + array( + 'productId' => 'unknown_id', + 'store' => $store + ) + ); + } + + /** + * Test product custom options list exception: store_not_exists + */ + public function testCustomOptionListExceptionStoreNotExists() + { + $fixtureProductId = Mage::registry('productData')->getId(); + + $this->setExpectedException('SoapFault'); + Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionList', + array( + 'productId' => $fixtureProductId, + 'store' => 'unknown_store_name' + ) + ); + } + + /** + * Test option add with invalid type + * + * @expectedException SoapFault + */ + public function testCustomOptionUpdateExceptionInvalidType() + { + $optionsToUpdate = Magento_Test_Helper_Api::simpleXmlToArray( + self::$_customOptionFixture->customOptionsToUpdate + ); + $option = (array)reset(self::$_createdOptionAfter); + + $toUpdateValues = $optionsToUpdate[$option['type']]; + $toUpdateValues['type'] = 'unknown_type'; + + $this->_updateOption($option['option_id'], $toUpdateValues); + } + + /** + * Test option remove and exception + * + * @expectedException SoapFault + * @depends testCustomOptionUpdateExceptionInvalidType + */ + public function testCustomOptionRemove() + { + // Remove + foreach (self::$_createdOptionAfter as $option) { + $removeOptionResult = Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionRemove', + // @codingStandardsIgnoreStart + array( + 'optionId' => $option->option_id + ) + // @codingStandardsIgnoreEnd + ); + $this->assertTrue((bool)$removeOptionResult); + } + + // Delete exception test + Magento_Test_Helper_Api::call( + $this, + 'catalogProductCustomOptionRemove', + array('optionId' => mt_rand(99999, 999999)) + ); + } + + /** + * Load XML from fixture + * + * @param string $fileName + * @return SimpleXMLElement + */ + protected static function _loadXmlFixture($fileName) + { + return simplexml_load_file(dirname(__FILE__) . '/../Api/_files/_data/xml/' . $fileName); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/ApiTest.php b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/ApiTest.php new file mode 100644 index 00000000000..90663482448 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Catalog/Model/Product/Type/ApiTest.php @@ -0,0 +1,54 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Catalog + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Catalog_Model_Product_Type_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * @param string $class + * @dataProvider itemsDataProvider + */ + public function testItems($class) + { + /** @var $model Mage_Catalog_Model_Product_Type_Api */ + $model = Mage::getModel($class); + $result = $model->items(); + $this->assertInternalType('array', $result); + $this->assertNotEmpty($result); + foreach ($result as $item) { + $this->assertArrayHasKey('type', $item); + $this->assertArrayHasKey('label', $item); + } + } + + public function itemsDataProvider() + { + return array( + array('Mage_Catalog_Model_Product_Type_Api'), + array('Mage_Catalog_Model_Product_Type_Api_V2'), // a dummy class, doesn't require separate test suite + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Catalog/_files/categories.php b/dev/tests/integration/testsuite/Mage/Catalog/_files/categories.php index 81b9e237d30..1f3f62ecdfc 100644 --- a/dev/tests/integration/testsuite/Mage/Catalog/_files/categories.php +++ b/dev/tests/integration/testsuite/Mage/Catalog/_files/categories.php @@ -116,6 +116,9 @@ $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) ->setSku('simple') ->setPrice(10) ->setWeight(18) + ->setStockData(array( + 'use_config_manage_stock' => 0, + )) ->setCategoryIds(array(2,3,4)) ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH) ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED) @@ -131,6 +134,9 @@ $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) ->setSku('12345') // SKU intentionally contains digits only ->setPrice(45.67) ->setWeight(56) + ->setStockData(array( + 'use_config_manage_stock' => 0, + )) ->setCategoryIds(array(5)) ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH) ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED) diff --git a/dev/tests/integration/testsuite/Mage/Catalog/_files/product_simple.php b/dev/tests/integration/testsuite/Mage/Catalog/_files/product_simple.php index 6d468eb3466..cfcb75336eb 100644 --- a/dev/tests/integration/testsuite/Mage/Catalog/_files/product_simple.php +++ b/dev/tests/integration/testsuite/Mage/Catalog/_files/product_simple.php @@ -27,6 +27,7 @@ /** @var $product Mage_Catalog_Model_Product */ $product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->isObjectNew(true); $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) ->setId(1) ->setAttributeSetId(4) @@ -34,6 +35,9 @@ $product->setTypeId(Mage_Catalog_Model_Product_Type::TYPE_SIMPLE) ->setName('Simple Product') ->setSku('simple') ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) ->setTierPrice( array( array( diff --git a/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system.php b/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system.php index 3346813b313..a5321101b07 100644 --- a/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system.php +++ b/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system.php @@ -26,11 +26,11 @@ */ $model = new Mage_Catalog_Model_Resource_Eav_Attribute( - new Mage_Core_Model_Event_Manager(), - new Mage_Core_Model_Cache() + Mage::getModel('Mage_Core_Model_Event_Manager'), + Mage::getModel('Mage_Core_Model_Cache') ); $model->setName('system_attribute') ->setId(2) ->setEntityTypeId(4) ->setIsUserDefined(0); -$model->save(); \ No newline at end of file +$model->save(); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system_with_applyto_data.php b/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system_with_applyto_data.php index 118200afc08..d79842026b3 100644 --- a/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system_with_applyto_data.php +++ b/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_system_with_applyto_data.php @@ -26,12 +26,12 @@ */ $model = new Mage_Catalog_Model_Resource_Eav_Attribute( - new Mage_Core_Model_Event_Manager(), - new Mage_Core_Model_Cache() + Mage::getModel('Mage_Core_Model_Event_Manager'), + Mage::getModel('Mage_Core_Model_Cache') ); $model->setName('system_attribute') ->setId(3) ->setEntityTypeId(4) ->setIsUserDefined(0) ->setApplyTo(array('simple', 'configurable')); -$model->save(); \ No newline at end of file +$model->save(); diff --git a/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_user_defined.php b/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_user_defined.php index 3d1476a02be..ea22b15b484 100644 --- a/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_user_defined.php +++ b/dev/tests/integration/testsuite/Mage/Catalog/controllers/_files/attribute_user_defined.php @@ -26,8 +26,8 @@ */ $model = new Mage_Catalog_Model_Resource_Eav_Attribute( - new Mage_Core_Model_Event_Manager(), - new Mage_Core_Model_Cache() + Mage::getModel('Mage_Core_Model_Event_Manager'), + Mage::getModel('Mage_Core_Model_Cache') ); $model->setName('user_attribute') ->setId(1) diff --git a/dev/tests/integration/testsuite/Mage/CatalogInventory/Model/Stock/Item/ApiTest.php b/dev/tests/integration/testsuite/Mage/CatalogInventory/Model/Stock/Item/ApiTest.php new file mode 100644 index 00000000000..4b8a911376d --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/CatalogInventory/Model/Stock/Item/ApiTest.php @@ -0,0 +1,53 @@ +<?php +/** + * Stock item API test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Catalog/_files/multiple_products.php + */ +class Mage_CatalogInventory_Model_Stock_Item_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test list method. + */ + public function testList() + { + $productsId = array(10, 11, 12); + /** Retrieve products stock data. */ + $productsStockData = Magento_Test_Helper_Api::call( + $this, + 'catalogInventoryStockItemList', + array($productsId) + ); + /** Assert product stock data retrieving was successful. */ + $this->assertNotEmpty($productsStockData, 'Product stock data retrieving was unsuccessful.'); + /** Assert retrieved product stock data is correct. */ + $expectedData = array( + 'product_id' => '10', + 'sku' => 'simple1', + 'qty' => 100, + 'is_in_stock' => '1' + ); + $stockData = reset($productsStockData); + $this->assertEquals($expectedData, $stockData, 'Product stock data is incorrect.'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/CatalogSearch/controllers/ResultControllerTest.php b/dev/tests/integration/testsuite/Mage/CatalogSearch/controllers/ResultControllerTest.php index b45f3e28d30..0b2b6941ca3 100644 --- a/dev/tests/integration/testsuite/Mage/CatalogSearch/controllers/ResultControllerTest.php +++ b/dev/tests/integration/testsuite/Mage/CatalogSearch/controllers/ResultControllerTest.php @@ -29,7 +29,6 @@ class Mage_CatalogSearch_ResultControllerTest extends Magento_Test_TestCase_Cont { /** * @magentoDataFixture Mage/CatalogSearch/_files/query.php - * @magentoConfigFixture current_store design/theme/full_name default/demo * @magentoConfigFixture current_store general/locale/code de_DE */ public function testIndexActionTranslation() diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/AbstractTest.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/AbstractTest.php new file mode 100644 index 00000000000..80f8debd833 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/AbstractTest.php @@ -0,0 +1,42 @@ +<?php +/** + * Abstract checkout API testcase. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + */ +abstract class Mage_Checkout_Model_Cart_AbstractTest extends PHPUnit_Framework_TestCase +{ + /** + * Retrieve quote created in fixture. + * + * @return Mage_Sales_Model_Quote + */ + protected function _getQuote() + { + /** @var $session Mage_Checkout_Model_Session */ + $session = Mage::getModel('Mage_Checkout_Model_Session'); + /** @var Mage_Sales_Model_Quote $quote */ + $quote = $session->getQuote(); + return $quote; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Api/_files/license_agreement.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Api/_files/license_agreement.php new file mode 100644 index 00000000000..8f86488487d --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Api/_files/license_agreement.php @@ -0,0 +1,38 @@ +<?php +/** + * Fixture for licenseAgreement method. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** @var Mage_Checkout_Model_Agreement $agreement */ +$agreement = Mage::getModel('Mage_Checkout_Model_Agreement'); +$agreement->setData( + array( + 'name' => 'Agreement name', + 'is_active' => '1', + 'is_html' => '0', + 'checkbox_text' => 'License text', + 'content' => 'Some content', + 'stores' => array(0) + ) +); +$agreement->save(); diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/ApiTest.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/ApiTest.php new file mode 100644 index 00000000000..52871420909 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/ApiTest.php @@ -0,0 +1,445 @@ +<?php +/** + * Checkout API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDbIsolation enabled + */ +class Mage_Checkout_Model_Cart_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test for product add to shopping cart. + * + * @magentoDataFixture Mage/Catalog/_files/product_simple_duplicated.php + * @magentoDataFixture Mage/Checkout/_files/quote.php + */ + public function testProductAddToCart() + { + /** @var Mage_Sales_Model_Resource_Quote_Collection $quoteCollection */ + $quoteCollection = Mage::getModel('Mage_Sales_Model_Resource_Quote_Collection'); + $quote = $quoteCollection->getFirstItem(); + $productSku = 'simple-1'; + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartProductAdd', + array( + 'quoteId' => $quote->getId(), + 'productsData' => array( + (object)array('sku' => $productSku, 'qty' => 1) + ) + ) + ); + + $this->assertTrue($soapResult, 'Error during product add to cart via API call'); + } + + /** + * Test for product with custom options add to shopping cart. + * + * @magentoDataFixture Mage/Catalog/_files/product_with_options.php + * @magentoDataFixture Mage/Checkout/_files/quote.php + */ + public function testProductWithCustomOptionsAddToCart() + { + // Create custom option for product + $customOptionId = null; + $customOptionTitle = 'test_option_code_1'; + $customOptionValue = 'option_value'; + /** @var Mage_Catalog_Model_Product $product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load(1); + /** @var Mage_Sales_Model_Resource_Quote_Collection $quoteCollection */ + $quoteCollection = Mage::getModel('Mage_Sales_Model_Resource_Quote_Collection'); + $quote = $quoteCollection->getFirstItem(); + + // Find ID of created custom option for future use + /** @var $productOption Mage_Catalog_Model_Product_Option */ + $productOption = Mage::getModel('Mage_Catalog_Model_Product_Option'); + + foreach ($productOption->getProductOptionCollection($product) as $option) { + if ($option['default_title'] == $customOptionTitle) { + $customOptionId = $option['option_id']; + break; + } + } + if (null === $customOptionId) { + $this->fail('Can not find custom option ID that been created'); + } + + $customOptionsData = array($customOptionId => $customOptionValue); + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartProductAdd', + array( + 'quoteId' => $quote->getId(), + 'productsData' => array( + (object)array('sku' => $product->getSku(), 'qty' => 1, 'options' => $customOptionsData) + ) + ) + ); + + $this->assertTrue($soapResult, 'Error during product with custom options add to cart via API call'); + + /** @var $quoteItemOption Mage_Sales_Model_Resource_Quote_Item_Option_Collection */ + $quoteItemOption = Mage::getResourceModel('Mage_Sales_Model_Resource_Quote_Item_Option_Collection'); + $itemOptionValue = null; + + foreach ($quoteItemOption->getOptionsByProduct($product) as $row) { + if ('option_' . $customOptionId == $row['code']) { + $itemOptionValue = $row['value']; + break; + } + } + if (null === $itemOptionValue) { + $this->fail('Custom option value not found in DB after API call'); + } + $this->assertEquals( + $customOptionValue, + $itemOptionValue, + 'Custom option value in DB does not match value passed by API' + ); + } + + /** + * Test for product list from shopping cart API method. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + */ + public function testCartProductList() + { + /** @var Mage_Catalog_Model_Product $product */ + $product = Mage::getModel('Mage_Catalog_Model_Product'); + $product->load(1); + /** @var Mage_Sales_Model_Resource_Quote_Collection $quoteCollection */ + $quoteCollection = Mage::getModel('Mage_Sales_Model_Resource_Quote_Collection'); + $quote = $quoteCollection->getFirstItem(); + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartProductList', + array('quoteId' => $quote->getId()) + ); + + $this->assertInternalType('array', $soapResult, 'Product List call result is not an array'); + + if (0 === key($soapResult)) { + $this->assertCount(1, $soapResult, 'Product List call result contain not exactly one product'); + + $soapResult = $soapResult[0]; //workaround for different result structure + } + $this->assertArrayHasKey('sku', $soapResult, 'Product List call result does not contain a product sku'); + $this->assertEquals($product->getSku(), $soapResult['sku'], 'Product Sku does not match fixture'); + } + + /** + * Test for product list from shopping cart API method + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_check_payment.php + * @magentoAppIsolation enabled + */ + public function testCreateOrder() + { + // Set order increment id prefix + $prefix = '01'; + Magento_Test_Helper_Eav::setIncrementIdPrefix('order', $prefix); + + $quote = $this->_getQuoteFixture(); + $orderIncrementId = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartOrder', + array( + 'quoteId' => $quote->getId() + ) + ); + + $this->assertTrue(is_string($orderIncrementId), 'Increment Id is not a string'); + $this->assertStringStartsWith($prefix, $orderIncrementId, 'Increment Id returned by API is not correct'); + } + + /** + * Test order creation with payment method + * + * @magentoConfigFixture current_store payment/ccsave/active 1 + * @magentoDataFixture Mage/Checkout/_files/quote_with_ccsave_payment.php + * @magentoAppIsolation enabled + */ + public function testCreateOrderWithPayment() + { + $quote = $this->_getQuoteFixture(); + $paymentMethod = array( + 'method' => 'ccsave', + 'cc_owner' => 'user', + 'cc_type' => 'VI', + 'cc_exp_month' => 5, + 'cc_exp_year' => 2016, + 'cc_number' => '4584728193062819', + 'cc_cid' => '000', + ); + + $orderIncrementId = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartOrderWithPayment', + array( + 'quoteId' => $quote->getId(), + 'store' => null, + 'agreements' => null, + 'paymentData' => (object)$paymentMethod + ) + ); + + $this->assertTrue(is_string($orderIncrementId), 'Increment Id is not a string'); + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::getModel('Mage_Sales_Model_Order')->loadByIncrementId($orderIncrementId); + $this->assertEquals('ccsave', $order->getPayment()->getMethod()); + } + + /** + * Test order creation with not available payment method + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_ccsave_payment.php + * @magentoAppIsolation enabled + */ + public function testCreateOrderWithNotAvailablePayment() + { + $quote = $this->_getQuoteFixture(); + $paymentMethod = array( + 'method' => 'paypal_direct', + 'cc_owner' => 'user', + 'cc_type' => 'VI', + 'cc_exp_month' => 5, + 'cc_exp_year' => 2016, + 'cc_number' => '4584728193062819', + 'cc_cid' => '000', + ); + + $errorCode = 1075; + $errorMessage = 'The requested Payment Method is not available.'; + try { + Magento_Test_Helper_Api::call( + $this, + 'shoppingCartOrderWithPayment', + array( + 'quoteId' => $quote->getId(), + 'store' => null, + 'agreements' => null, + 'paymentData' => (object)$paymentMethod + ) + ); + $this->fail('Expected error exception was not raised.'); + } catch (SoapFault $e) { + $this->_assertError($errorCode, $errorMessage, $e->faultcode, $e->faultstring); + } + } + + /** + * Test order creation with payment method data empty + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_ccsave_payment.php + * @magentoAppIsolation enabled + */ + public function testCreateOrderWithEmptyPaymentData() + { + $quote = $this->_getQuoteFixture(); + $errorCode = 1071; + $errorMessage = 'Payment method data is empty.'; + try { + Magento_Test_Helper_Api::call( + $this, + 'shoppingCartOrderWithPayment', + array( + 'quoteId' => $quote->getId(), + 'store' => null, + 'agreements' => null, + 'paymentData' => array() + ) + ); + $this->fail('Expected error exception was not raised.'); + } catch (SoapFault $e) { + $this->_assertError($errorCode, $errorMessage, $e->faultcode, $e->faultstring); + } + } + + /** + * Test order creation with invalid payment method data + * + * @magentoConfigFixture current_store payment/ccsave/active 1 + * @magentoDataFixture Mage/Checkout/_files/quote_with_ccsave_payment.php + * @magentoAppIsolation enabled + */ + public function testCreateOrderWithInvalidPaymentData() + { + $quote = $this->_getQuoteFixture(); + $paymentMethod = array( + 'method' => 'ccsave', + 'cc_owner' => 'user', + 'cc_type' => 'VI', + 'cc_exp_month' => 5, + 'cc_exp_year' => 2010, + 'cc_number' => '4584728193062819', + 'cc_cid' => '000', + ); + $errorCode = 1075; + $errorMessage = 'Incorrect credit card expiration date.'; + try { + Magento_Test_Helper_Api::call( + $this, + 'shoppingCartOrderWithPayment', + array( + 'quoteId' => $quote->getId(), + 'store' => null, + 'agreements' => null, + 'paymentData' => (object)$paymentMethod + ) + ); + $this->fail('Expected error exception was not raised.'); + } catch (SoapFault $e) { + $this->_assertError($errorCode, $errorMessage, $e->faultcode, $e->faultstring); + } + } + + /** + * Assert that error code and message equals expected + * + * @param int $expectedCode + * @param string $expectedMessage + * @param int $actualCode + * @param string $actualMessage + */ + protected function _assertError($expectedCode, $expectedMessage, $actualCode, $actualMessage) + { + $this->assertEquals($expectedCode, $actualCode); + $this->assertEquals($expectedMessage, $actualMessage); + } + + /** + * Test info method. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_check_payment.php + */ + public function testInfo() + { + /** @var Mage_Checkout_Model_Cart $quote */ + $quote = $this->_getQuoteFixture(); + $quoteId = $quote->getId(); + /** Retrieve quote info. */ + $quoteInfo = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartInfo', + array($quoteId) + ); + /** Assert quote info retrieving was successful. */ + $this->assertNotEmpty($quoteInfo, 'Quote info retrieving was unsuccessful.'); + /** Assert base fields are present in the response. */ + $expectedFields = array('shipping_address', 'billing_address', 'items', 'payment'); + $missingFields = array_diff($expectedFields, array_keys($quoteInfo)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in response: %s.", implode(', ', $missingFields)) + ); + /** Assert retrieved quote id is correct. */ + $this->assertEquals($quoteId, $quoteInfo['quote_id'], 'Quote Id retrieving was unsuccessful.'); + } + + /** + * Test totals method. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_check_payment.php + */ + public function testTotals() + { + if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { + $this->markTestIncomplete('Legacy API is expected to support MySQL only.'); + } + /** @var Mage_Checkout_Model_Cart $quote */ + $quote = $this->_getQuoteFixture(); + $quoteId = $quote->getId(); + /** Retrieve quote info. */ + $quoteTotals = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartTotals', + array($quoteId) + ); + /** Assert quote totals retrieving were successful. */ + $this->assertNotEmpty($quoteTotals, 'Quote totals retrieving were unsuccessful.'); + /** Assert totals titles. */ + $expectedQuotesTitles = array('Subtotal', 'Grand Total'); + $actualQuotesTitles = array(); + $grandTotal = null; + foreach ($quoteTotals as $quoteTotal) { + $actualQuotesTitles[] = $quoteTotal['title']; + if ($quoteTotal['title'] == 'Grand Total') { + $grandTotal = $quoteTotal; + } + } + $missingQuotesTitles = array_diff($expectedQuotesTitles, $actualQuotesTitles); + $this->assertEmpty( + $missingQuotesTitles, + sprintf("The following quotes titles must be present in response: %s.", implode(', ', $missingQuotesTitles)) + ); + /** Assert grand total is retrieved correct. */ + $expectedGrandTotal = array('title' => 'Grand Total', 'amount' => 20); + $this->assertEquals($expectedGrandTotal, $grandTotal, 'Grand total retrieving was unsuccessful.'); + } + + /** + * Test licenseAgreement method. + * + * @magentoConfigFixture current_store checkout/options/enable_agreements 1 + * @magentoDataFixture Mage/Checkout/Model/Cart/Api/_files/license_agreement.php + * @magentoDataFixture Mage/Checkout/_files/quote_with_check_payment.php + */ + public function testLicenseAgreement() + { + /** @var Mage_Checkout_Model_Cart $quote */ + $quote = $this->_getQuoteFixture(); + $quoteId = $quote->getId(); + /** Retrieve quote license agreement. */ + $licenseAgreement = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartLicense', + array($quoteId) + ); + /** Assert quote license agreement retrieving were successful. */ + $this->assertNotEmpty($licenseAgreement, 'Quote license agreement retrieving was unsuccessful.'); + /** Assert license info is retrieved correct. */ + /** @var Mage_Checkout_Model_Agreement $agreement */ + $agreement = Mage::getModel('Mage_Checkout_Model_Agreement')->load('Agreement name', 'name'); + $agreementData = $agreement->getData(); + unset($agreementData['store_id']); + $this->assertEquals($agreementData, reset($licenseAgreement), 'License agreement data is incorrect.'); + } + + /** + * Retrieve the quote object created in fixture. + * + * @return Mage_Sales_Model_Quote + */ + protected function _getQuoteFixture() + { + /** @var Mage_Sales_Model_Resource_Quote_Collection $quoteCollection */ + $quoteCollection = Mage::getModel('Mage_Sales_Model_Resource_Quote_Collection'); + /** @var Mage_Sales_Model_Quote $quote */ + $quote = $quoteCollection->getFirstItem(); + return $quote; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Coupon/ApiTest.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Coupon/ApiTest.php new file mode 100644 index 00000000000..89f3cbc7438 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Coupon/ApiTest.php @@ -0,0 +1,105 @@ +<?php +/** + * Coupon API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + * @magentoDataFixture Mage/Checkout/_files/discount_10percent.php + */ +class Mage_Checkout_Model_Cart_Coupon_ApiTest extends PHPUnit_Framework_TestCase +{ + /** @var Mage_Catalog_Model_Product */ + protected $_product; + /** @var Mage_Sales_Model_Quote */ + protected $_quote; + /** @var Mage_SalesRule_Model_Rule */ + protected $_salesRule; + + /** + * We can't put this code inside setUp() as it will be called before fixtures execution + */ + protected function _init() + { + $this->_product = Mage::getModel('Mage_Catalog_Model_Product')->load(1); + $this->_quote = Mage::getModel('Mage_Sales_Model_Resource_Quote_Collection')->getFirstItem(); + $this->_salesRule = Mage::getModel('Mage_SalesRule_Model_Rule')->load('Test Coupon', 'name'); + } + + /** + * Test coupon code applying. + */ + public function testCartCouponAdd() + { + $this->_init(); + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartCouponAdd', + array( + 'quoteId' => $this->_quote->getId(), + 'couponCode' => $this->_salesRule->getCouponCode() + ) + ); + + $this->assertTrue($soapResult, 'Coupon code was not applied'); + /** @var $discountedQuote Mage_Sales_Model_Quote */ + $discountedQuote = $this->_quote->load($this->_quote->getId()); + $discountedPrice = sprintf('%01.2f', $this->_product->getPrice() * (1 - 10 / 100)); + + $this->assertEquals( + $discountedQuote->getSubtotalWithDiscount(), + $discountedPrice, + 'Quote subtotal price does not match discounted item price' + ); + } + + /** + * Test coupon code removing + */ + public function testCartCouponRemove() + { + $this->_init(); + $originalPrice = $this->_product->getPrice(); + + // Apply coupon + $this->_quote->setCouponCode($this->_salesRule->getCouponCode()) + ->collectTotals() + ->save(); + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartCouponRemove', + array('quoteId' => $this->_quote->getId()) + ); + + $this->assertTrue($soapResult, 'Coupon code was not removed'); + + /** @var $quoteWithoutDiscount Mage_Sales_Model_Quote */ + $quoteWithoutDiscount = $this->_quote->load($this->_quote->getId()); + + $this->assertEquals( + $originalPrice, + $quoteWithoutDiscount->getSubtotalWithDiscount(), + 'Quote subtotal price does not match its original price after discount removal' + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Customer/ApiTest.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Customer/ApiTest.php new file mode 100644 index 00000000000..e26ed7e4e3a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Customer/ApiTest.php @@ -0,0 +1,116 @@ +<?php +/** + * Checkout Cart Customer API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + */ +class Mage_Checkout_Model_Cart_Customer_ApiTest extends Mage_Checkout_Model_Cart_AbstractTest +{ + /** + * Test setting customer to a quote. + */ + public function testSet() + { + $quote = $this->_getQuote(); + + $customerData = array( + 'firstname' => 'testFirstname', + 'lastname' => 'testLastName', + 'email' => 'testEmail@mail.com', + 'mode' => 'guest', + 'website_id' => '0' + ); + + $result = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartCustomerSet', + array( + 'quoteId' => $quote->getId(), + 'customerData' => (object)$customerData, + ) + ); + $this->assertTrue($result); + + $quote->load($quote->getId()); + $expectedQuoteData = array( + 'customer_firstname' => 'testFirstname', + 'customer_lastname' => 'testLastName', + 'customer_email' => 'testEmail@mail.com', + ); + $diff = array_diff_assoc($expectedQuoteData, $quote->getData()); + $this->assertEmpty($diff, 'Customer data in quote is incorrect.'); + } + + /** + * Test setting customer address data to a quote. + */ + public function testSetAddresses() + { + $quote = $this->_getQuote(); + + $billingAddress = array( + 'mode' => 'billing', + 'firstname' => 'first name', + 'lastname' => 'last name', + 'street' => 'street address', + 'city' => 'city', + 'postcode' => 'postcode', + 'country_id' => 'US', + 'region_id' => 1, + 'telephone' => '123456789', + 'is_default_billing' => 1 + ); + $shippingAddress = array( + 'mode' => 'shipping', + 'firstname' => 'testFirstname', + 'lastname' => 'testLastname', + 'company' => 'testCompany', + 'street' => 'testStreet', + 'city' => 'testCity', + 'postcode' => 'testPostcode', + 'country_id' => 'US', + 'region_id' => 1, + 'telephone' => '0123456789', + 'is_default_shipping' => 0, + ); + + $result = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartCustomerAddresses', + array( + 'quoteId' => $quote->getId(), + 'customerAddressData' => array( + (object)$billingAddress, + (object)$shippingAddress, + ), + ) + ); + $this->assertTrue($result); + + $quote->load($quote->getId()); + $billingDiff = array_diff($billingAddress, $quote->getBillingAddress()->getData()); + $this->assertEmpty($billingDiff, 'Billing address in quote is incorrect.'); + $shippingDiff = array_diff($shippingAddress, $quote->getShippingAddress()->getData()); + $this->assertEmpty($shippingDiff, 'Shipping address in quote is incorrect.'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Payment/ApiTest.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Payment/ApiTest.php new file mode 100644 index 00000000000..cbe942177e4 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Payment/ApiTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Cart payment methods API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Checkout_Model_Cart_Payment_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test retrieving list of available payment methods for a particular quote + * + * @magentoDataFixture Mage/Checkout/_files/quote.php + */ + public function testShoppingCartPaymentList() + { + $paymentMethods = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartPaymentList', + array( + 'quoteId' => $this->_getQuote()->getId(), + ) + ); + + $this->assertCount(1, $paymentMethods, 'Exactly one payment method was expected.'); + $this->assertEquals('free', $paymentMethods[0]['code'], '"free" method expected'); + } + + /** + * Test setting payment method for the cart + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_address_saved.php + */ + public function testShoppingCartPaymentMethod() + { + $paymentMethod = array( + 'po_number' => null, + 'method' => 'checkmo', + 'cc_cid' => null, + 'cc_owner' => null, + 'cc_number' => null, + 'cc_type' => null, + 'cc_exp_year' => null, + 'cc_exp_month' => null + ); + + $result = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartPaymentMethod', + array( + 'quoteId' => $this->_getQuote()->getId(), + 'paymentData' => (object)$paymentMethod, + ) + ); + + $this->assertTrue($result, 'Unable to set payment method'); + } + + /** + * Returns quote generated by fixture + * + * @return Mage_Sales_Model_Quote + */ + protected function _getQuote() + { + /** @var Mage_Sales_Model_Resource_Quote_Collection $quoteCollection */ + $quoteCollection = Mage::getModel('Mage_Sales_Model_Resource_Quote_Collection'); + /** @var $quote Mage_Sales_Model_Quote */ + $quote = $quoteCollection->getFirstItem(); + + return $quote; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Product/ApiTest.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Product/ApiTest.php new file mode 100644 index 00000000000..c637eb37237 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Product/ApiTest.php @@ -0,0 +1,142 @@ +<?php +/** + * Checkout Cart Product API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Checkout_Model_Cart_Product_ApiTest extends Mage_Checkout_Model_Cart_AbstractTest +{ + /** + * Test quote item update. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + */ + public function testUpdate() + { + $quote = $this->_getQuote(); + $quoteItems = $quote->getAllItems(); + /** @var Mage_Sales_Model_Quote_Item $quoteItem */ + $quoteItem = reset($quoteItems); + $this->assertEquals(1, $quoteItem->getQty(), 'Quote item should have qty = 1.'); + + $qtyToUpdate = 5; + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartProductUpdate', + array( + 'quoteId' => $quote->getId(), + 'productsData' => array( + (object)array( + 'sku' => 'simple', + 'qty' => $qtyToUpdate, + ) + ) + ) + ); + + $this->assertTrue($soapResult, 'Error during product update in cart via API call'); + /** @var Mage_Sales_Model_Quote $quoteAfterUpdate */ + $quoteAfterUpdate = Mage::getModel('Mage_Sales_Model_Quote'); + $quoteAfterUpdate->load($quote->getId()); + $quoteItemsUpdated = $quoteAfterUpdate->getAllItems(); + /** @var Mage_Sales_Model_Quote_Item $quoteItem */ + $quoteItemUpdated = reset($quoteItemsUpdated); + $this->assertEquals($qtyToUpdate, $quoteItemUpdated->getQty(), 'Incorrect quote item quantity after update.'); + } + + /** + * Test quote item remove. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + */ + public function testRemove() + { + $quote = $this->_getQuote(); + $this->assertCount(1, $quote->getAllItems(), 'Quote should have exactly 1 item.'); + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartProductRemove', + array( + 'quoteId' => $quote->getId(), + 'productsData' => array( + (object)array( + 'sku' => 'simple', + ) + ) + ) + ); + + $this->assertTrue($soapResult, 'Error during product remove from cart via API call'); + /** @var Mage_Sales_Model_Quote $quoteAfterUpdate */ + $quoteAfterUpdate = Mage::getModel('Mage_Sales_Model_Quote'); + $quoteAfterUpdate->load($quote->getId()); + $this->assertCount(0, $quoteAfterUpdate->getAllItems(), 'Quote item was not deleted.'); + } + + /** + * Test quote item moving from inactive quote to active customer quote. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + * @magentoDataFixture Mage/Customer/_files/customer.php + * @magentoDbIsolation enabled + * @magentoConfigIsolation enabled + */ + public function testMoveToCustomerQuote() + { + /** Prepare data. */ + $inactiveQuote = $this->_getQuote(); + $this->assertCount(1, $inactiveQuote->getAllItems(), 'Quote should have exactly 1 item.'); + $inactiveQuote->setIsActive(0)->setCustomerId(1)->save(); + $activeQuote = Mage::getModel('Mage_Sales_Model_Quote'); + $activeQuote->setData(array( + 'store_id' => 1, + 'is_active' => 1, + 'is_multi_shipping' => 0, + 'customer_id' => 1 + )); + $activeQuote->save(); + + /** Move products from inactive quote via API. */ + $isSuccessful = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartProductMoveToCustomerQuote', + array( + 'quoteId' => $inactiveQuote->getId(), + 'productsData' => array( + (object)array( + 'product_id' => '1' + ) + ) + ) + ); + $this->assertTrue($isSuccessful, "Product was not moved from inactive quote to active one."); + + /** Ensure that data was saved to DB correctly. */ + /** @var Mage_Sales_Model_Quote $quoteAfterMove */ + $quoteAfterMove = Mage::getModel('Mage_Sales_Model_Quote'); + $quoteAfterMove->load($activeQuote->getId()); + /** @var Mage_Sales_Model_Resource_Quote_Item_Collection $itemsCollection */ + $itemsCollection = $quoteAfterMove->getItemsCollection(false); + $this->assertCount(1, $itemsCollection->getItems(), 'Product was not moved from inactive quote to active one.'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Shipping/ApiTest.php b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Shipping/ApiTest.php new file mode 100644 index 00000000000..d6167a2c097 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/Model/Cart/Shipping/ApiTest.php @@ -0,0 +1,116 @@ +<?php +/** + * Tests for shipping method in shopping cart API. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Checkout/_files/quote_with_check_payment.php + */ +class Mage_Checkout_Model_Cart_Shipping_ApiTest extends PHPUnit_Framework_TestCase +{ + protected function setUp() + { + /** Collect rates before requesting them via API. */ + $this->_getQuoteFixture()->getShippingAddress()->setCollectShippingRates(true)->collectTotals()->save(); + parent::setUp(); + } + + /** + * Test retrieving of shipping methods applicable to the shopping cart. + * + */ + public function testGetShippingMethodsList() + { + /** Retrieve the list of available shipping methods via API. */ + $shippingMethodsList = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartShippingList', + array( + $this->_getQuoteFixture()->getId() + ) + ); + + /** Verify the API call results. */ + $this->assertCount(1, $shippingMethodsList, 'There is exactly 1 shipping method expected.'); + $expectedItemData = array( + 'code' => 'flatrate_flatrate', + 'carrier' => 'flatrate', + 'carrier_title' => 'Flat Rate', + 'method' => 'flatrate', + 'method_title' => 'Fixed', + 'method_description' => null, + 'price' => 10 + ); + Magento_Test_Helper_Api::checkEntityFields($this, $expectedItemData, reset($shippingMethodsList)); + } + + /** + * Test assigning shipping method to quote. + * + * @magentoDbIsolation enabled + */ + public function testSetShippingMethod() + { + /** Prepare data. */ + $this->_getQuoteFixture()->getShippingAddress()->setShippingMethod(null)->save(); + /** @var Mage_Sales_Model_Quote $quoteBefore */ + $quoteBefore = Mage::getModel('Mage_Sales_Model_Quote')->load($this->_getQuoteFixture()->getId()); + $this->assertNull( + $quoteBefore->getShippingAddress()->getShippingMethod(), + "There should be no shipping method assigned to quote before assigning via API." + ); + + /** Retrieve the list of available shipping methods via API. */ + $shippingMethod = 'flatrate_flatrate'; + $isAdded = Magento_Test_Helper_Api::call( + $this, + 'shoppingCartShippingMethod', + array( + $this->_getQuoteFixture()->getId(), + $shippingMethod + ) + ); + $this->assertTrue($isAdded, "Shipping method was not assigned to the quote."); + + /** Ensure that data was saved to DB. */ + /** @var Mage_Sales_Model_Quote $quoteAfter */ + $quoteAfter = Mage::getModel('Mage_Sales_Model_Quote')->load($this->_getQuoteFixture()->getId()); + $this->assertEquals( + $shippingMethod, + $quoteAfter->getShippingAddress()->getShippingMethod(), + "Shipping method was assigned to quote incorrectly." + ); + } + + /** + * Retrieve the quote object created in fixture. + * + * @return Mage_Sales_Model_Quote + */ + protected function _getQuoteFixture() + { + /** @var Mage_Sales_Model_Resource_Quote_Collection $quoteCollection */ + $quoteCollection = Mage::getModel('Mage_Sales_Model_Resource_Quote_Collection'); + /** @var Mage_Sales_Model_Quote $quote */ + $quote = $quoteCollection->getFirstItem(); + return $quote; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Checkout/_files/discount_10percent.php b/dev/tests/integration/testsuite/Mage/Checkout/_files/discount_10percent.php new file mode 100644 index 00000000000..6fe060ac454 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/_files/discount_10percent.php @@ -0,0 +1,42 @@ +<?php +/** + * SalesRule 10% discount coupon + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var Mage_SalesRule_Model_Rule $salesRule */ +$salesRule = Mage::getModel('Mage_SalesRule_Model_Rule'); + +$data = array( + 'name' => 'Test Coupon', + 'is_active' => true, + 'website_ids' => array(Mage::app()->getStore()->getWebsiteId()), + 'customer_group_ids' => array(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID), + 'coupon_type' => Mage_SalesRule_Model_Rule::COUPON_TYPE_SPECIFIC, + 'coupon_code' => uniqid(), + 'simple_action' => Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION, + 'discount_amount' => 10, + 'discount_step' => 1, +); + +$salesRule->loadPost($data)->setUseAutoGeneration(false)->save(); diff --git a/dev/tests/integration/testsuite/Mage/Checkout/_files/quote.php b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote.php new file mode 100644 index 00000000000..f22b6c2f60a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote.php @@ -0,0 +1,34 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Checkout + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +$quote = Mage::getModel('Mage_Sales_Model_Quote'); +$quote->setData(array( + 'store_id' => 1, + 'is_active' => 0, + 'is_multi_shipping' => 0 +)); +$quote->save(); diff --git a/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address.php b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address.php new file mode 100644 index 00000000000..6ce6910e660 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address.php @@ -0,0 +1,46 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Checkout + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +require __DIR__ . '/../../Customer/_files/customer.php'; +require __DIR__ . '/../../Customer/_files/customer_address.php'; +require __DIR__ . '/../../Catalog/_files/products.php'; + +/** @var Mage_Sales_Model_Quote_Address $quoteShippingAddress */ +$quoteShippingAddress = Mage::getModel('Mage_Sales_Model_Quote_Address'); +$quoteShippingAddress->importCustomerAddress($customerAddress); + +/** @var Mage_Sales_Model_Quote $quote */ +$quote = Mage::getModel('Mage_Sales_Model_Quote'); +$quote->setStoreId(1) + ->setIsActive(false) + ->setIsMultiShipping(false) + ->assignCustomerWithAddressChange($customer) + ->setShippingAddress($quoteShippingAddress) + ->setBillingAddress($quoteShippingAddress) + ->setCheckoutMethod($customer->getMode()) + ->setPasswordHash($customer->encryptPassword($customer->getPassword())) + ->addProduct($product->load($product->getId()), 2); diff --git a/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address_saved.php b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address_saved.php new file mode 100644 index 00000000000..c8ebe691aff --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_address_saved.php @@ -0,0 +1,32 @@ +<?php +/** + * Save quote_with_address fixture + * + * The quote is not saved inside the original fixture. It is later saved inside child fixtures, but along with some + * additional data which may break some tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +require 'quote_with_address.php'; + +$quote->collectTotals()->save(); diff --git a/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_ccsave_payment.php b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_ccsave_payment.php new file mode 100644 index 00000000000..aa4ce46a90c --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_ccsave_payment.php @@ -0,0 +1,38 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Checkout + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +require 'quote_with_address.php'; +/** @var Mage_Sales_Model_Quote $quote */ + +$quote->getShippingAddress()->setShippingMethod('flatrate_flatrate'); +$quote->getPayment()->setMethod('ccsave'); + +$quote->collectTotals(); +$quote->save(); + +$quoteService = new Mage_Sales_Model_Service_Quote($quote); +$quoteService->getQuote()->getPayment()->setMethod('ccsave'); diff --git a/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment.php b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment.php new file mode 100644 index 00000000000..530f7f4f8a1 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment.php @@ -0,0 +1,44 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Checkout + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +require 'quote_with_address.php'; +/** @var Mage_Sales_Model_Quote $quote */ + +/** @var $rate Mage_Sales_Model_Quote_Address_Rate */ +$rate = Mage::getModel('Mage_Sales_Model_Quote_Address_Rate'); +$rate->setCode('freeshipping_freeshipping'); +$rate->getPrice(1); + +$quote->getShippingAddress()->setShippingMethod('freeshipping_freeshipping'); +$quote->getShippingAddress()->addShippingRate($rate); +$quote->getPayment()->setMethod('checkmo'); + +$quote->collectTotals(); +$quote->save(); + +$quoteService = new Mage_Sales_Model_Service_Quote($quote); +$quoteService->getQuote()->getPayment()->setMethod('checkmo'); diff --git a/app/code/core/Mage/Core/Block/Template/Smarty.php b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment_rollback.php similarity index 87% rename from app/code/core/Mage/Core/Block/Template/Smarty.php rename to dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment_rollback.php index f08d18c79e0..ee4e5738b19 100644 --- a/app/code/core/Mage/Core/Block/Template/Smarty.php +++ b/dev/tests/integration/testsuite/Mage/Checkout/_files/quote_with_check_payment_rollback.php @@ -1,5 +1,7 @@ <?php /** + * Rollback for quote_with_check_payment.php fixture. + * * Magento * * NOTICE OF LICENSE @@ -18,14 +20,8 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Mage - * @package Mage_Core * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - -class Mage_Core_Block_Template_Smarty extends Mage_Core_Block_Template -{ - -} +Mage::unregister('quote'); diff --git a/dev/tests/integration/testsuite/Mage/Cms/Helper/Wysiwyg/ImagesTest.php b/dev/tests/integration/testsuite/Mage/Cms/Helper/Wysiwyg/ImagesTest.php new file mode 100644 index 00000000000..f86f6758869 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Cms/Helper/Wysiwyg/ImagesTest.php @@ -0,0 +1,41 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Cms_Helper_Wysiwyg_ImagesTest extends PHPUnit_Framework_TestCase +{ + public function testGetStorageRoot() + { + /** @var $dir Mage_Core_Model_Dir */ + $dir = Mage::getObjectManager()->get('Mage_Core_Model_Dir'); + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + $helper = new Mage_Cms_Helper_Wysiwyg_Images($filesystem); + $this->assertStringStartsWith($dir->getDir(Mage_Core_Model_Dir::MEDIA), $helper->getStorageRoot()); + } + + public function testGetCurrentUrl() + { + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + $helper = new Mage_Cms_Helper_Wysiwyg_Images($filesystem); + $this->assertStringStartsWith('http://localhost/', $helper->getCurrentUrl()); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Cms/Model/Wysiwyg/Images/StorageTest.php b/dev/tests/integration/testsuite/Mage/Cms/Model/Wysiwyg/Images/StorageTest.php index 38f91035eb6..0b48561e6ae 100644 --- a/dev/tests/integration/testsuite/Mage/Cms/Model/Wysiwyg/Images/StorageTest.php +++ b/dev/tests/integration/testsuite/Mage/Cms/Model/Wysiwyg/Images/StorageTest.php @@ -65,4 +65,14 @@ class Mage_Cms_Model_Wysiwyg_Images_StorageTest extends PHPUnit_Framework_TestCa return; } } + + public function testGetThumbsPath() + { + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + $model = new Mage_Cms_Model_Wysiwyg_Images_Storage($filesystem); + $this->assertStringStartsWith( + realpath(Magento_Test_Bootstrap::getInstance()->getInstallDir()), + $model->getThumbsPath() + ); + } } diff --git a/dev/tests/integration/testsuite/Mage/Core/Block/AbstractTest.php b/dev/tests/integration/testsuite/Mage/Core/Block/AbstractTest.php index a35eadadb08..43508972b1f 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Block/AbstractTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Block/AbstractTest.php @@ -424,14 +424,19 @@ class Mage_Core_Block_AbstractTest extends PHPUnit_Framework_TestCase public function testGetChildData() { $parent = $this->_createBlockWithLayout('parent', 'parent'); - $block = $this->_createBlockWithLayout('block', 'block', 'Mage_Core_Block_Text'); - $block->setSomeValue('value'); + $block = $this->_createBlockWithLayout('block', 'block'); + $block->setSomeProperty('some_value'); $parent->setChild('block1', $block); - $this->assertEquals( - array('type' => 'Mage_Core_Block_TextMock', 'some_value' => 'value'), - $parent->getChildData('block1') - ); - $this->assertEquals('value', $parent->getChildData('block1', 'some_value')); + + // all child data + $actualChildData = $parent->getChildData('block1'); + $this->assertArrayHasKey('some_property', $actualChildData); + $this->assertEquals('some_value', $actualChildData['some_property']); + + // specific child data key + $this->assertEquals('some_value', $parent->getChildData('block1', 'some_property')); + + // non-existing child block $this->assertNull($parent->getChildData('unknown_block')); } @@ -637,27 +642,6 @@ class Mage_Core_Block_AbstractTest extends PHPUnit_Framework_TestCase $this->assertEquals(1800, $this->_block->getCacheLifetime()); } - /** - * App isolation is enabled, because config options object is affected - * - * @magentoAppIsolation enabled - * @magentoDbIsolation enabled - */ - public function testGetVar() - { - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__DIR__) . '/Model/_files/design/' - )); - $themeUtility->registerThemes()->setDesignTheme('test/default', 'frontend'); - - $this->assertEquals('Core Value1', $this->_block->getVar('var1')); - $this->assertEquals('value1', $this->_block->getVar('var1', 'Namespace_Module')); - $this->_block->setModuleName('Namespace_Module'); - $this->assertEquals('value1', $this->_block->getVar('var1')); - $this->assertEquals(false, $this->_block->getVar('unknown_var')); - } - /** * Create <N> sample blocks * diff --git a/dev/tests/integration/testsuite/Mage/Core/Block/TemplateTest.php b/dev/tests/integration/testsuite/Mage/Core/Block/TemplateTest.php index d467916cd9e..858e287fb0b 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Block/TemplateTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Block/TemplateTest.php @@ -60,30 +60,6 @@ class Mage_Core_Block_TemplateTest extends PHPUnit_Framework_TestCase $this->assertEquals('value', $this->_block->getTemplate()); } - /** - * @magentoConfigFixture frontend/design/theme/full_name default/demo - * @magentoConfigFixture adminhtml/design/theme/full_name default/basic - * @magentoAppIsolation enabled - */ - public function testGetTemplateFile() - { - Mage::app()->getConfig()->getOptions()->setDesignDir(__DIR__ . DIRECTORY_SEPARATOR . '_files'); - - // with template - $template = 'dummy.phtml'; - $this->_block->setTemplate($template); - $file = $this->_block->getTemplateFile(); - $this->assertContains('frontend', $file); - $this->assertStringEndsWith($template, $file); - - - // change area - $this->_block->setArea('adminhtml'); - $file = $this->_block->getTemplateFile(); - $this->assertContains('adminhtml', $file); - $this->assertStringEndsWith($template, $file); - } - public function testGetArea() { $this->assertEquals('frontend', $this->_block->getArea()); @@ -93,22 +69,6 @@ class Mage_Core_Block_TemplateTest extends PHPUnit_Framework_TestCase $this->assertEquals('another_area', $this->_block->getArea()); } - /** - * @magentoAppIsolation enabled - * @covers Mage_Core_Block_Template::assign - * @covers Mage_Core_Block_Template::setScriptPath - * @covers Mage_Core_Block_Template::fetchView - */ - public function testAssign() - { - Mage::app()->getConfig()->getOptions()->setDesignDir(dirname(__FILE__) . DIRECTORY_SEPARATOR . '_files'); - - $this->_block->assign(array('varOne' => 'value1', 'varTwo' => 'value2')) - ->setScriptPath(__DIR__ . DIRECTORY_SEPARATOR . '_files'); - $template = __DIR__ . DIRECTORY_SEPARATOR . '_files/template_test_assign.phtml'; - $this->assertEquals('value1, value2', $this->_block->fetchView($template)); - } - public function testGetDirectOutput() { $this->assertFalse($this->_block->getDirectOutput()); @@ -124,34 +84,6 @@ class Mage_Core_Block_TemplateTest extends PHPUnit_Framework_TestCase $this->assertFalse($this->_block->getShowTemplateHints()); } - /** - * @covers Mage_Core_Block_Template::fetchView - * @covers Mage_Core_Block_Abstract::setLayout - * @covers Mage_Core_Block_Abstract::getLayout - * @see testAssign - */ - public function testFetchView() - { - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->setDirectOutput(true); - $this->_block->setLayout($layout); - $this->assertTrue($this->_block->getDirectOutput()); - - $this->assertEmpty($this->_block->fetchView(__DIR__ . DS . uniqid('invalid_filename.phtml'))); - } - - /** - * @magentoAppIsolation enabled - */ - public function testRenderView() - { - $this->assertEmpty($this->_block->renderView()); - Mage::app()->getConfig()->getOptions()->setDesignDir(__DIR__ . DIRECTORY_SEPARATOR . '_files'); - Mage::getDesign()->setDesignTheme('default/demo'); - $this->_block->setTemplate('dummy.phtml'); - $this->assertEquals('1234567890', $this->_block->renderView()); - } - /** * @covers Mage_Core_Block_Template::_toHtml * @covers Mage_Core_Block_Abstract::toHtml diff --git a/dev/tests/integration/testsuite/Mage/Core/Controller/RequestHttpTest.php b/dev/tests/integration/testsuite/Mage/Core/Controller/RequestHttpTest.php index af7170b7de1..06d50829979 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Controller/RequestHttpTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Controller/RequestHttpTest.php @@ -93,18 +93,12 @@ class Mage_Core_Controller_RequestHttpTest extends PHPUnit_Framework_TestCase public function testIsDirectAccessFrontendName() { $this->assertFalse($this->_model->isDirectAccessFrontendName('test')); - $this->assertFalse( - $this->_model->isDirectAccessFrontendName('api'), - "Mage_Core_Controller_RequestHttp should not be used in API area." - ); + $this->assertTrue($this->_model->isDirectAccessFrontendName('api')); } public function testGetDirectFrontNames() { - $this->assertEmpty( - $this->_model->getDirectFrontNames(), - "After API module removal there should not be areas with direct front name." - ); + $this->assertContains('api', array_keys($this->_model->getDirectFrontNames())); } public function testGetOriginalRequest() diff --git a/dev/tests/integration/testsuite/Mage/Core/Controller/Varien/ActionTest.php b/dev/tests/integration/testsuite/Mage/Core/Controller/Varien/ActionTest.php index 9a9fbde137b..0418d124ad5 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Controller/Varien/ActionTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Controller/Varien/ActionTest.php @@ -276,11 +276,10 @@ class Mage_Core_Controller_Varien_ActionTest extends PHPUnit_Framework_TestCase } /** - * @magentoConfigFixture install/design/theme/full_name default/basic - * @magentoConfigFixture adminhtml/design/theme/full_name default/basic - * @magentoConfigFixture current_store design/theme/full_name default/demo - * @magentoAppIsolation enabled - * + * @magentoConfigFixture install/design/theme/full_name default/basic + * @magentoConfigFixture frontend/design/theme/full_name default/demo + * @magentoConfigFixture adminhtml/design/theme/full_name default/basic + * @magentoAppIsolation enabled * @dataProvider controllerAreaDesignDataProvider * * @param string $controllerClass @@ -291,6 +290,7 @@ class Mage_Core_Controller_Varien_ActionTest extends PHPUnit_Framework_TestCase public function testPreDispatch($controllerClass, $expectedArea, $expectedStore, $expectedDesign) { Mage::getConfig()->setCurrentAreaCode($expectedArea); + /** @var $controller Mage_Core_Controller_Varien_Action */ $controller = Mage::getObjectManager()->create($controllerClass, array( diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/App/AreaTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/App/AreaTest.php index 9eb4c5facdc..1a8700ecedf 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/App/AreaTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/App/AreaTest.php @@ -60,30 +60,6 @@ class Mage_Core_Model_App_AreaTest extends PHPUnit_Framework_TestCase $this->assertSame($design, Mage::getDesign()); } - /** - * @magentoConfigFixture adminhtml/design/theme/full_name default/basic - * @magentoAppIsolation enabled - */ - public function testDetectDesignGlobalConfig() - { - /** @var $model Mage_Core_Model_App_Area */ - $model = Mage::getModel('Mage_Core_Model_App_Area', array('areaCode' => 'adminhtml')); - $model->detectDesign(); - $theme = Mage::getDesign()->getConfigurationDesignTheme('adminhtml', array('useId' => false)); - $this->assertEquals('default/basic', $theme); - } - - /** - * @magentoConfigFixture current_store design/theme/full_name default/blank - * @magentoAppIsolation enabled - */ - public function testDetectDesignStoreConfig() - { - $this->_model->detectDesign(); - $theme = Mage::getDesign()->getConfigurationDesignTheme('frontend', array('useId' => false)); - $this->assertEquals('default/blank', $theme); - } - // @codingStandardsIgnoreStart /** * @magentoConfigFixture current_store design/theme/ua_regexp a:1:{s:1:"_";a:2:{s:6:"regexp";s:10:"/firefox/i";s:5:"value";s:14:"default/modern";}} diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/AppTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/AppTest.php index 394cd9a1e8a..ffa98abf307 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/AppTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/AppTest.php @@ -62,13 +62,12 @@ class Mage_Core_Model_AppTest extends PHPUnit_Framework_TestCase /** * @covers Mage_Core_Model_App::_initCache * - * @magentoConfigFixture global/cache/id_prefix test * @magentoAppIsolation enabled */ public function testInit() { $this->assertNull($this->_model->getConfig()); - $this->_model->init(''); + $this->_model->init(Magento_Test_Bootstrap::getInstance()->getInitParams()); $this->assertInstanceOf('Mage_Core_Model_Config', $this->_model->getConfig()); $this->assertNotEmpty($this->_model->getConfig()->getNode()); $this->assertContains(Mage_Core_Model_App::ADMIN_STORE_ID, array_keys($this->_model->getStores(true))); @@ -77,7 +76,19 @@ class Mage_Core_Model_AppTest extends PHPUnit_Framework_TestCase $objectManager = Mage::getObjectManager(); /** @var $cache Mage_Core_Model_Cache */ $cache = $objectManager->get('Mage_Core_Model_Cache'); - $this->assertAttributeEquals('test', '_idPrefix', $cache); + $appCache = $this->_model->getCacheInstance(); + $this->assertSame($appCache, $cache); + } + + /** + * @magentoAppIsolation enabled + */ + public function testBaseInit() + { + $this->assertNull($this->_model->getConfig()); + $this->_model->baseInit(Magento_Test_Bootstrap::getInstance()->getInitParams()); + $this->assertInstanceOf('Mage_Core_Model_Config', $this->_model->getConfig()); + $this->assertNotEmpty($this->_model->getConfig()->getNode()); } /** @@ -88,11 +99,11 @@ class Mage_Core_Model_AppTest extends PHPUnit_Framework_TestCase if (!Magento_Test_Bootstrap::canTestHeaders()) { $this->markTestSkipped('Can\'t test application run without sending headers'); } - - $_SERVER['HTTP_HOST'] = 'localhost'; - $this->_mageModel->getRequest()->setRequestUri('core/index/index'); - $this->_mageModel->run(array()); - $this->assertTrue($this->_mageModel->getRequest()->isDispatched()); + $request = new Magento_Test_Request(); + $request->setRequestUri('core/index/index'); + $this->_mageModel->setRequest($request); + $this->_mageModel->run(Magento_Test_Bootstrap::getInstance()->getInitParams()); + $this->assertTrue($request->isDispatched()); } public function testIsInstalled() @@ -100,20 +111,6 @@ class Mage_Core_Model_AppTest extends PHPUnit_Framework_TestCase $this->assertTrue($this->_mageModel->isInstalled()); } - /** - * @magentoAppIsolation enabled - * @expectedException Magento_Exception - * @expectedExceptionMessage Application is not installed yet, please complete the installation first. - */ - public function testRequireInstalledInstance() - { - $this->_model->baseInit(array( - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA - => sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'invalid') - )); - $this->_model->requireInstalledInstance(); - } - public function testGetCookie() { $this->assertInstanceOf('Mage_Core_Model_Cookie', $this->_model->getCookie()); @@ -396,7 +393,7 @@ class Mage_Core_Model_AppTest extends PHPUnit_Framework_TestCase { $objectManager = Mage::getObjectManager(); $this->_model = $objectManager->get('Mage_Core_Model_App'); - $this->_model->loadDiConfiguration('frontend'); + $this->_model->getConfig()->loadDiConfiguration('frontend'); $testInstance = $objectManager->create('Mage_Backend_Block_Widget_Grid_ColumnSet'); $this->assertAttributeInstanceOf('Mage_DesignEditor_Model_Url_NavigationMode', '_urlBuilder', $testInstance); } diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Config/OptionsTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Config/OptionsTest.php deleted file mode 100644 index eb0b2b8c92a..00000000000 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Config/OptionsTest.php +++ /dev/null @@ -1,151 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Mage_Core - * @subpackage integration_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -class Mage_Core_Model_Config_OptionsTest extends PHPUnit_Framework_TestCase -{ - /** - * @var Mage_Core_Model_Config_Options - */ - protected $_model; - - protected static $_keys = array( - 'app_dir' => 'app', - 'base_dir' => 'base', - 'code_dir' => 'code', - 'design_dir' => 'design', - 'etc_dir' => 'etc', - 'lib_dir' => 'lib', - 'locale_dir' => 'locale', - 'pub_dir' => 'pub', - 'js_dir' => 'js', - 'media_dir' => 'media', - 'var_dir' => 'var', - 'tmp_dir' => 'tmp', - 'cache_dir' => 'cache', - 'log_dir' => 'log', - 'session_dir' => 'session', - 'upload_dir' => 'upload', - 'export_dir' => 'export', - ); - - protected function setUp() - { - $this->_model = Mage::getModel('Mage_Core_Model_Config_Options'); - } - - protected function tearDown() - { - $this->_model = null; - } - - public function testConstruct() - { - $data = $this->_model->getData(); - foreach (array_keys(self::$_keys) as $key) { - $this->assertArrayHasKey($key, $data); - unset($data[$key]); - } - $this->assertEmpty($data); - } - - public function testGetDir() - { - foreach (self::$_keys as $full => $partial) { - $this->assertEquals($this->_model->getData($full), $this->_model->getDir($partial)); - } - } - - /** - * @expectedException Mage_Core_Exception - */ - public function testGetDirException() - { - $this->_model->getDir('invalid'); - } - - /** - * @covers Mage_Core_Model_Config_Options::getAppDir - * @covers Mage_Core_Model_Config_Options::getBaseDir - * @covers Mage_Core_Model_Config_Options::getCodeDir - * @covers Mage_Core_Model_Config_Options::getDesignDir - * @covers Mage_Core_Model_Config_Options::getEtcDir - * @covers Mage_Core_Model_Config_Options::getLibDir - * @covers Mage_Core_Model_Config_Options::getMediaDir - * @covers Mage_Core_Model_Config_Options::getVarDir - * @covers Mage_Core_Model_Config_Options::getTmpDir - * @covers Mage_Core_Model_Config_Options::getCacheDir - * @covers Mage_Core_Model_Config_Options::getLogDir - * @covers Mage_Core_Model_Config_Options::getSessionDir - * @covers Mage_Core_Model_Config_Options::getUploadDir - * @covers Mage_Core_Model_Config_Options::getExportDir - * @dataProvider getGettersDataProvider - * @param string $method - */ - public function testGetters($method) - { - $dir = $this->_model->$method(); - $this->assertFileExists($dir, "Method '{$method}()' returned directory that doesn't exist: '{$dir}'"); - } - - /** - * @return array - */ - public function getGettersDataProvider() - { - return array( - array('getAppDir'), - array('getBaseDir'), - array('getCodeDir'), - array('getDesignDir'), - array('getEtcDir'), - array('getLibDir'), - array('getMediaDir'), - array('getVarDir'), - array('getTmpDir'), - array('getCacheDir'), - array('getLogDir'), - array('getSessionDir'), - array('getUploadDir'), - array('getExportDir'), - ); - } - - public function testCreateDirIfNotExists() - { - $var = $this->_model->getVarDir(); - - $sampleDir = uniqid($var); - $this->assertTrue($this->_model->createDirIfNotExists($sampleDir)); - $this->assertTrue($this->_model->createDirIfNotExists($sampleDir)); - rmdir($sampleDir); - - $sampleFile = "{$var}/" . uniqid('file') . '.txt'; - file_put_contents($sampleFile, '1'); - $this->assertFalse($this->_model->createDirIfNotExists($sampleFile)); - unlink($sampleFile); - } -} diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/ConfigFactoryTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/ConfigFactoryTest.php index a61dbfb6cc7..77afd5eaad2 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/ConfigFactoryTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/ConfigFactoryTest.php @@ -33,20 +33,13 @@ */ class Mage_Core_Model_ConfigFactoryTest extends PHPUnit_Framework_TestCase { - protected static $_options = array(); - /** @var Mage_Core_Model_Config */ protected $_model; - public static function setUpBeforeClass() - { - self::$_options = Magento_Test_Bootstrap::getInstance()->getAppOptions(); - } - public function setUp() { $this->_model = Mage::getModel('Mage_Core_Model_Config'); - $this->_model->init(self::$_options); + $this->_model->init(); } protected function tearDown() diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/ConfigTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/ConfigTest.php index 8241dc7adf8..27a6830eba6 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/ConfigTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/ConfigTest.php @@ -34,11 +34,9 @@ */ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase { - protected static $_options = array(); - - public static function setUpBeforeClass() + protected function setUp() { - self::$_options = Magento_Test_Bootstrap::getInstance()->getAppOptions(); + Mage::app()->getCacheInstance()->banUse('config'); } public function testGetResourceModel() @@ -46,24 +44,11 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase $this->assertInstanceOf('Mage_Core_Model_Resource_Config', $this->_createModel(true)->getResourceModel()); } - public function testGetOptions() - { - $this->assertInstanceOf('Mage_Core_Model_Config_Options', $this->_createModel(true)->getOptions()); - } - - public function testSetOptions() - { - $model = $this->_createModel(); - $key = uniqid('key'); - $model->setOptions(array($key => 'value')); - $this->assertEquals('value', $model->getOptions()->getData($key)); - } - public function testInit() { $model = $this->_createModel(); $this->assertFalse($model->getNode()); - $model->init(self::$_options); + $model->init(); $this->assertInstanceOf('Varien_Simplexml_Element', $model->getNode()); } @@ -71,7 +56,6 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase { $model = $this->_createModel(); $this->assertFalse($model->getNode()); - $model->setOptions(self::$_options); $model->loadBase(); $this->assertInstanceOf('Varien_Simplexml_Element', $model->getNode('global')); } @@ -79,16 +63,18 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase /** * @param string $etcDir * @param array $configOptions - * @param string $expectedNode * @param string $expectedValue + * @param string $expectedNode * @dataProvider loadBaseLocalConfigDataProvider */ - public function testLoadBaseLocalConfig($etcDir, array $configOptions, $expectedNode, $expectedValue) - { - $configOptions['etc_dir'] = __DIR__ . "/_files/local_config/{$etcDir}"; - /** @var $model Mage_Core_Model_Config */ - $model = Mage::getModel('Mage_Core_Model_Config'); - $model->setOptions($configOptions); + public function testLoadBaseLocalConfig($etcDir, array $configOptions, $expectedValue, + $expectedNode = 'global/resources/core_setup/connection/model' + ) { + $configOptions[Mage_Core_Model_App::INIT_OPTION_DIRS] = array( + Mage_Core_Model_Dir::CONFIG => __DIR__ . "/_files/local_config/{$etcDir}", + ); + $model = $this->_createModelWithApp($configOptions); + $model->loadBase(); $this->assertInstanceOf('Varien_Simplexml_Element', $model->getNode($expectedNode)); $this->assertEquals($expectedValue, (string)$model->getNode($expectedNode)); @@ -99,53 +85,61 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase */ public function loadBaseLocalConfigDataProvider() { + $extraConfigData = ' + <root> + <global> + <resources> + <core_setup> + <connection> + <model>overridden</model> + </connection> + </core_setup> + </resources> + </global> + </root> + '; return array( 'no local config file & no custom config file' => array( - 'no_local_config_no_custom_config', - array(Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE => ''), - 'a/value', + 'no_local_config', + array(), 'b', ), 'no local config file & custom config file' => array( - 'no_local_config_custom_config', - array(Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE => 'custom/local.xml'), - 'a', - '', + 'no_local_config', + array(Mage_Core_Model_Config::INIT_OPTION_EXTRA_FILE => 'custom/local.xml'), + 'b', ), 'no local config file & custom config data' => array( - 'no_local_config_no_custom_config', - array( - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA - => '<root><a><value>overridden</value></a></root>' - ), - 'a/value', + 'no_local_config', + array(Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA => $extraConfigData), 'overridden', ), 'local config file & no custom config file' => array( - 'local_config_no_custom_config', - array(Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE => ''), - 'value', + 'local_config', + array(), 'local', ), 'local config file & custom config file' => array( - 'local_config_custom_config', - array(Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE => 'custom/local.xml'), - 'value', + 'local_config', + array(Mage_Core_Model_Config::INIT_OPTION_EXTRA_FILE => 'custom/local.xml'), 'custom', ), - 'local config file & invalid custom config file' => array( - 'local_config_custom_config', - array(Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE => 'custom/invalid.pattern.xml'), - 'value', + 'local config file & prohibited custom config file' => array( + 'local_config', + array(Mage_Core_Model_Config::INIT_OPTION_EXTRA_FILE => 'custom/prohibited.filename.xml'), 'local', ), 'local config file & custom config data' => array( - 'local_config_custom_config', + 'local_config', + array(Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA => $extraConfigData), + 'overridden', + ), + 'local config file & custom config file & custom config data' => array( + 'local_config', array( - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE => 'custom/local.xml', - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA => '<root><value>overridden</value></root>', + Mage_Core_Model_Config::INIT_OPTION_EXTRA_FILE => 'custom/local.xml', + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA => $extraConfigData, ), - 'value', 'overridden', ), ); @@ -156,45 +150,56 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase if (date_default_timezone_get() != 'UTC') { $this->markTestSkipped('Test requires "UTC" to be the default timezone.'); } - /** @var $model Mage_Core_Model_Config */ - $model = Mage::getModel('Mage_Core_Model_Config'); - $model->setOptions(array( - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA + + $options = array( + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA => sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'Fri, 21 Dec 2012 00:00:00 +0000') - )); + ); + $model = $this->_createModelWithApp($options); + $model->loadBase(); $this->assertEquals(1356048000, $model->getInstallDate()); } public function testLoadBaseInstallDateInvalid() { - /** @var $model Mage_Core_Model_Config */ - $model = Mage::getModel('Mage_Core_Model_Config'); - $model->setOptions(array( - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA + $options = array( + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA => sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'invalid') - )); + ); + $model = $this->_createModelWithApp($options); + $model->loadBase(); $this->assertEmpty($model->getInstallDate()); } public function testLoadLocales() { - $model = Mage::getModel('Mage_Core_Model_Config'); - $model->init(array( - 'locale_dir' => dirname(__FILE__) . '/_files/locale' - )); + $options = array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::LOCALE => __DIR__ . '/_files/locale', + ) + ); + $model = $this->_createModelWithApp($options); + + $model->loadBase(); $model->loadLocales(); $this->assertInstanceOf('Mage_Core_Model_Config_Element', $model->getNode('global/locale')); } + /** + * @magentoAppIsolation enabled + */ public function testLoadModulesCache() { - $model = $this->_createModel(); - $model->setOptions(array( - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA + $options = array( + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA => sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'Wed, 21 Nov 2012 03:26:00 +0000') - )); + ); + $model = $this->_createModelWithApp($options); + + Mage::app()->getCacheInstance()->allowUse('config'); + $model->loadBase(); $this->assertTrue($model->loadModulesCache()); $this->assertInstanceOf('Mage_Core_Model_Config_Element', $model->getNode()); @@ -203,7 +208,6 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase public function testLoadModules() { $model = $this->_createModel(); - $model->setOptions(self::$_options); $model->loadBase(); $this->assertFalse($model->getNode('modules')); $model->loadModules(); @@ -214,11 +218,12 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase public function testLoadModulesLocalConfigPrevails() { - $model = $this->_createModel(); - $model->setOptions(array( - Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA + $options = array( + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA => '<config><modules><Mage_Core><active>false</active></Mage_Core></modules></config>' - )); + ); + $model = $this->_createModelWithApp($options); + $model->loadBase(); $model->loadModules(); @@ -231,7 +236,6 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase { $model = $this->_createModel(); $this->assertFalse($model->isLocalConfigLoaded()); - $model->setOptions(self::$_options); $model->loadBase(); $this->assertTrue($model->isLocalConfigLoaded()); } @@ -246,7 +250,6 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase try { $model = $this->_createModel(); - $model->setOptions(self::$_options); $model->loadBase(); $model->loadModules(); @@ -262,15 +265,21 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase public function testReinitBaseConfig() { - $model = $this->_createModel(); - $options = self::$_options; - $options[Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA] = '<config><test>old_value</test></config>'; - $model->setOptions($options); + $options = Magento_Test_Bootstrap::getInstance()->getInitParams(); + $options[Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA] = '<config><test>old_value</test></config>'; + + $objectManager = new Magento_Test_ObjectManager(); + $model = $this->_createModelWithApp($options, $objectManager); + + /** @var $app Mage_Core_Model_App */ + $app = $objectManager->get('Mage_Core_Model_App'); + $model->loadBase(); $this->assertEquals('old_value', $model->getNode('test')); - $options[Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA] = '<config><test>new_value</test></config>'; - $model->setOptions($options); + $options[Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA] = '<config><test>new_value</test></config>'; + $app->init($options); + $model->reinit(); $this->assertEquals('new_value', $model->getNode('test')); } @@ -280,8 +289,13 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase $this->assertInstanceOf('Varien_Cache_Core', $this->_createModel()->getCache()); } + /** + * @magentoAppIsolation enabled + */ public function testSaveCache() { + Mage::app()->getCacheInstance()->allowUse('config'); + $model = $this->_createModel(true); $model->removeCache(); $this->assertFalse($model->loadCache()); @@ -291,8 +305,13 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase $this->assertInstanceOf('Mage_Core_Model_Config_Element', $model->getNode()); } + /** + * @magentoAppIsolation enabled + */ public function testRemoveCache() { + Mage::app()->getCacheInstance()->allowUse('config'); + $model = $this->_createModel(); $model->removeCache(); $this->assertFalse($model->loadCache()); @@ -309,7 +328,7 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase { $model = $this->_createModel(); $this->assertFalse($model->getNode()); - $model->init(self::$_options); + $model->init(); $this->assertInstanceOf('Mage_Core_Model_Config_Element', $model->getNode()); $this->assertInstanceOf('Mage_Core_Model_Config_Element', $model->getNode(null, 'store', 1)); $this->assertInstanceOf('Mage_Core_Model_Config_Element', $model->getNode(null, 'website', 1)); @@ -317,8 +336,7 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase public function testSetNode() { - $model = $this->_createModel(); - $model->init(self::$_options); + $model = $this->_createModel(true); /* some existing node should be used */ $model->setNode('admin/routers/adminhtml/use', 'test'); $this->assertEquals('test', (string) $model->getNode('admin/routers/adminhtml/use')); @@ -344,26 +362,11 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase } } - public function testGetTempVarDir() - { - $this->assertTrue(is_dir($this->_createModel()->getTempVarDir())); - } - - public function testGetDistroServerVars() + public function testGetDistroBaseUrl() { $_SERVER['SCRIPT_NAME'] = __FILE__; $_SERVER['HTTP_HOST'] = 'example.com'; - $vars = $this->_createModel()->getDistroServerVars(); - $this->assertArrayHasKey('root_dir', $vars); - $this->assertArrayHasKey('app_dir', $vars); - $this->assertArrayHasKey('var_dir', $vars); - $this->assertArrayHasKey('base_url', $vars); - $this->assertEquals('http://example.com/', $vars['base_url']); - } - - public function testSubstDistroServerVars() - { - $this->assertEquals('http://localhost/', $this->_createModel()->substDistroServerVars('{{base_url}}')); + $this->assertEquals('http://example.com/', $this->_createModel()->getDistroBaseUrl()); } public function testGetModuleConfig() @@ -373,27 +376,6 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase $this->assertInstanceOf('Mage_Core_Model_Config_Element', $model->getModuleConfig('Mage_Core')); } - public function testGetVarDir() - { - $dir = $this->_createModel()->getVarDir(); - $this->assertTrue(is_dir($dir)); - $this->assertTrue(is_writable($dir)); - } - - public function testCreateDirIfNotExists() - { - $model = $this->_createModel(); - $dir = $model->getVarDir() . DIRECTORY_SEPARATOR . uniqid('dir'); - try { - $this->assertFalse(is_dir($dir)); - $this->assertTrue($model->createDirIfNotExists($dir)); - rmdir($dir); - } catch (Exception $e) { - rmdir($dir); - throw $e; - } - } - public function testGetModuleDir() { $model = $this->_createModel(true); @@ -531,17 +513,37 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase $this->assertObjectHasAttribute('password', $fieldset); } + /** + * Creates Mage_Core_Model_Config model with initialized Mage_Core_Model_App + * + * @param array $appOptions + * @param Magento_Test_ObjectManager $objectManager + * @return Mage_Core_Model_Config + */ + protected function _createModelWithApp(array $appOptions, Magento_Test_ObjectManager $objectManager = null) + { + $baseOptions = Magento_Test_Bootstrap::getInstance()->getInitParams(); + $appOptions = array_replace_recursive($baseOptions, $appOptions); + $objectManager = $objectManager ?: new Magento_Test_ObjectManager(); + /** @var $app Mage_Core_Model_App */ + $app = $objectManager->get('Mage_Core_Model_App'); + $app->init($appOptions); + return $objectManager->create('Mage_Core_Model_Config'); + } + /** * Instantiate Mage_Core_Model_Config and initialize (load configuration) if needed * * @param bool $initialize + * @param array $arguments * @return Mage_Core_Model_Config */ - protected function _createModel($initialize = false) + protected function _createModel($initialize = false, array $arguments = array()) { - $model = Mage::getModel('Mage_Core_Model_Config'); + /** @var $model Mage_Core_Model_Config */ + $model = Mage::getModel('Mage_Core_Model_Config', $arguments); if ($initialize) { - $model->init(self::$_options); + $model->init(); } return $model; } @@ -557,13 +559,12 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase /** * Check if areas loaded correctly from configuration - * - * @magentoAppIsolation enabled - * @magentoDataFixture Mage/Core/_files/load_configuration.php */ public function testGetAreas() { - $allowedAreas = Mage::app()->getConfig()->getAreas(); + $model = $this->_createModel(true, array('sourceData' => __DIR__ . '/../_files/etc/config.xml')); + + $allowedAreas = $model->getAreas(); $this->assertNotEmpty($allowedAreas, 'Areas are not initialized'); $this->assertArrayHasKey('test_area1', $allowedAreas, 'Test area #1 is not loaded'); @@ -590,13 +591,12 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase /** * Check if routers loaded correctly from configuration - * - * @magentoAppIsolation enabled - * @magentoDataFixture Mage/Core/_files/load_configuration.php */ public function testGetRouters() { - $loadedRouters = Mage::app()->getConfig()->getRouters(); + $model = $this->_createModel(true, array('sourceData' => __DIR__ . '/../_files/etc/config.xml')); + + $loadedRouters = $model->getRouters(); $this->assertArrayHasKey('test_router1', $loadedRouters, 'Test router #1 is not initialized in test area.'); $this->assertArrayHasKey('test_router2', $loadedRouters, 'Test router #2 is not initialized in test area.'); diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Design/FallbackTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Design/FallbackTest.php index 1b146602498..0970a81696f 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Design/FallbackTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Design/FallbackTest.php @@ -27,6 +27,53 @@ class Mage_Core_Model_Design_FallbackTest extends PHPUnit_Framework_TestCase { + /** + * @expectedException InvalidArgumentException + */ + public function testConstructException() + { + $dirs = new Mage_Core_Model_Dir(__DIR__); + Mage::getObjectManager()->create( + 'Mage_Core_Model_Design_Fallback', + array( + 'dirs' => $dirs, + 'params' => array() + ) + ); + } + + /** + * @covers Mage_Core_Model_Design_Fallback::getArea + * @covers Mage_Core_Model_Design_Fallback::getTheme + * @covers Mage_Core_Model_Design_Fallback::getLocale + */ + public function testGetters() + { + $theme = 't'; + $themeModel = $this->getMock('Mage_Core_Model_Theme', array('getThemeCode'), array(), '', false); + $themeModel->expects($this->any()) + ->method('getThemeCode') + ->will($this->returnValue($theme)); + + $dirs = new Mage_Core_Model_Dir(__DIR__); + $stub = array( + 'themeConfig' => 'stub', + 'area' => 'a', + 'themeModel' => $themeModel, + 'locale' => 'l', + ); + $model = Mage::getObjectManager()->create( + 'Mage_Core_Model_Design_Fallback', + array( + 'dirs' => $dirs, + 'params' => $stub + ) + ); + $this->assertEquals('a', $model->getArea()); + $this->assertEquals($theme, $model->getTheme()); + $this->assertEquals('l', $model->getLocale()); + } + /** * Build a model to test * @@ -37,15 +84,14 @@ class Mage_Core_Model_Design_FallbackTest extends PHPUnit_Framework_TestCase */ protected function _buildModel($area, $themePath, $locale) { - $testDir = implode(DS, array(dirname( __DIR__), '_files', 'fallback')); - Mage::getConfig()->getOptions()->addData(array( - 'js_dir' => implode(DS, array($testDir, 'pub', 'js')), - 'design_dir' => $testDir . DIRECTORY_SEPARATOR . 'design' - )); + // Prepare config with directories + $baseDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'fallback'; + $viewDir = $baseDir . DIRECTORY_SEPARATOR . 'design'; + $dirs = new Mage_Core_Model_Dir($baseDir, array(), array(Mage_Core_Model_Dir::THEMES => $viewDir)); /** @var $collection Mage_Core_Model_Theme_Collection */ $collection = Mage::getModel('Mage_Core_Model_Theme_Collection'); - $themeModel = $collection->setBaseDir($testDir . DIRECTORY_SEPARATOR . 'design') + $themeModel = $collection->setBaseDir($viewDir) ->addDefaultPattern() ->addFilter('theme_path', $themePath) ->addFilter('area', $area) @@ -58,7 +104,8 @@ class Mage_Core_Model_Design_FallbackTest extends PHPUnit_Framework_TestCase 'themeModel' => $themeModel, ); - return Mage::getObjectManager()->create('Mage_Core_Model_Design_Fallback', array('data' => $params)); + return Mage::getObjectManager()->create('Mage_Core_Model_Design_Fallback', + array('dirs' => $dirs, 'params' => $params)); } /** @@ -311,7 +358,7 @@ class Mage_Core_Model_Design_FallbackTest extends PHPUnit_Framework_TestCase ), 'lib file in js lib' => array( 'mage/script.js', 'frontend', 'package/custom_theme', - '%s/pub/js/mage/script.js', + '%s/pub/lib/mage/script.js', ), ); } diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageFallbackTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageFallbackTest.php index 66d9b67199d..09099bcc2ee 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageFallbackTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageFallbackTest.php @@ -27,25 +27,24 @@ /** * Tests for the view layer fallback mechanism - * - * @magentoDbIsolation enabled + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php */ class Mage_Core_Model_Design_PackageFallbackTest extends PHPUnit_Framework_TestCase { /** * @var Mage_Core_Model_Design_Package */ - protected $_model; + protected $_model = null; protected function setUp() { - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'design', - Mage::getModel('Mage_Core_Model_Design_Package') + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => dirname(__DIR__) . '/_files/design' + ) )); - $themeUtility->registerThemes()->setDesignTheme('test/default', 'frontend');; - $this->_model = $themeUtility->getDesign(); + $this->_model = new Mage_Core_Model_Design_Package(Mage::getObjectManager()->create('Magento_Filesystem')); + $this->_model->setDesignTheme('test/default'); } protected function tearDown() diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageMergingTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageMergingTest.php index e5eaf439f44..f3d9e53f360 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageMergingTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageMergingTest.php @@ -26,7 +26,7 @@ */ /** - * @magentoDbIsolation enabled + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php */ class Mage_Core_Model_Design_PackageMergingTest extends PHPUnit_Framework_TestCase { @@ -51,19 +51,20 @@ class Mage_Core_Model_Design_PackageMergingTest extends PHPUnit_Framework_TestCa public static function setUpBeforeClass() { - self::$_themePublicDir = Mage::app()->getConfig()->getOptions()->getMediaDir() . '/theme'; + self::$_themePublicDir = Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA) . '/theme'; self::$_viewPublicMergedDir = self::$_themePublicDir . '/_merged'; } protected function setUp() { - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'design', - Mage::getModel('Mage_Core_Model_Design_Package') + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => dirname(__DIR__) . '/_files/design' + ) )); - $themeUtility->registerThemes()->setDesignTheme('package/default', 'frontend'); - $this->_model = $themeUtility->getDesign(); + $filesystem = Mage::getObjectManager()->create('Magento_Filesystem'); + $this->_model = new Mage_Core_Model_Design_Package($filesystem); + $this->_model->setDesignTheme('package/default'); } protected function tearDown() @@ -94,7 +95,6 @@ class Mage_Core_Model_Design_PackageMergingTest extends PHPUnit_Framework_TestCa * @magentoConfigFixture current_store dev/css/merge_css_files 1 * @magentoConfigFixture current_store dev/js/merge_files 1 * @magentoConfigFixture current_store dev/static/sign 0 - * @magentoAppIsolation enabled */ public function testMergeFiles($contentType, $files, $expectedFilename, $related = array()) { @@ -122,7 +122,6 @@ class Mage_Core_Model_Design_PackageMergingTest extends PHPUnit_Framework_TestCa * @magentoConfigFixture current_store dev/css/merge_css_files 1 * @magentoConfigFixture current_store dev/js/merge_files 1 * @magentoConfigFixture current_store dev/static/sign 1 - * @magentoAppIsolation enabled */ public function testMergeFilesSigned($contentType, $files, $expectedFilename, $related = array()) { @@ -189,7 +188,6 @@ class Mage_Core_Model_Design_PackageMergingTest extends PHPUnit_Framework_TestCa /** * @magentoConfigFixture current_store dev/js/merge_files 1 - * @magentoAppIsolation enabled */ public function testMergeFilesModification() { @@ -209,7 +207,6 @@ class Mage_Core_Model_Design_PackageMergingTest extends PHPUnit_Framework_TestCa /** * @magentoConfigFixture current_store dev/js/merge_files 1 - * @magentoAppIsolation enabled */ public function testCleanMergedJsCss() { diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackagePublicationTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackagePublicationTest.php index 47c25d82fff..d3ac6c4df5b 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackagePublicationTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackagePublicationTest.php @@ -25,62 +25,35 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -/** - * @magentoDbIsolation enabled - */ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_TestCase { - /** - * Path to the public directory for view files - * - * @var string - */ - protected static $_themePublicDir; - - /** - * Path for temporary fixture files. Used to test publishing changed files. - * - * @var string - */ - protected static $_fixtureTmpDir; - /** * @var Mage_Core_Model_Design_Package */ protected $_model; - public static function setUpBeforeClass() - { - self::$_themePublicDir = Mage::app()->getConfig()->getOptions()->getMediaDir() . '/theme'; - self::$_fixtureTmpDir = Magento_Test_Bootstrap::getInstance()->getTmpDir() . '/publication'; - } - protected function setUp() { - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'design', - Mage::getModel('Mage_Core_Model_Design_Package') - )); - $themeUtility->registerThemes()->setDesignTheme('test/default', 'frontend'); - $this->_model = $themeUtility->getDesign(); + $this->_model = Mage::getModel('Mage_Core_Model_Design_Package'); } protected function tearDown() { $filesystem = Mage::getObjectManager()->create('Magento_Filesystem'); - $filesystem->delete(self::$_fixtureTmpDir); - $filesystem->delete(self::$_themePublicDir . '/adminhtml'); - $filesystem->delete(self::$_themePublicDir . '/frontend'); + $publicDir = $this->_model->getPublicDir(); + $filesystem->delete($publicDir . '/adminhtml'); + $filesystem->delete($publicDir . '/frontend'); } /** * @magentoAppIsolation enabled */ - public function testGetPublicThemeDir() + public function testGetPublicDir() { - Mage::app()->getConfig()->getOptions()->setMediaDir(__DIR__); - $this->assertEquals(__DIR__ . DIRECTORY_SEPARATOR . 'theme', $this->_model->getPublicDir()); + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = Mage::getObjectManager()->get('Mage_Core_Model_Dir'); + $expectedPublicDir = $dirs->getDir(Mage_Core_Model_Dir::MEDIA) . DIRECTORY_SEPARATOR . 'theme'; + $this->assertEquals($expectedPublicDir, $this->_model->getPublicDir()); } /** @@ -92,6 +65,8 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te */ protected function _testGetViewUrl($file, $expectedUrl, $locale = null) { + $this->_initTestTheme(); + Mage::app()->getLocale()->setLocale($locale); $url = $this->_model->getViewFileUrl($file); $this->assertStringEndsWith($expectedUrl, $url); @@ -100,7 +75,9 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te } /** - * @magentoConfigFixture default/design/theme/allow_view_files_duplication 1 + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoConfigFixture global/design/theme/allow_view_files_duplication 1 + * @magentoAppIsolation enabled * @dataProvider getViewUrlFilesDuplicationDataProvider */ public function testGetViewUrlFilesDuplication($file, $expectedUrl, $locale = null) @@ -139,7 +116,9 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te } /** - * @magentoConfigFixture default/design/theme/allow_view_files_duplication 0 + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoConfigFixture global/design/theme/allow_view_files_duplication 0 + * @magentoAppIsolation enabled * @dataProvider testGetViewUrlNoFilesDuplicationDataProvider */ public function testGetViewUrlNoFilesDuplication($file, $expectedUrl, $locale = null) @@ -170,10 +149,14 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te } /** - * @magentoConfigFixture default/design/theme/allow_view_files_duplication 0 + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoConfigFixture global/design/theme/allow_view_files_duplication 0 + * @magentoAppIsolation enabled */ public function testGetViewUrlNoFilesDuplicationWithCaching() { + $this->_initTestTheme(); + $this->_model->setDesignTheme('test/default'); Mage::app()->getLocale()->setLocale('en_US'); $theme = $this->_model->getDesignTheme(); $themeDesignParams = array('themeModel' => $theme); @@ -218,12 +201,16 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te * Test on vulnerability for protected files * * @expectedException Magento_Exception + * @expectedExceptionMessage because it does not reside in a public directory + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoAppIsolation enabled * @dataProvider getProtectedFiles * @param array $designParams * @param string $filePath */ public function testTemplatePublicationVulnerability($designParams, $filePath) { + $this->_initTestTheme(); $this->_model->getViewFileUrl($filePath, $designParams); } @@ -261,12 +248,15 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te * @param string $file * @param $designParams * @param string $expectedFile + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoAppIsolation enabled * @dataProvider publishViewFileDataProvider */ public function testPublishViewFile($file, $designParams, $expectedFile) { - $expectedFile = self::$_themePublicDir . '/' . $expectedFile; - $this->_deleteFiles[] = $expectedFile; + $this->_initTestTheme(); + + $expectedFile = $this->_model->getPublicDir() . '/' . $expectedFile; // test doesn't make sense if the original file doesn't exist or the target file already exists $originalFile = $this->_model->getViewFile($file, $designParams); @@ -310,9 +300,12 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te /** * Publication of CSS files located in the theme (development mode) + * @magentoAppIsolation enabled + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php */ public function testPublishCssFileFromTheme() { + $this->_initTestTheme(); $expectedFiles = array( 'css/file.css', 'recursive.css', @@ -326,7 +319,7 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te 'Namespace_Module/absolute_valid_module.gif', 'Mage_Page/favicon.ico', // non-fixture file from real module ); - $publishedDir = self::$_themePublicDir . '/frontend/package/default/en_US'; + $publishedDir = $this->_model->getPublicDir() . '/frontend/package/default/en_US'; $this->assertFileNotExists($publishedDir, 'Please verify isolation from previous test(s).'); $this->_model->getViewFileUrl('css/file.css', array( 'package' => 'package', @@ -341,6 +334,8 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te /** * Publication of CSS files located in the module + * + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php * @dataProvider publishCssFileFromModuleDataProvider */ public function testPublishCssFileFromModule( @@ -348,7 +343,7 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te ) { $this->_model->getViewFileUrl($cssViewFile, $designParams); - $expectedCssFile = self::$_themePublicDir . '/' . $expectedCssFile; + $expectedCssFile = $this->_model->getPublicDir() . '/' . $expectedCssFile; $this->assertFileExists($expectedCssFile); $actualCssContent = file_get_contents($expectedCssFile); @@ -363,7 +358,7 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te } foreach ($expectedRelatedFiles as $expectedFile) { - $expectedFile = self::$_themePublicDir . '/' . $expectedFile; + $expectedFile = $this->_model->getPublicDir() . '/' . $expectedFile; $this->assertFileExists($expectedFile); } } @@ -413,6 +408,9 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te /** * Test that modified CSS file and changed resources are re-published in developer mode + * + * @magentoAppIsolation enabled + * @magentoDataFixture Mage/Core/_files/media_for_change.php */ public function testPublishResourcesAndCssWhenChangedCssDevMode() { @@ -424,6 +422,9 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te /** * Test that modified CSS file and changed resources are not re-published in usual mode + * + * @magentoAppIsolation enabled + * @magentoDataFixture Mage/Core/_files/media_for_change.php */ public function testNotPublishResourcesAndCssWhenChangedCssUsualMode() { @@ -440,11 +441,17 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te */ protected function _testPublishResourcesAndCssWhenChangedCss($expectedPublished) { - $fixtureViewPath = self::$_fixtureTmpDir . '/frontend/test/default/'; - $publishedPath = self::$_themePublicDir . '/frontend/test/default/en_US/'; + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => + Magento_Test_Bootstrap::getInstance()->getInstallDir() . '/media_for_change' + ) + )); + $this->_model->setDesignTheme('test/default'); + $themePath = $this->_model->getDesignTheme()->getFullPath(); + $fixtureViewPath = Magento_Test_Bootstrap::getInstance()->getInstallDir() . "/media_for_change/$themePath/"; + $publishedPath = $this->_model->getPublicDir() . "/$themePath/en_US/"; - // Prepare temporary fixture directory and publish files from it - $this->_copyFixtureViewToTmpDir($fixtureViewPath); $this->_model->getViewFileUrl('style.css', array('locale' => 'en_US')); // Change main file and referenced files - everything changed and referenced must appear @@ -472,9 +479,10 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te } } - /** * Test changed resources, referenced in non-modified CSS file, are re-published + * + * @magentoDataFixture Mage/Core/_files/media_for_change.php * @magentoAppIsolation enabled */ public function testPublishChangedResourcesWhenUnchangedCssDevMode() @@ -488,6 +496,8 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te /** * Test changed resources, referenced in non-modified CSS file, are re-published + * + * @magentoDataFixture Mage/Core/_files/media_for_change.php * @magentoAppIsolation enabled */ public function testNotPublishChangedResourcesWhenUnchangedCssUsualMode() @@ -506,11 +516,17 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te */ protected function _testPublishChangedResourcesWhenUnchangedCss($expectedPublished) { - $fixtureViewPath = self::$_fixtureTmpDir . '/frontend/test/default/'; - $publishedPath = self::$_themePublicDir . '/frontend/test/default/en_US/'; + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => + Magento_Test_Bootstrap::getInstance()->getInstallDir() . '/media_for_change' + ) + )); + $this->_model->setDesignTheme('test/default'); + $themePath = $this->_model->getDesignTheme()->getFullPath(); + $fixtureViewPath = Magento_Test_Bootstrap::getInstance()->getInstallDir() . "/media_for_change/$themePath/"; + $publishedPath = $this->_model->getPublicDir() . "/$themePath/en_US/"; - // Prepare temporary fixture directory and publish files from it - $this->_copyFixtureViewToTmpDir($fixtureViewPath); $this->_model->getViewFileUrl('style.css', array('locale' => 'en_US')); // Change referenced files @@ -530,22 +546,16 @@ class Mage_Core_Model_Design_PackagePublicationTest extends PHPUnit_Framework_Te } /** - * Prepare design directory with initial css and resources - * - * @param string $fixtureViewPath + * Init the model with a test theme from fixture themes dir + * Init application with custom view dir, @magentoAppIsolation required */ - protected function _copyFixtureViewToTmpDir($fixtureViewPath) + protected function _initTestTheme() { - Mage::app()->getConfig()->getOptions()->setDesignDir(self::$_fixtureTmpDir); - mkdir($fixtureViewPath . '/images', 0777, true); - - // Copy all files to fixture location - $mTime = time() - 10; // To ensure that all files, changed later in test, will be recognized for publication - $sourcePath = dirname(__DIR__) . '/_files/design/frontend/test/publication/'; - $files = array('theme.xml', 'style.css', 'sub.css', 'images/square.gif', 'images/rectangle.gif'); - foreach ($files as $file) { - copy($sourcePath . $file, $fixtureViewPath . $file); - touch($fixtureViewPath . $file, $mTime); - } + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => dirname(__DIR__) . '/_files/design/' + ) + )); + $this->_model->setDesignTheme('test/default'); } } diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageTest.php index 4942ea526c7..a910db073eb 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Design/PackageTest.php @@ -26,7 +26,7 @@ */ /** - * @magentoDbIsolation enabled + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php */ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase { @@ -35,39 +35,29 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase */ protected $_model; - protected static $_developerMode; - public static function setUpBeforeClass() { - $mediaDir = Mage::app()->getConfig()->getOptions()->getMediaDir(); + $themeDir = Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA) . 'theme'; $filesystem = Mage::getObjectManager()->create('Magento_Filesystem'); - $filesystem->delete($mediaDir . '/theme/frontend'); - $filesystem->delete($mediaDir . '/theme/_merged'); + $filesystem->delete($themeDir . '/frontend'); + $filesystem->delete($themeDir . '/_merged'); $ioAdapter = new Varien_Io_File(); $ioAdapter->cp( - Mage::app()->getConfig()->getOptions()->getJsDir() . '/prototype/prototype.js', - Mage::app()->getConfig()->getOptions()->getJsDir() . '/prototype/prototype.min.js' + Mage::getBaseDir(Mage_Core_Model_Dir::PUB_LIB) . '/prototype/prototype.js', + Mage::getBaseDir(Mage_Core_Model_Dir::PUB_LIB) . '/prototype/prototype.min.js' ); - self::$_developerMode = Mage::getIsDeveloperMode(); } public static function tearDownAfterClass() { $ioAdapter = new Varien_Io_File(); - $ioAdapter->rm(Mage::app()->getConfig()->getOptions()->getJsDir() . '/prototype/prototype.min.js'); - Mage::setIsDeveloperMode(self::$_developerMode); + $ioAdapter->rm(Mage::getBaseDir(Mage_Core_Model_Dir::PUB_LIB) . '/prototype/prototype.min.js'); } protected function setUp() { - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'design', - Mage::getModel('Mage_Core_Model_Design_Package') - )); - $themeUtility->registerThemes()->setDesignTheme('test/default', 'frontend'); - $this->_model = $themeUtility->getDesign(); + $this->_model = new Mage_Core_Model_Design_Package(Mage::getObjectManager()->create('Magento_Filesystem')); } protected function tearDown() @@ -75,6 +65,21 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase $this->_model = null; } + /** + * Emulate fixture design theme + * + * @param string $themePath + */ + protected function _emulateFixtureTheme($themePath = 'test/default') + { + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => realpath(__DIR__ . '/../_files/design'), + ), + )); + $this->_model->setDesignTheme($themePath); + } + public function testSetGetArea() { $this->assertEquals(Mage_Core_Model_Design_Package::DEFAULT_AREA, $this->_model->getArea()); @@ -82,11 +87,6 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase $this->assertEquals('test', $this->_model->getArea()); } - public function testGetTheme() - { - $this->assertEquals('test/default', $this->_model->getDesignTheme()->getThemePath()); - } - public function testSetDesignTheme() { $this->_model->setDesignTheme('test/test', 'test'); @@ -99,11 +99,48 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase $this->assertInstanceOf('Mage_Core_Model_Theme', $this->_model->getDesignTheme()); } + /** + * @magentoConfigFixture frontend/design/theme/full_name f + * @magentoConfigFixture install/design/theme/full_name i + * @magentoConfigFixture adminhtml/design/theme/full_name b + * @magentoConfigFixture current_store design/theme/theme_id 0 + */ + public function testGetConfigurationDesignThemeDefaults() + { + $this->assertEquals('f', $this->_model->getConfigurationDesignTheme()); + $this->assertEquals('f', $this->_model->getConfigurationDesignTheme('frontend')); + $this->assertEquals('f', $this->_model->getConfigurationDesignTheme('frontend', array('store' => 0))); + $this->assertEquals('f', $this->_model->getConfigurationDesignTheme('frontend', array('store' => null))); + $this->assertEquals('i', $this->_model->getConfigurationDesignTheme('install')); + $this->assertEquals('i', $this->_model->getConfigurationDesignTheme('install', array('store' => uniqid()))); + $this->assertEquals('b', $this->_model->getConfigurationDesignTheme('adminhtml')); + $this->assertEquals('b', $this->_model->getConfigurationDesignTheme('adminhtml', array('store' => uniqid()))); + } + + /** + * @magentoConfigFixture current_store design/theme/theme_id one + * @magentoConfigFixture fixturestore_store design/theme/theme_id two + * @magentoDataFixture Mage/Core/_files/store.php + */ + public function testGetConfigurationDesignThemeStore() + { + $storeId = Mage::app()->getStore()->getId(); + $this->assertEquals('one', $this->_model->getConfigurationDesignTheme()); + $this->assertEquals('one', $this->_model->getConfigurationDesignTheme(null, array('store' => $storeId))); + $this->assertEquals('one', $this->_model->getConfigurationDesignTheme('frontend', array('store' => $storeId))); + $this->assertEquals('two', $this->_model->getConfigurationDesignTheme(null, array('store' => 'fixturestore'))); + $this->assertEquals('two', $this->_model->getConfigurationDesignTheme( + 'frontend', array('store' => 'fixturestore') + )); + } + /** * @dataProvider getFilenameDataProvider + * @magentoAppIsolation enabled */ public function testGetFilename($file, $params) { + $this->_emulateFixtureTheme(); $this->assertFileExists($this->_model->getFilename($file, $params)); } @@ -141,8 +178,12 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase ); } + /** + * @magentoAppIsolation enabled + */ public function testGetOptimalCssUrls() { + $this->_emulateFixtureTheme(); $expected = array( 'http://localhost/pub/media/theme/frontend/test/default/en_US/css/styles.css', 'http://localhost/pub/lib/mage/translate-inline.css', @@ -159,9 +200,11 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase * @param array $expectedFiles * @dataProvider getOptimalCssUrlsMergedDataProvider * @magentoConfigFixture current_store dev/css/merge_css_files 1 + * @magentoAppIsolation enabled */ public function testGetOptimalCssUrlsMerged($files, $expectedFiles) { + $this->_emulateFixtureTheme(); $this->assertEquals($expectedFiles, $this->_model->getOptimalCssUrls($files)); } @@ -179,9 +222,12 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase ); } - + /** + * @magentoAppIsolation enabled + */ public function testGetOptimalJsUrls() { + $this->_emulateFixtureTheme(); $expected = array( 'http://localhost/pub/media/theme/frontend/test/default/en_US/js/tabs.js', 'http://localhost/pub/lib/jquery/jquery-ui-timepicker-addon.js', @@ -200,9 +246,11 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase * @param array $expectedFiles * @dataProvider getOptimalJsUrlsMergedDataProvider * @magentoConfigFixture current_store dev/js/merge_files 1 + * @magentoAppIsolation enabled */ public function testGetOptimalJsUrlsMerged($files, $expectedFiles) { + $this->_emulateFixtureTheme(); $this->assertEquals($expectedFiles, $this->_model->getOptimalJsUrls($files)); } @@ -220,32 +268,43 @@ class Mage_Core_Model_Design_PackageTest extends PHPUnit_Framework_TestCase ); } + /** + * @magentoAppIsolation enabled + */ public function testGetViewConfig() { + $this->_emulateFixtureTheme(); $config = $this->_model->getViewConfig(); $this->assertInstanceOf('Magento_Config_View', $config); $this->assertEquals(array('var1' => 'value1', 'var2' => 'value2'), $config->getVars('Namespace_Module')); } /** + * @param bool $devMode * @param string $file * @param string $result - * @covers Mage_Core_Model_Design_Package::getViewUrl + * * @dataProvider getViewUrlDataProvider + * * @magentoConfigFixture current_store dev/static/sign 0 + * @magentoAppIsolation enabled */ public function testGetViewUrl($devMode, $file, $result) { + $this->_emulateFixtureTheme(); Mage::setIsDeveloperMode($devMode); $this->assertEquals($this->_model->getViewFileUrl($file), $result); } /** + * @param bool $devMode * @param string $file * @param string $result - * @covers Mage_Core_Model_Design_Package::getSkinUrl + * * @dataProvider getViewUrlDataProvider + * * @magentoConfigFixture current_store dev/static/sign 1 + * @magentoAppIsolation enabled */ public function testGetViewUrlSigned($devMode, $file, $result) { diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Email/Template/FilterTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Email/Template/FilterTest.php index a3722622e66..950d5ff288e 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Email/Template/FilterTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Email/Template/FilterTest.php @@ -44,8 +44,6 @@ class Mage_Core_Model_Email_Template_FilterTest extends PHPUnit_Framework_TestCa /** * Isolation level has been raised in order to flush themes configuration in-memory cache - * - * @magentoAppIsolation enabled */ public function testViewDirective() { @@ -102,27 +100,35 @@ class Mage_Core_Model_Email_Template_FilterTest extends PHPUnit_Framework_TestCa } /** - * @magentoDbIsolation enabled - * @magentoAppIsolation enabled - * @magentoConfigFixture default_store design/theme/full_name test/default + * @magentoDataFixture Mage/Core/Model/Email/_files/themes.php * @magentoConfigFixture adminhtml/design/theme/full_name test/default + * @magentoAppIsolation enabled * @dataProvider layoutDirectiveDataProvider * - * @param string $currentArea + * @param string $area * @param string $directiveParams * @param string $expectedOutput */ - public function testLayoutDirective($currentArea, $directiveParams, $expectedOutput) + public function testLayoutDirective($area, $directiveParams, $expectedOutput) { - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'design' + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => dirname(__DIR__) . '/_files/design' + ) )); - $themeUtility->registerThemes() - ->setDesignTheme('test/default', 'frontend') - ->setDesignTheme('test/default', 'adminhtml'); - $this->_emulateCurrentArea($currentArea); + $collection = new Mage_Core_Model_Resource_Theme_Collection; + $themeId = $collection->getThemeByFullPath('frontend/test/default')->getId(); + Mage::app()->getStore()->setConfig(Mage_Core_Model_Design_Package::XML_PATH_THEME_ID, $themeId); + + /** @var $layout Mage_Core_Model_Layout */ + $objectManager = Mage::getObjectManager(); + $layout = Mage::getObjectManager()->create('Mage_Core_Model_Layout', array('area' => $area)); + $objectManager->addSharedInstance($layout, 'Mage_Core_Model_Layout'); + $this->assertEquals($area, $layout->getArea()); + $this->assertEquals($area, Mage::app()->getLayout()->getArea()); + Mage::getDesign()->setDesignTheme('test/default'); + $actualOutput = $this->_model->layoutDirective(array( '{{layout ' . $directiveParams . '}}', 'layout', @@ -161,18 +167,4 @@ class Mage_Core_Model_Email_Template_FilterTest extends PHPUnit_Framework_TestCa ); return $result; } - - /** - * Emulate the current application area - * - * @param string $area - */ - protected function _emulateCurrentArea($area) - { - /** @var $layoutFactory Mage_Core_Model_Layout_Factory */ - $layoutFactory = Mage::getObjectManager()->get('Mage_Core_Model_Layout_Factory'); - $layout = $layoutFactory->createLayout(array('area' => $area)); - $this->assertEquals($area, $layout->getArea()); - $this->assertEquals($area, Mage::app()->getLayout()->getArea()); - } } diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Email/TemplateTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Email/TemplateTest.php index ababfcca6e8..1cbede5ed7b 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Email/TemplateTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Email/TemplateTest.php @@ -39,8 +39,6 @@ class Mage_Core_Model_Email_TemplateTest extends PHPUnit_Framework_TestCase protected function setUp() { - Mage_Core_Utility_Theme::registerDesignMock(); - Mage::getDesign()->setDefaultDesignTheme(); $this->_mail = $this->getMock( 'Zend_Mail', array('send', 'addTo', 'addBcc', 'setReturnPath', 'setReplyTo'), array('utf-8') ); @@ -83,14 +81,8 @@ class Mage_Core_Model_Email_TemplateTest extends PHPUnit_Framework_TestCase $this->assertSame($filter, $this->_model->getTemplateFilter()); } - /** - * @magentoAppIsolation enabled - */ public function testLoadDefault() { - Mage::app()->getConfig()->getOptions() - ->setLocaleDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'locale'); - $this->_model->loadDefault('customer_create_account_email_template'); $this->assertNotEmpty($this->_model->getTemplateText()); $this->assertNotEmpty($this->_model->getTemplateSubject()); @@ -114,12 +106,11 @@ class Mage_Core_Model_Email_TemplateTest extends PHPUnit_Framework_TestCase /** * @magentoAppIsolation enabled * @magentoDataFixture Mage/Core/_files/store.php - * @magentoConfigFixture fixturestore_store design/theme/full_name test/default - * @magentoDataFixture Mage/Core/Model/Email/_files/theme_registration.php */ public function testGetProcessedTemplate() { - $expectedViewUrl = 'theme/frontend/test/default/en_US/Mage_Page/favicon.ico'; + $this->_setBlueThemeForFixtureStore(); + $expectedViewUrl = 'theme/frontend/default/demo_blue/en_US/Mage_Page/favicon.ico'; $this->_model->setTemplateText('{{view url="Mage_Page::favicon.ico"}}'); $this->assertStringEndsNotWith($expectedViewUrl, $this->_model->getProcessedTemplate()); $this->_model->setDesignConfig(array( @@ -128,6 +119,18 @@ class Mage_Core_Model_Email_TemplateTest extends PHPUnit_Framework_TestCase $this->assertStringEndsWith($expectedViewUrl, $this->_model->getProcessedTemplate()); } + /** + * Set 'default/demo_blue' for the 'fixturestore' store. + * Application isolation is required, if a test uses this method. + */ + protected function _setBlueThemeForFixtureStore() + { + $theme = Mage::getModel('Mage_Core_Model_Theme'); + $theme->load('default/demo_blue', 'theme_path'); + Mage::app()->getStore('fixturestore') + ->setConfig(Mage_Core_Model_Design_Package::XML_PATH_THEME_ID, $theme->getId()); + } + /** * @magentoAppIsolation enabled * @magentoDataFixture Mage/Core/_files/design_change.php @@ -144,12 +147,11 @@ class Mage_Core_Model_Email_TemplateTest extends PHPUnit_Framework_TestCase /** * @magentoAppIsolation enabled * @magentoDataFixture Mage/Core/_files/store.php - * @magentoConfigFixture fixturestore_store design/theme/full_name test/default - * @magentoDataFixture Mage/Core/Model/Email/_files/theme_registration.php */ public function testGetProcessedTemplateSubject() { - $expectedViewUrl = 'theme/frontend/test/default/en_US/Mage_Page/favicon.ico'; + $this->_setBlueThemeForFixtureStore(); + $expectedViewUrl = 'theme/frontend/default/demo_blue/en_US/Mage_Page/favicon.ico'; $this->_model->setTemplateSubject('{{view url="Mage_Page::favicon.ico"}}'); $this->assertStringEndsNotWith($expectedViewUrl, $this->_model->getProcessedTemplateSubject(array())); $this->_model->setDesignConfig(array( diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Email/_files/themes.php b/dev/tests/integration/testsuite/Mage/Core/Model/Email/_files/themes.php new file mode 100644 index 00000000000..bfcc7910940 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Email/_files/themes.php @@ -0,0 +1,29 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** @var $registration Mage_Core_Model_Theme_Registration */ +$registration = Mage::getModel('Mage_Core_Model_Theme_Registration'); +$registration->register( + __DIR__ . DIRECTORY_SEPARATOR . 'design', + implode(DIRECTORY_SEPARATOR, array('*','*', '*', 'theme.xml')) +); diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Layout/MergeTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Layout/MergeTest.php index 8f8c2df0b04..004485100ef 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Layout/MergeTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Layout/MergeTest.php @@ -25,9 +25,6 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -/** - * @magentoDbIsolation enabled - */ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase { /** @@ -35,21 +32,18 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase */ protected $_model; - /** - * @var Mage_Core_Utility_Theme - */ - protected $_themeUtility; - protected function setUp() { - $this->_themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__DIR__) . '/_files/design', - Mage::getDesign() - )); - $this->_themeUtility->registerThemes()->setDesignTheme('test/default', 'frontend'); - /* Disable loading and saving layout cache */ Mage::app()->getCacheInstance()->banUse('layout'); + + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => dirname(__DIR__) . '/_files/design' + ) + )); + Mage::getDesign()->setDesignTheme('test/default'); + $this->_model = Mage::getModel('Mage_Core_Model_Layout_Merge', array( 'arguments' => array('area' => 'frontend', 'theme' => Mage::getDesign()->getDesignTheme()->getId()) )); @@ -152,6 +146,9 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase /** * Test that, regarding of the current area, page types hierarchy getter retrieves the front-end page types + * + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoAppIsolation enabled * @throws Exception */ public function testGetPageHandlesHierarchyFromBackend() @@ -159,21 +156,16 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase $area = Mage::getDesign()->getArea(); $this->assertEquals('frontend', $area, 'Test assumes that front-end is the current area.'); - /* use new instance to ensure that in-memory caching, if any, won't affect test results */ /** @var $model Mage_Core_Model_Layout_Merge */ $model = Mage::getModel('Mage_Core_Model_Layout_Merge'); $frontendPageTypes = $model->getPageHandlesHierarchy(); $this->assertNotEmpty($frontendPageTypes); + /* use new instance to ensure that in-memory caching, if any, won't affect test results */ + $model = Mage::getModel('Mage_Core_Model_Layout_Merge'); Mage::getDesign()->setArea('adminhtml'); - try { - $backendPageTypes = $this->_model->getPageHandlesHierarchy(); - $this->assertSame($frontendPageTypes, $backendPageTypes); - } catch (Exception $e) { - Mage::getDesign()->setArea($area); - throw $e; - } - Mage::getDesign()->setArea($area); + $backendPageTypes = $model->getPageHandlesHierarchy(); + $this->assertSame($frontendPageTypes, $backendPageTypes); } /** @@ -215,16 +207,18 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase } /** + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php * @magentoAppIsolation enabled */ public function testLoad() { + $collection = new Mage_Core_Model_Resource_Theme_Collection; $layoutHandle = 'layout_test_handle'; $expectedText = 'Text declared in the frontend/test/test_theme'; /** @var $model Mage_Core_Model_Layout_Merge */ $model = Mage::getModel('Mage_Core_Model_Layout_Merge', array('arguments' => array( - 'area' => 'frontend', - 'theme' => $this->_themeUtility->getThemeByParams('test/test_theme', 'frontend')->getId() + 'area' => 'frontend', + 'theme' => $collection->getThemeByFullPath('frontend/test/test_theme')->getId() ))); $this->assertNotContains($layoutHandle, $model->getHandles()); $this->assertNotContains($expectedText, $model->asString()); @@ -234,6 +228,7 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase } /** + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php * @magentoAppIsolation enabled */ public function testLoadCache() @@ -244,23 +239,29 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase $expectedTextThemeOne = 'Text declared in the frontend/test/test_theme'; $expectedTextThemeTwo = 'Text declared in the frontend/test/cache_test_theme'; + $collection = new Mage_Core_Model_Resource_Theme_Collection; $model = Mage::getModel('Mage_Core_Model_Layout_Merge', array('arguments' => array( 'area' => 'frontend', - 'theme' => $this->_themeUtility->getThemeByParams('test/test_theme', 'frontend')->getId() + 'theme' => $collection->getThemeByFullPath('frontend/test/test_theme')->getId() ))); $model->load($layoutHandle); $this->assertContains($expectedTextThemeOne, $model->asString()); $this->assertNotContains($expectedTextThemeTwo, $model->asString()); + $collection = new Mage_Core_Model_Resource_Theme_Collection; $model = Mage::getModel('Mage_Core_Model_Layout_Merge', array('arguments' => array( 'area' => 'frontend', - 'theme' => $this->_themeUtility->getThemeByParams('test/cache_test_theme', 'frontend')->getId() + 'theme' => $collection->getThemeByFullPath('frontend/test/cache_test_theme')->getId() ))); $model->load($layoutHandle); $this->assertContains($expectedTextThemeTwo, $model->asString()); $this->assertNotContains($expectedTextThemeOne, $model->asString()); } + /** + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoAppIsolation enabled + */ public function testFetchDbLayoutUpdates() { $update = '<reference name="root"><block type="Mage_Core_Block_Template" template="dummy.phtml"/></reference>'; @@ -280,6 +281,10 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase ); } + /** + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoAppIsolation enabled + */ public function testGetFileLayoutUpdatesXmlFromTheme() { $this->_replaceConfigLayoutUpdates(' @@ -383,6 +388,8 @@ class Mage_Core_Model_Layout_MergeTest extends PHPUnit_Framework_TestCase /** * @magentoConfigFixture current_store advanced/modules_disable_output/Mage_Catalog true * @magentoConfigFixture current_store advanced/modules_disable_output/Mage_Page true + * @magentoDataFixture Mage/Core/Model/_files/design/themes.php + * @magentoAppIsolation enabled */ public function testGetFileLayoutUpdatesXmlDisabledOutput() { diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/LayoutArgumentTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/LayoutArgumentTest.php deleted file mode 100644 index 4472b384276..00000000000 --- a/dev/tests/integration/testsuite/Mage/Core/Model/LayoutArgumentTest.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Mage_Core - * @subpackage integration_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -/** - * Layout integration tests - * - * @magentoDbIsolation enabled - */ -class Mage_Core_Model_LayoutArgumentTest extends Mage_Core_Model_LayoutTestBase -{ - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - */ - public function testLayoutArgumentsDirective() - { - $this->_layout->getUpdate()->load(array('layout_test_handle_arguments')); - $this->_layout->generateXml()->generateElements(); - $this->assertEquals('1', $this->_layout->getBlock('block_with_args')->getOne()); - $this->assertEquals('two', $this->_layout->getBlock('block_with_args')->getTwo()); - $this->assertEquals('3', $this->_layout->getBlock('block_with_args')->getThree()); - } - - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - */ - public function testLayoutArgumentsDirectiveIfComplexValues() - { - $this->_layout->getUpdate()->load(array('layout_test_handle_arguments_complex_values')); - $this->_layout->generateXml()->generateElements(); - - $this->assertEquals(array('parameters' => array('first' => '1', 'second' => '2')), - $this->_layout->getBlock('block_with_args_complex_values')->getOne()); - - $this->assertEquals('two', $this->_layout->getBlock('block_with_args_complex_values')->getTwo()); - - $this->assertEquals(array('extra' => array('key1' => 'value1', 'key2' => 'value2')), - $this->_layout->getBlock('block_with_args_complex_values')->getThree()); - } - - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - */ - public function testLayoutObjectArgumentsDirective() - { - $this->_layout->getUpdate()->load(array('layout_test_handle_arguments_object_type')); - $this->_layout->generateXml()->generateElements(); - $this->assertInstanceOf('Mage_Core_Block_Text', $this->_layout->getBlock('block_with_object_args')->getOne()); - $this->assertInstanceOf('Mage_Core_Block_Messages', - $this->_layout->getBlock('block_with_object_args')->getTwo() - ); - $this->assertEquals(3, $this->_layout->getBlock('block_with_object_args')->getThree()); - } - - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - */ - public function testLayoutUrlArgumentsDirective() - { - $this->_layout->getUpdate()->load(array('layout_test_handle_arguments_url_type')); - $this->_layout->generateXml()->generateElements(); - $this->assertContains('customer/account/login', $this->_layout->getBlock('block_with_url_args')->getOne()); - $this->assertContains('customer/account/logout', $this->_layout->getBlock('block_with_url_args')->getTwo()); - $this->assertContains('customer_id/3', $this->_layout->getBlock('block_with_url_args')->getTwo()); - } - - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - */ - public function testLayoutObjectArgumentUpdatersDirective() - { - $this->_layout->getUpdate()->load(array('layout_test_handle_arguments_object_type_updaters')); - $this->_layout->generateXml()->generateElements(); - - $expectedObjectData = array( - 0 => 'updater call', - 1 => 'updater call', - 2 => 'updater call', - ); - - $expectedSimpleData = 2; - - $block = $this->_layout->getBlock('block_with_object_updater_args')->getOne(); - $this->assertInstanceOf('Mage_Core_Block_Text', $block); - $this->assertEquals($expectedObjectData, $block->getUpdaterCall()); - $this->assertEquals($expectedSimpleData, $this->_layout->getBlock('block_with_object_updater_args')->getTwo()); - } -} diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/LayoutDirectivesTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/LayoutDirectivesTest.php new file mode 100644 index 00000000000..dd484b1a97d --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/LayoutDirectivesTest.php @@ -0,0 +1,241 @@ +<?php +/** + * Set of tests of layout directives handling behavior + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Core_Model_LayoutDirectivesTest extends PHPUnit_Framework_TestCase +{ + /** + * Test scheduled operations in the rendering of elements + * + * Expected behavior: + * 1) block1 was not declared at the moment when "1" invocation declared. The operation is scheduled + * 2) block1 creation directive schedules adding "2" as well + * 3) block2 is generated with "3" + * 4) yet another action schedules replacing value of block2 into "4" + * 5) when entire layout is read, all scheduled operations are executed in the same order as declared + * (blocks are instantiated first, of course) + * The end result can be observed in container1 + */ + public function testRenderElement() + { + $layout = $this->_getLayoutModel('render.xml'); + $this->assertEmpty($layout->renderElement('nonexisting_element')); + $this->assertEquals('124', $layout->renderElement('container1')); + $this->assertEquals('12', $layout->renderElement('block1')); + } + + /** + * Invoke getBlock() while layout is being generated + * + * Assertions in this test are pure formalism. The point is to emulate situation where block refers to other block + * while the latter hasn't been generated yet, and assure that there is no crash + */ + public function testGetBlockUnscheduled() + { + $layout = $this->_getLayoutModel('get_block.xml'); + $this->assertInstanceOf('Mage_Core_Block_Text', $layout->getBlock('block1')); + $this->assertInstanceOf('Mage_Core_Block_Text', $layout->getBlock('block2')); + } + + /** + * @expectedException Magento_Exception + */ + public function testGetBlockUnscheduledException() + { + $this->_getLayoutModel('get_block_exception.xml'); + } + + public function testLayoutArgumentsDirective() + { + $layout = $this->_getLayoutModel('arguments.xml'); + $this->assertEquals('1', $layout->getBlock('block_with_args')->getOne()); + $this->assertEquals('two', $layout->getBlock('block_with_args')->getTwo()); + $this->assertEquals('3', $layout->getBlock('block_with_args')->getThree()); + } + + public function testLayoutArgumentsDirectiveIfComplexValues() + { + $layout = $this->_getLayoutModel('arguments_complex_values.xml'); + + $this->assertEquals(array('parameters' => array('first' => '1', 'second' => '2')), + $layout->getBlock('block_with_args_complex_values')->getOne()); + + $this->assertEquals('two', $layout->getBlock('block_with_args_complex_values')->getTwo()); + + $this->assertEquals(array('extra' => array('key1' => 'value1', 'key2' => 'value2')), + $layout->getBlock('block_with_args_complex_values')->getThree()); + } + + public function testLayoutObjectArgumentsDirective() + { + $layout = $this->_getLayoutModel('arguments_object_type.xml'); + $this->assertInstanceOf('Mage_Core_Block_Text', $layout->getBlock('block_with_object_args')->getOne()); + $this->assertInstanceOf('Mage_Core_Block_Messages', + $layout->getBlock('block_with_object_args')->getTwo() + ); + $this->assertEquals(3, $layout->getBlock('block_with_object_args')->getThree()); + } + + public function testLayoutUrlArgumentsDirective() + { + $layout = $this->_getLayoutModel('arguments_url_type.xml'); + $this->assertContains('customer/account/login', $layout->getBlock('block_with_url_args')->getOne()); + $this->assertContains('customer/account/logout', $layout->getBlock('block_with_url_args')->getTwo()); + $this->assertContains('customer_id/3', $layout->getBlock('block_with_url_args')->getTwo()); + } + + public function testLayoutObjectArgumentUpdatersDirective() + { + $layout = $this->_getLayoutModel('arguments_object_type_updaters.xml'); + + $expectedObjectData = array( + 0 => 'updater call', + 1 => 'updater call', + 2 => 'updater call', + ); + + $expectedSimpleData = 2; + + $block = $layout->getBlock('block_with_object_updater_args')->getOne(); + $this->assertInstanceOf('Mage_Core_Block_Text', $block); + $this->assertEquals($expectedObjectData, $block->getUpdaterCall()); + $this->assertEquals($expectedSimpleData, $layout->getBlock('block_with_object_updater_args')->getTwo()); + } + + public function testMoveSameAlias() + { + $layout = $this->_getLayoutModel('move_the_same_alias.xml'); + $this->assertEquals('container1', $layout->getParentName('no_name3')); + } + + public function testMoveNewAlias() + { + $layout = $this->_getLayoutModel('move_new_alias.xml'); + $this->assertEquals('new_alias', $layout->getElementAlias('no_name3')); + } + + public function testActionAnonymousParentBlock() + { + $layout = $this->_getLayoutModel('action_for_anonymous_parent_block.xml'); + $this->assertEquals('schedule_block', $layout->getParentName('test.block.insert')); + $this->assertEquals('schedule_block_1', $layout->getParentName('test.block.append')); + } + + public function testRemove() + { + $layout = $this->_getLayoutModel('remove.xml'); + $this->assertFalse($layout->getBlock('no_name2')); + $this->assertFalse($layout->getBlock('child_block1')); + $this->assertTrue($layout->isBlock('child_block2')); + } + + public function testMove() + { + $layout = $this->_getLayoutModel('move.xml'); + $this->assertEquals('container2', $layout->getParentName('container1')); + $this->assertEquals('container1', $layout->getParentName('no.name2')); + $this->assertEquals('block_container', $layout->getParentName('no_name3')); + + // verify `after` attribute + $this->assertEquals('block_container', $layout->getParentName('no_name')); + $childrenOrderArray = array_keys($layout->getChildBlocks($layout->getParentName('no_name'))); + $positionAfter = array_search('child_block1', $childrenOrderArray); + $positionToVerify = array_search('no_name', $childrenOrderArray); + $this->assertEquals($positionAfter, --$positionToVerify); + + // verify `before` attribute + $this->assertEquals('block_container', $layout->getParentName('no_name4')); + $childrenOrderArray = array_keys($layout->getChildBlocks($layout->getParentName('no_name4'))); + $positionBefore = array_search('child_block2', $childrenOrderArray); + $positionToVerify = array_search('no_name4', $childrenOrderArray); + $this->assertEquals($positionBefore, ++$positionToVerify); + } + + /** + * @expectedException Magento_Exception + */ + public function testMoveBroken() + { + $this->_getLayoutModel('move_broken.xml'); + } + + /** + * @expectedException Magento_Exception + */ + public function testMoveAliasBroken() + { + $this->_getLayoutModel('move_alias_broken.xml'); + } + + /** + * @expectedException Magento_Exception + */ + public function testRemoveBroken() + { + $this->_getLayoutModel('remove_broken.xml'); + } + + /** + * @param string $case + * @param string $expectedResult + * @dataProvider sortSpecialCasesDataProvider + */ + public function testSortSpecialCases($case, $expectedResult) + { + $layout = $this->_getLayoutModel($case); + $this->assertEquals($expectedResult, $layout->renderElement('root')); + } + + /** + * @return array + */ + public function sortSpecialCasesDataProvider() + { + return array( + 'Before element which is after' => array('sort_before_after.xml', '312'), + 'Before element which is previous' => array('sort_before_before.xml', '213'), + 'After element which is after' => array('sort_after_after.xml', '312'), + 'After element which is previous' => array('sort_after_previous.xml', '321'), + ); + } + + + /** + * Prepare a layout model with pre-loaded fixture of an update XML + * + * @param string $fixtureFile + * @return Mage_Core_Model_Layout + */ + protected function _getLayoutModel($fixtureFile) + { + /** @var $layout Mage_Core_Model_Layout */ + $layout = Mage::getModel('Mage_Core_Model_Layout'); + $layout->setXml(simplexml_load_file( + __DIR__ . "/_files/layout_directives_test/{$fixtureFile}", + 'Mage_Core_Model_Layout_Element' + )); + $layout->generateElements(); + return $layout; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/LayoutTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/LayoutTest.php index c2b7f550353..d3a8d537206 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/LayoutTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/LayoutTest.php @@ -28,10 +28,27 @@ /** * Layout integration tests * - * @magentoDbIsolation enabled + * Note that some methods are not covered here, see the Mage_Core_Model_LayoutDirectivesTest + * + * @see Mage_Core_Model_LayoutDirectivesTest */ -class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase +class Mage_Core_Model_LayoutTest extends PHPUnit_Framework_TestCase { + /** + * @var Mage_Core_Model_Layout + */ + protected $_layout; + + protected function setUp() + { + $this->_layout = Mage::getModel('Mage_Core_Model_Layout'); + } + + protected function tearDown() + { + $this->_layout = null; + } + /** * @param array $inputArguments * @param string $expectedArea @@ -56,6 +73,7 @@ class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase { $structure = new Magento_Data_Structure; $structure->createElement('test.container', array()); + /** @var $layout Mage_Core_Model_Layout */ $layout = Mage::getModel('Mage_Core_Model_Layout', array('structure' => $structure)); $this->assertTrue($layout->hasElement('test.container')); } @@ -80,166 +98,54 @@ class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase $this->assertTrue($this->_layout->isDirectOutput()); } - /** - * @covers Mage_Core_Model_Layout::getAllBlocks - * @covers Mage_Core_Model_Layout::generateBlocks - * @covers Mage_Core_Model_Layout::getBlock - * @magentoConfigFixture default_store design/theme/full_name test/default - */ - public function testGenerateXmlAndElements() - { - $this->_layout->generateXml(); - /** - * Generate fixture - * file_put_contents(dirname(__FILE__) . '/_files/_layout_update.xml', $this->_model->getNode()->asNiceXml()); - */ - $this->assertXmlStringEqualsXmlFile(__DIR__ . '/_files/_layout_update.xml', $this->_layout->getXmlString()); - - $this->assertEquals(array(), $this->_layout->getAllBlocks()); - - $expectedBlocks = array( - 'root', - 'head', - 'head.calendar', - 'notifications', - 'notification_baseurl', - 'cache_notifications', - 'notification_survey', - 'notification_security', - 'messages', - 'root_schedule_block', - 'index_notifications', - 'index_notifications_copy' - ); - $this->_layout->generateElements(); - - $actualBlocks = $this->_layout->getAllBlocks(); - $this->assertEquals($expectedBlocks, array_keys($actualBlocks)); - - /** @var $block Mage_Adminhtml_Block_Page_Head */ - $block = $this->_layout->getBlock('head'); - $this->assertEquals('Magento Admin', $block->getTitle()); - - $block = $this->_layout->getBlock('head.calendar'); - $this->assertSame($this->_layout->getBlock('head'), $block->getParentBlock()); - - /** @var $block Mage_Core_Block_Template */ - $block = $this->_layout->getBlock('root'); - $this->assertEquals('popup.phtml', $block->getTemplate()); - - $this->assertFalse($this->_layout->getBlock('test.nonexisting.block')); - } - - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - */ - public function testLayoutDirectives() + public function testGenerateXml() { - /** - * Test move with the same alias - */ + $structure = new Magento_Data_Structure; /** @var $layout Mage_Core_Model_Layout */ - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load(array('layout_test_handle_move_the_same_alias')); - $layout->generateXml()->generateElements(); - $this->assertEquals('container1', $layout->getParentName('no_name3')); - - /** - * Test move with a new alias - */ - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load(array('layout_test_handle_move_new_alias')); - $layout->generateXml()->generateElements(); - $this->assertEquals('new_alias', $layout->getElementAlias('no_name3')); - - /** - * Test layout action with anonymous parent block - */ - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load(array('layout_test_handle_action_for_anonymous_parent_block')); - $layout->generateXml()->generateElements(); - $this->assertEquals('schedule_block', $layout->getParentName('test.block.insert')); - $this->assertEquals('schedule_block_1', $layout->getParentName('test.block.append')); - - /** - * Test layout remove directive - */ - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load(array('layout_test_handle_remove')); - $layout->generateXml()->generateElements(); - $this->assertFalse($layout->getBlock('no_name2')); - $this->assertFalse($layout->getBlock('child_block1')); - $this->assertTrue($layout->isBlock('child_block2')); - - /** - * Test correct move - */ - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load(array('layout_test_handle_move')); - $layout->generateXml()->generateElements(); - $this->assertEquals('container2', $layout->getParentName('container1')); - $this->assertEquals('container1', $layout->getParentName('no.name2')); - $this->assertEquals('block_container', $layout->getParentName('no_name3')); - - // verify `after` attribute - $this->assertEquals('block_container', $layout->getParentName('no_name')); - $childrenOrderArray = array_keys($layout->getChildBlocks($layout->getParentName('no_name'))); - $positionAfter = array_search('child_block1', $childrenOrderArray); - $positionToVerify = array_search('no_name', $childrenOrderArray); - $this->assertEquals($positionAfter, --$positionToVerify); - - // verify `before` attribute - $this->assertEquals('block_container', $layout->getParentName('no_name4')); - $childrenOrderArray = array_keys($layout->getChildBlocks($layout->getParentName('no_name4'))); - $positionBefore = array_search('child_block2', $childrenOrderArray); - $positionToVerify = array_search('no_name4', $childrenOrderArray); - $this->assertEquals($positionBefore, ++$positionToVerify); - } - - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - * @expectedException Magento_Exception - */ - public function testLayoutMoveDirectiveBroken() - { - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load(array('layout_test_handle_move_broken')); - $layout->generateXml()->generateElements(); - } - - /** - * @magentoConfigFixture default_store design/theme/full_name test/default - * @expectedException Magento_Exception - */ - public function testLayoutMoveAliasBroken() - { - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load(array('layout_test_handle_move_alias_broken')); - $layout->generateXml()->generateElements(); + $layout = $this->getMock('Mage_Core_Model_Layout', array('getUpdate'), array( + $this->getMock('Mage_Core_Model_BlockFactory', array(), array(), '', false), + $structure, + $this->getMock('Mage_Core_Model_Layout_Argument_Processor', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Layout_Translator', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Layout_ScheduledStructure', array(), array(), '', false), + )); + $merge = $this->getMock('StdClass', array('asSimplexml')); + $merge->expects($this->once())->method('asSimplexml')->will($this->returnValue(simplexml_load_string( + '<layout><container name="container1"></container></layout>', + 'Mage_Core_Model_Layout_Element' + ))); + $layout->expects($this->once())->method('getUpdate')->will($this->returnValue($merge)); + $this->assertEmpty($layout->getXpath('/layout/container[@name="container1"]')); + $layout->generateXml(); + $this->assertNotEmpty($layout->getXpath('/layout/container[@name="container1"]')); } /** - * @magentoConfigFixture default_store design/theme/full_name test/default - * @expectedException Magento_Exception + * A smoke test for generating elements + * + * See sophisticated tests at Mage_Core_Model_LayoutDirectivesTest + * @see Mage_Core_Model_LayoutDirectivesTest */ - public function testGenerateElementsBroken() + public function testGenerateGetAllBlocks() { - $layout = Mage::getModel('Mage_Core_Model_Layout'); - $layout->getUpdate()->load('layout_test_handle_remove_broken'); - $layout->generateXml()->generateElements(); - } - - public function testRenderElement() - { - $utility = new Mage_Core_Utility_Layout($this); - $layout = $utility->getLayoutFromFixture(__DIR__ . '/_files/valid_layout_updates.xml', - $utility->getLayoutDependencies() - ); - $layout->getUpdate()->load(array('first_handle', 'a_handle', 'another_handle')); - $layout->generateXml()->generateElements(); - $this->assertEmpty($layout->renderElement('nonexisting_element')); - $this->assertEquals("Value: 1 Reference: 1.1\nValue: 2 Reference: 2.2\n", $layout->renderElement('container1')); - $this->assertEquals("Value: 1 Reference: 1.1\n", $layout->renderElement('block1')); + $this->_layout->setXml(simplexml_load_string( + '<layout> + <block type="Mage_Core_Block_Text" name="block1"> + <block type="Mage_Core_Block_Text"/> + </block> + <block type="Mage_Core_Block_Text" template="test"/> + <block type="Mage_Core_Block_Text"/> + </layout>', + 'Mage_Core_Model_Layout_Element' + )); + $this->assertEquals(array(), $this->_layout->getAllBlocks()); + $this->_layout->generateElements(); + $expected = array('block1', 'block1_schedule_block', 'schedule_block', 'schedule_block_1'); + $this->assertSame($expected, array_keys($this->_layout->getAllBlocks())); + $child = $this->_layout->getBlock('block1_schedule_block'); + $this->assertSame($this->_layout->getBlock('block1'), $child->getParentBlock()); + $this->assertEquals('test', $this->_layout->getBlock('schedule_block')->getData('template')); + $this->assertFalse($this->_layout->getBlock('nonexisting')); } public function testGetElementProperty() @@ -272,7 +178,7 @@ class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase public function testSetUnsetBlock() { $expectedBlockName = 'block_' . __METHOD__; - $expectedBlock = Mage::app()->getLayout()->createBlock('Mage_Core_Block_Text'); + $expectedBlock = $this->_layout->createBlock('Mage_Core_Block_Text'); $this->_layout->setBlock($expectedBlockName, $expectedBlock); $this->assertSame($expectedBlock, $this->_layout->getBlock($expectedBlockName)); @@ -413,32 +319,6 @@ class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase $this->assertSame(array('two', 'four', 'three'), $layout->getChildNames('one')); } - /** - * @param string $handle - * @param string $expectedResult - * @dataProvider sortSpecialCasesDataProvider - */ - public function testSortSpecialCases($handle, $expectedResult) - { - $utility = new Mage_Core_Utility_Layout($this); - $layout = $utility->getLayoutFromFixture(__DIR__ . '/_files/sort_special_cases.xml', - $utility->getLayoutDependencies() - ); - $layout->getUpdate()->load($handle); - $layout->generateXml()->generateElements(); - $this->assertEquals($expectedResult, $layout->renderElement('root')); - } - - public function sortSpecialCasesDataProvider() - { - return array( - 'Before element which is after' => array('before_after', '312'), - 'Before element which is previous' => array('before_before', '213'), - 'After element which is after' => array('after_after', '312'), - 'After element which is previous' => array('after_previous', '321'), - ); - } - public function testGetChildBlocks() { $this->_layout->addContainer('parent', 'Parent'); @@ -508,43 +388,8 @@ class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase $this->assertSame($block, $this->_layout->getBlock('test')); } - /** - * Invoke getBlock() while layout is being generated - * - * Assertions in this test are pure formalism. The point is to emulate situation where block refers to other block - * while the latter hasn't been generated yet, and assure that there is no crash - */ - public function testGetBlockUnscheduled() - { - $utility = new Mage_Core_Utility_Layout($this); - $layout = $utility->getLayoutFromFixture(__DIR__ . '/_files/valid_layout_updates.xml', - $utility->getLayoutDependencies() - ); - $layout->getUpdate()->load(array('get_block_special_case')); - $layout->generateXml()->generateElements(); - $this->assertInstanceOf('Mage_Core_Block_Text', $layout->getBlock('block1')); - $this->assertInstanceOf('Mage_Core_Block_Text', $layout->getBlock('block2')); - } - - /** - * @expectedException Magento_Exception - */ - public function testGetBlockUnscheduledException() - { - $utility = new Mage_Core_Utility_Layout($this); - $layout = $utility->getLayoutFromFixture(__DIR__ . '/_files/valid_layout_updates.xml', - $utility->getLayoutDependencies() - ); - $layout->getUpdate()->load(array('get_block_special_case_exception')); - $layout->generateXml(); - $layout->generateElements(); - } - public function testGetParentName() { - /** - * Test get name - */ $this->_layout->addContainer('one', 'One'); $this->_layout->addContainer('two', 'Two', array(), 'one'); $this->assertFalse($this->_layout->getParentName('one')); @@ -586,23 +431,11 @@ class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase $this->assertInstanceOf('Mage_Core_Block_Messages', $this->_layout->getMessagesBlock()); } - /** - * @param string $blockType - * @param string $expectedClassName - * @dataProvider getBlockSingletonDataProvider - */ - public function testGetBlockSingleton($blockType, $expectedClassName) - { - $block = $this->_layout->getBlockSingleton($blockType); - $this->assertInstanceOf($expectedClassName, $block); - $this->assertSame($block, $this->_layout->getBlockSingleton($blockType)); - } - - public function getBlockSingletonDataProvider() + public function testGetBlockSingleton() { - return array( - array('Mage_Core_Block_Text', 'Mage_Core_Block_Text') - ); + $block = $this->_layout->getBlockSingleton('Mage_Core_Block_Text'); + $this->assertInstanceOf('Mage_Core_Block_Text', $block); + $this->assertSame($block, $this->_layout->getBlockSingleton('Mage_Core_Block_Text')); } public function testHelper() @@ -621,6 +454,9 @@ class Mage_Core_Model_LayoutTest extends Mage_Core_Model_LayoutTestBase $this->assertEquals($moduleName, Mage_Core_Model_Layout::findTranslationModuleName($node)); } + /** + * @return array + */ public function findTranslationModuleNameDefaultsDataProvider() { $layout = '<layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Magento/ApiTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Magento/ApiTest.php new file mode 100644 index 00000000000..15f69d4c7cb --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Magento/ApiTest.php @@ -0,0 +1,42 @@ +<?php +/** + * Core module API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Magento info Api tests + */ +class Mage_Core_Model_Magento_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test magento magento info retrieving + */ + public function testInfo() + { + $magentoInfo = Magento_Test_Helper_Api::call($this, 'magentoInfo'); + $this->assertNotEmpty($magentoInfo['magento_version']); + $this->assertNotEmpty($magentoInfo['magento_edition']); + $this->assertEquals(Mage::getEdition(), $magentoInfo['magento_edition']); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/ObserverTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/ObserverTest.php index 4d0332d3128..c50b12dedc4 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/ObserverTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/ObserverTest.php @@ -38,24 +38,28 @@ class Mage_Core_Model_ObserverTest extends PHPUnit_Framework_TestCase */ public function testThemeRegistration() { + $baseDir = 'base_dir'; + $pattern = 'path_pattern'; + $eventObserver = $this->_createEventObserverForThemeRegistration(); - $eventObserver->getEvent()->setBaseDir(dirname(__FILE__) . DS . '_files' . DS . 'design'); + $eventObserver->getEvent()->setBaseDir($baseDir); + $eventObserver->getEvent()->setPathPattern($pattern); + + /** @var $objectManager Magento_Test_ObjectManager */ + $objectManager = Mage::getObjectManager(); + $themeRegistration = $this->getMock( + 'Mage_Core_Model_Theme_Registration', + array('register'), + array($objectManager->create('Mage_Core_Model_Theme')) + ); + $themeRegistration->expects($this->once()) + ->method('register') + ->with($baseDir, $pattern); + $objectManager->addSharedInstance($themeRegistration, 'Mage_Core_Model_Theme_Registration'); /** @var $observer Mage_Core_Model_Observer */ $observer = Mage::getModel('Mage_Core_Model_Observer'); $observer->themeRegistration($eventObserver); - - $defaultModel = $this->_getThemeModel(); - $defaultModel->load('default/default', 'theme_path'); - - $iphoneModel = $this->_getThemeModel(); - $iphoneModel->load('default/default_iphone', 'theme_path'); - - $this->assertEquals('Default', $defaultModel->getThemeTitle()); - $this->assertEquals(null, $defaultModel->getParentId()); - - $this->assertEquals('Iphone', $iphoneModel->getThemeTitle()); - $this->assertEquals($defaultModel->getId(), $iphoneModel->getParentId()); } /** diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Store/ApiTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Store/ApiTest.php new file mode 100644 index 00000000000..c72af0f9566 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Store/ApiTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Core module API tests. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** + * Magento store Api tests + * + * @magentoDataFixture Mage/Core/_files/store.php + */ +class Mage_Core_Model_Store_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test store info. + */ + public function testInfo() + { + $expectedStore = Mage::app()->getStore('fixturestore'); + $storeInfo = Magento_Test_Helper_Api::call($this, 'storeInfo', array( + 'storeId' => 'fixturestore', + )); + $expectedData= $expectedStore->getData(); + $this->assertEquals($expectedData, $storeInfo); + } + + /** + * Test stores list. + */ + public function testList() + { + $actualStores = Magento_Test_Helper_Api::call($this, 'storeList'); + $expectedStores = Mage::app()->getStores(); + /** @var Mage_Core_Model_Store $expectedStore */ + foreach ($expectedStores as $expectedStore) { + $expectedStoreFound = false; + foreach ($actualStores as $actualStore) { + if ($actualStore['store_id'] == $expectedStore->getId()) { + $this->assertEquals($expectedStore->getData(), $actualStore); + $expectedStoreFound = true; + } + } + if (!$expectedStoreFound) { + $this->fail(sprintf('Store "%s" was not found in API response.', $expectedStore->getFrontendName())); + } + } + } +} diff --git a/dev/tests/integration/testsuite/Mage/Install/Helper/DataTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Store/GroupTest.php similarity index 53% rename from dev/tests/integration/testsuite/Mage/Install/Helper/DataTest.php rename to dev/tests/integration/testsuite/Mage/Core/Model/Store/GroupTest.php index 70967b43f73..96a086c6e78 100644 --- a/dev/tests/integration/testsuite/Mage/Install/Helper/DataTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Store/GroupTest.php @@ -19,25 +19,37 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category Magento - * @package Mage_Install + * @package Mage_Core * @subpackage integration_tests * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -class Mage_Install_Helper_DataTest extends PHPUnit_Framework_TestCase +class Mage_Core_Model_Store_GroupTest extends PHPUnit_Framework_TestCase { - public function testCleanVarFolder() + /** + * @var Mage_Core_Model_Store_Group + */ + protected $_model; + + public function setUp() + { + $eventDispatcher = Mage::getObjectManager()->get('Mage_Core_Model_Event_Manager'); + $cacheManager = Mage::getObjectManager()->get('Mage_Core_Model_Cache'); + $this->_model = new Mage_Core_Model_Store_Group($eventDispatcher, $cacheManager); + } + + public function tearDown() + { + $this->_model = null; + } + + public function testSetGetWebsite() { - $rootFolder = Mage::getConfig()->getVarDir() . DIRECTORY_SEPARATOR . 'parentFolder'; - $subFolderA = $rootFolder . DIRECTORY_SEPARATOR . 'subFolderA' . DIRECTORY_SEPARATOR; - $subFolderB = $rootFolder . DIRECTORY_SEPARATOR . 'subFolderB' . DIRECTORY_SEPARATOR; - @mkdir($subFolderA, 0777, true); - @mkdir($subFolderB, 0777, true); - @file_put_contents($subFolderB . 'test.txt', 'Some text here'); - $helper = Mage::helper('Mage_Install_Helper_Data'); - $helper->setVarSubFolders(array($rootFolder)); - $helper->cleanVarFolder(); - $this->assertFalse(is_dir($rootFolder)); + $this->assertFalse($this->_model->getWebsite()); + $website = Mage::app()->getWebsite(); + $this->_model->setWebsite($website); + $actualResult = $this->_model->getWebsite(); + $this->assertSame($website, $actualResult); } } diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/StoreTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/StoreTest.php index 379a1b038cf..7504294c377 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/StoreTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/StoreTest.php @@ -84,6 +84,24 @@ class Mage_Core_Model_StoreTest extends PHPUnit_Framework_TestCase $this->_model->setConfig(Mage_Core_Model_Store::XML_PATH_USE_REWRITES, 0); } + public function testSetGetWebsite() + { + $this->assertFalse($this->_model->getWebsite()); + $website = Mage::app()->getWebsite(); + $this->_model->setWebsite($website); + $actualResult = $this->_model->getWebsite(); + $this->assertSame($website, $actualResult); + } + + public function testSetGetGroup() + { + $this->assertFalse($this->_model->getGroup()); + $storeGroup = Mage::app()->getGroup(); + $this->_model->setGroup($storeGroup); + $actualResult = $this->_model->getGroup(); + $this->assertSame($storeGroup, $actualResult); + } + /** * Isolation is enabled, as we pollute config with rewrite values * @@ -123,29 +141,30 @@ class Mage_Core_Model_StoreTest extends PHPUnit_Framework_TestCase array(Mage_Core_Model_Store::URL_TYPE_DIRECT_LINK, false, true, 'http://localhost/index.php/'), array(Mage_Core_Model_Store::URL_TYPE_DIRECT_LINK, true, false, 'http://localhost/'), array(Mage_Core_Model_Store::URL_TYPE_DIRECT_LINK, true, true, 'http://localhost/'), - array(Mage_Core_Model_Store::URL_TYPE_JS, false, false, 'http://localhost/pub/lib/'), - array(Mage_Core_Model_Store::URL_TYPE_JS, false, true, 'http://localhost/pub/lib/'), - array(Mage_Core_Model_Store::URL_TYPE_JS, true, false, 'http://localhost/pub/lib/'), - array(Mage_Core_Model_Store::URL_TYPE_JS, true, true, 'http://localhost/pub/lib/'), + array(Mage_Core_Model_Store::URL_TYPE_LIB, false, false, 'http://localhost/pub/lib/'), + array(Mage_Core_Model_Store::URL_TYPE_LIB, false, true, 'http://localhost/pub/lib/'), + array(Mage_Core_Model_Store::URL_TYPE_LIB, true, false, 'http://localhost/pub/lib/'), + array(Mage_Core_Model_Store::URL_TYPE_LIB, true, true, 'http://localhost/pub/lib/'), array(Mage_Core_Model_Store::URL_TYPE_MEDIA, false, false, 'http://localhost/pub/media/'), array(Mage_Core_Model_Store::URL_TYPE_MEDIA, false, true, 'http://localhost/pub/media/'), array(Mage_Core_Model_Store::URL_TYPE_MEDIA, true, false, 'http://localhost/pub/media/'), array(Mage_Core_Model_Store::URL_TYPE_MEDIA, true, true, 'http://localhost/pub/media/'), - array(Mage_Core_Model_Store::URL_TYPE_THEME, false, false, 'http://localhost/pub/media/theme/'), - array(Mage_Core_Model_Store::URL_TYPE_THEME, false, true, 'http://localhost/pub/media/theme/'), - array(Mage_Core_Model_Store::URL_TYPE_THEME, true, false, 'http://localhost/pub/media/theme/'), - array(Mage_Core_Model_Store::URL_TYPE_THEME, true, true, 'http://localhost/pub/media/theme/') ); } + /** + * @magentoAppIsolation enabled + */ public function testGetBaseUrlInPub() { + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_URIS => array(Mage_Core_Model_Dir::PUB => '') + )); $this->_model->load('default'); - $_SERVER['SCRIPT_FILENAME'] = 'test/pub/index.php'; $this->assertEquals( 'http://localhost/lib/', - $this->_model->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_JS) + $this->_model->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_LIB) ); $this->assertEquals( 'http://localhost/media/', diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/Theme/CollectionTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/Theme/CollectionTest.php index 7bde8095192..cb8d54c4f7e 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/Theme/CollectionTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/Theme/CollectionTest.php @@ -37,8 +37,6 @@ class Mage_Core_Model_Theme_CollectionTest extends PHPUnit_Framework_TestCase */ public function testLoadThemesFromFileSystem() { - Mage::app()->getConfig()->getOptions()->setDesignDir(dirname(__DIR__)); - $baseDesignDir = implode(DS, array(__DIR__, '..', '_files', 'design')); $pathPattern = implode(DS, array('frontend', 'default', '*', 'theme.xml')); diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/ThemeTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/ThemeTest.php index 67b1d204fc8..40cf31279d7 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/ThemeTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/ThemeTest.php @@ -29,6 +29,8 @@ class Mage_Core_Model_ThemeTest extends PHPUnit_Framework_TestCase { /** * Test crud operations for theme model using valid data + * + * @magentoDbIsolation enabled */ public function testCrud() { @@ -42,22 +44,17 @@ class Mage_Core_Model_ThemeTest extends PHPUnit_Framework_TestCase /** * Load from configuration - * - * @magentoAppIsolation enabled - * @magentoDbIsolation enabled */ public function testLoadFromConfiguration() { $designPath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'design'; - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array($designPath)); - $themeUtility->registerThemes()->setDesignTheme('default/default', 'frontend'); - $themePath = implode(DS, array('frontend', 'default', 'default', 'theme.xml')); /** @var $themeModel Mage_Core_Model_Theme */ $themeModel = Mage::getObjectManager()->create('Mage_Core_Model_Theme'); - $theme = $themeModel->getCollectionFromFilesystem()->setBaseDir($designPath)->addTargetPattern($themePath) + $theme = $themeModel->getCollectionFromFilesystem() + ->setBaseDir($designPath) + ->addTargetPattern($themePath) ->getFirstItem(); $this->assertEquals($this->_expectedThemeDataFromConfiguration(), $theme->getData()); diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/TranslateTest.php b/dev/tests/integration/testsuite/Mage/Core/Model/TranslateTest.php index d2a16de7ec3..3dcc3bdf304 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/TranslateTest.php +++ b/dev/tests/integration/testsuite/Mage/Core/Model/TranslateTest.php @@ -37,20 +37,18 @@ class Mage_Core_Model_TranslateTest extends PHPUnit_Framework_TestCase public function setUp() { - Mage::getConfig()->setOptions(array( - 'locale_dir' => dirname(__FILE__) . '/_files/locale', - )); + $pathChunks = array(dirname(__FILE__), '_files', 'design', 'frontend', 'test', 'default', 'locale', 'en_US', + 'translate.csv'); - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__FILE__) . '/_files/design', - Mage::getDesign() - )); - $themeUtility->registerThemes()->setDesignTheme('test/default', 'frontend'); + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + $design = $this->getMock('Mage_Core_Model_Design_Package', array('getLocaleFileName'), array($filesystem)); + $design->expects($this->any()) + ->method('getLocaleFileName') + ->will($this->returnValue(implode(DS, $pathChunks))); Mage::getConfig()->setModuleDir('Mage_Core', 'locale', dirname(__FILE__) . '/_files/Mage/Core/locale'); Mage::getConfig()->setModuleDir('Mage_Catalog', 'locale', dirname(__FILE__) . '/_files/Mage/Catalog/locale'); - $this->_model = Mage::getModel('Mage_Core_Model_Translate'); + $this->_model = Mage::getModel('Mage_Core_Model_Translate', array($design)); $this->_model->init('frontend'); } @@ -153,6 +151,10 @@ class Mage_Core_Model_TranslateTest extends PHPUnit_Framework_TestCase array( Mage::getModel('Mage_Core_Model_Translate_Expr', array('text' => 'text_with_no_translation')), 'text_with_no_translation' + ), + array( + 'Design value to translate', + 'Design translated value' ) ); } diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/layout.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/layout.xml index 16875f3bfc6..54f6e843a71 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/layout.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/layout.xml @@ -68,224 +68,4 @@ <action method="getSomething"/> </reference> </layout_test_handle_main> - - <layout_test_handle_move> - <container name="container1" label="Container 1"> - <block type="Mage_Core_Block_Text" name="no.name2" as="no.name2"/> - </container> - <container name="container2" label="Container 2"/> - <move element="container1" destination="container2"/> - - <block type="Mage_Core_Block_Text" name="block_container" as="block.container"> - <block type="Mage_Core_Block_Text" name="child_block1"/> - <block type="Mage_Core_Block_Text" name="child_block2"/> - </block> - - <container name="container3" label="Container 3"> - <block type="Mage_Core_Block_Text" name="no_name"/> - </container> - <move element="no_name" destination="block_container" after="child_block1"/> - - <block type="Mage_Core_Block_Text" name="no_name4"/> - <move element="no_name4" destination="block_container" before="child_block2"/> - - <move element="no_name3" destination="block_container"/> - <block type="Mage_Core_Block_Text" name="no_name3"/> - </layout_test_handle_move> - - <layout_test_handle_arguments> - <block type="Mage_Core_Block_Text" name="block_with_args"> - <arguments> - <one>1</one> - <two>2</two> - </arguments> - </block> - <reference name="block_with_args"> - <arguments> - <two>two</two> - <three>3</three> - </arguments> - </reference> - </layout_test_handle_arguments> - - <layout_test_handle_arguments_complex_values> - <block type="Mage_Core_Block_Text" name="block_with_args_complex_values"> - <arguments> - <one> - <parameters> - <first>1</first> - <second>2</second> - </parameters> - </one> - <two> - <parameter_one> - <value>Paramter One</value> - </parameter_one> - <parameter_two>2</parameter_two> - </two> - <three> - <extra> - <key1>value</key1> - </extra> - </three> - </arguments> - </block> - <reference name="block_with_args_complex_values"> - <arguments> - <two>two</two> - <three> - <extra> - <key1>value1</key1> - <key2>value2</key2> - </extra> - </three> - </arguments> - </reference> - </layout_test_handle_arguments_complex_values> - - <layout_test_handle_arguments_object_type> - <block type="Mage_Core_Block_Text" name="block_with_object_args"> - <arguments> - <one type='object'>Mage_Core_Block_Text</one> - <two type='object'>Mage_Core_Block_Text</two> - <three type='object'>Mage_Core_Block_Text</three> - <four type='object'>Mage_Core_Block_Text</four> - </arguments> - </block> - <reference name="block_with_object_args"> - <arguments> - <two>Mage_Core_Block_Messages</two> - <three type=''>3</three> - </arguments> - </reference> - </layout_test_handle_arguments_object_type> - - <layout_test_handle_arguments_object_type_updaters> - <block type="Mage_Core_Block_Text" name="block_with_object_updater_args"> - <arguments> - <one type='object'>Mage_Core_Block_Text</one> - <two>0</two> - </arguments> - </block> - <reference name="block_with_object_updater_args"> - <arguments> - <one> - <updater>Mage_Core_Model_LayoutArgumentObjectUpdater</updater> - <updater>Mage_Core_Model_LayoutArgumentObjectUpdater</updater> - </one> - <two> - <updater>Mage_Core_Model_LayoutArgumentSimpleUpdater</updater> - </two> - </arguments> - </reference> - <reference name="block_with_object_updater_args"> - <arguments> - <one> - <updater>Mage_Core_Model_LayoutArgumentObjectUpdater</updater> - </one> - <two> - <updater>Mage_Core_Model_LayoutArgumentSimpleUpdater</updater> - </two> - </arguments> - </reference> - </layout_test_handle_arguments_object_type_updaters> - - <layout_test_handle_arguments_url_type> - <block type="Mage_Core_Block_Text" name="block_with_url_args"> - <arguments> - <one type="url"> - <path>customer/account/login</path> - <params> - <_current>1</_current> - <_secure>1</_secure> - </params> - </one> - <two type="url"> - <path>customer/account/logout</path> - <params> - <_current>1</_current> - <_secure>1</_secure> - <customer_id>2</customer_id> - </params> - </two> - </arguments> - </block> - <reference name="block_with_url_args"> - <arguments> - <two> - <params> - <customer_id>3</customer_id> - </params> - </two> - </arguments> - </reference> - </layout_test_handle_arguments_url_type> - - - <layout_test_handle_move_broken> - <container name="container1" label="Container 1"/> - <move element="no_name3"/> - <block type="Mage_Core_Block_Text" name="no_name3"/> - </layout_test_handle_move_broken> - - <layout_test_handle_move_alias_broken> - <container name="container1" label="Container 1"> - <block type="Mage_Core_Block_Text" name="no_name1" as="same_alias"/> - </container> - <move element="no_name3" destination="container1" as="same_alias"/> - <block type="Mage_Core_Block_Text" name="no_name3" as="same_alias"/> - </layout_test_handle_move_alias_broken> - - <layout_test_handle_move_the_same_alias> - <container name="container1" label="Container 1"> - <block type="Mage_Core_Block_Text" name="no_name1" as="same_alias"/> - </container> - <move element="no_name3" destination="container1"/> - <block type="Mage_Core_Block_Text" name="no_name3" as="same_alias"/> - </layout_test_handle_move_the_same_alias> - - <layout_test_handle_move_new_alias> - <container name="container1" label="Container 1"> - <block type="Mage_Core_Block_Text" name="no_name1" as="same_alias"/> - </container> - <move element="no_name3" destination="container1" as="new_alias"/> - <block type="Mage_Core_Block_Text" name="no_name3" as="same_alias"/> - </layout_test_handle_move_new_alias> - - <layout_test_handle_remove> - <container name="container1" label="Container 1"> - <block type="Mage_Core_Block_Text" name="no_name2"/> - </container> - <remove name="container1"/> - - <remove name="child_block1"/> - <block type="Mage_Core_Block_Text" name="block_container" as="block.container"> - <block type="Mage_Core_Block_Text" name="child_block1"/> - <block type="Mage_Core_Block_Text" name="child_block2"/> - </block> - <remove name="not_exist"/> - </layout_test_handle_remove> - - <layout_test_handle_remove_broken> - <block name="test.broken.block" type="Mage_Core_Block_Text"/> - <remove name="test.broken.block"/> - <block type="Mage_Core_Block_Template" name="bug.without.name.action.is.ignored"> - <action method="insert"><element>test.broken.block</element></action> - <action method="append"><element>test.broken.block</element></action> - </block> - </layout_test_handle_remove_broken> - - - <layout_test_handle_action_for_anonymous_parent_block> - <block name="test.block.insert" type="Mage_Core_Block_Text"/> - - <block type="Mage_Core_Block_Template"> - <action method="insert"><element>test.block.insert</element></action> - </block> - - <block name="test.block.append" type="Mage_Core_Block_Text"/> - <block type="Mage_Core_Block_Text"> - <action method="append"><element>test.block.append</element></action> - </block> - </layout_test_handle_action_for_anonymous_parent_block> </layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/test.phtml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/test.phtml index 992c4c873b3..708bcd7549e 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/test.phtml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/frontend/test/default/Mage_Core/test.phtml @@ -24,4 +24,4 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ -echo "Value: {$this->getTestValue()} Reference: {$this->getReferenceValue()}\n"; +echo 'Content of this file is not asserted. Only its presence.'; diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/themes.php b/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/themes.php new file mode 100644 index 00000000000..c0082d1d77e --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/design/themes.php @@ -0,0 +1,33 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Core + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var $registration Mage_Core_Model_Theme_Registration */ +$registration = Mage::getModel('Mage_Core_Model_Theme_Registration'); +$registration->register( + __DIR__, + implode(DIRECTORY_SEPARATOR, array('*', '*', '*', 'theme.xml')) +); diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/fallback/pub/js/mage/script.js b/dev/tests/integration/testsuite/Mage/Core/Model/_files/fallback/pub/lib/mage/script.js similarity index 100% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/fallback/pub/js/mage/script.js rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/fallback/pub/lib/mage/script.js diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_no_custom_config/a.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/action_for_anonymous_parent_block.xml similarity index 69% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_no_custom_config/a.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/action_for_anonymous_parent_block.xml index 781197f9e2a..cdbf362522a 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_no_custom_config/a.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/action_for_anonymous_parent_block.xml @@ -19,15 +19,19 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Magento - * @package Magento_Core - * @subpackage integration_tests * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ --> -<root> - <a> - <value>a</value> - </a> -</root> +<layout> + <block name="test.block.insert" type="Mage_Core_Block_Text"/> + + <block type="Mage_Core_Block_Template"> + <action method="insert"><element>test.block.insert</element></action> + </block> + + <block name="test.block.append" type="Mage_Core_Block_Text"/> + <block type="Mage_Core_Block_Text"> + <action method="append"><element>test.block.append</element></action> + </block> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments.xml new file mode 100644 index 00000000000..1e6ae71360a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <block type="Mage_Core_Block_Text" name="block_with_args"> + <arguments> + <one>1</one> + <two>2</two> + </arguments> + </block> + <reference name="block_with_args"> + <arguments> + <two>two</two> + <three>3</three> + </arguments> + </reference> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_complex_values.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_complex_values.xml new file mode 100644 index 00000000000..29b414bb28c --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_complex_values.xml @@ -0,0 +1,59 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <block type="Mage_Core_Block_Text" name="block_with_args_complex_values"> + <arguments> + <one> + <parameters> + <first>1</first> + <second>2</second> + </parameters> + </one> + <two> + <parameter_one> + <value>Paramter One</value> + </parameter_one> + <parameter_two>2</parameter_two> + </two> + <three> + <extra> + <key1>value</key1> + </extra> + </three> + </arguments> + </block> + <reference name="block_with_args_complex_values"> + <arguments> + <two>two</two> + <three> + <extra> + <key1>value1</key1> + <key2>value2</key2> + </extra> + </three> + </arguments> + </reference> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type.xml new file mode 100644 index 00000000000..d49fd067c16 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type.xml @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <block type="Mage_Core_Block_Text" name="block_with_object_args"> + <arguments> + <one type='object'>Mage_Core_Block_Text</one> + <two type='object'>Mage_Core_Block_Text</two> + <three type='object'>Mage_Core_Block_Text</three> + <four type='object'>Mage_Core_Block_Text</four> + </arguments> + </block> + <reference name="block_with_object_args"> + <arguments> + <two>Mage_Core_Block_Messages</two> + <three type=''>3</three> + </arguments> + </reference> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type_updaters.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type_updaters.xml new file mode 100644 index 00000000000..97d3821ee0f --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_object_type_updaters.xml @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <block type="Mage_Core_Block_Text" name="block_with_object_updater_args"> + <arguments> + <one type='object'>Mage_Core_Block_Text</one> + <two>0</two> + </arguments> + </block> + <reference name="block_with_object_updater_args"> + <arguments> + <one> + <updater>Mage_Core_Model_LayoutArgumentObjectUpdater</updater> + <updater>Mage_Core_Model_LayoutArgumentObjectUpdater</updater> + </one> + <two> + <updater>Mage_Core_Model_LayoutArgumentSimpleUpdater</updater> + </two> + </arguments> + </reference> + <reference name="block_with_object_updater_args"> + <arguments> + <one> + <updater>Mage_Core_Model_LayoutArgumentObjectUpdater</updater> + </one> + <two> + <updater>Mage_Core_Model_LayoutArgumentSimpleUpdater</updater> + </two> + </arguments> + </reference> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_url_type.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_url_type.xml new file mode 100644 index 00000000000..a266b64bb1a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/arguments_url_type.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <block type="Mage_Core_Block_Text" name="block_with_url_args"> + <arguments> + <one type="url"> + <path>customer/account/login</path> + <params> + <_current>1</_current> + <_secure>1</_secure> + </params> + </one> + <two type="url"> + <path>customer/account/logout</path> + <params> + <_current>1</_current> + <_secure>1</_secure> + <customer_id>2</customer_id> + </params> + </two> + </arguments> + </block> + <reference name="block_with_url_args"> + <arguments> + <two> + <params> + <customer_id>3</customer_id> + </params> + </two> + </arguments> + </reference> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/custom/invalid.pattern.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/get_block.xml similarity index 81% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/custom/invalid.pattern.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/get_block.xml index 1430dc32c05..c5e0fc2dd49 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/custom/invalid.pattern.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/get_block.xml @@ -19,11 +19,13 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Magento - * @package Magento_Core - * @subpackage integration_tests * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ --> -intentionally non-well-formed XML +<layout> + <block name="block1" type="Mage_Core_Block_Text"> + <action method="getChildBlock"><value>block2</value></action> + <block name="block2" type="Mage_Core_Block_Text"/> + </block> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/get_block_exception.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/get_block_exception.xml new file mode 100644 index 00000000000..fcf3c2319cd --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/get_block_exception.xml @@ -0,0 +1,31 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <block name="block1" type="Mage_Core_Block_Text"> + <container name="container" label="Container"/> + <action method="getChildBlock"><value>container</value></action> + </block> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move.xml new file mode 100644 index 00000000000..272df53b954 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="container1" label="Container 1"> + <block type="Mage_Core_Block_Text" name="no.name2" as="no.name2"/> + </container> + <container name="container2" label="Container 2"/> + <move element="container1" destination="container2"/> + + <block type="Mage_Core_Block_Text" name="block_container" as="block.container"> + <block type="Mage_Core_Block_Text" name="child_block1"/> + <block type="Mage_Core_Block_Text" name="child_block2"/> + </block> + + <container name="container3" label="Container 3"> + <block type="Mage_Core_Block_Text" name="no_name"/> + </container> + <move element="no_name" destination="block_container" after="child_block1"/> + + <block type="Mage_Core_Block_Text" name="no_name4"/> + <move element="no_name4" destination="block_container" before="child_block2"/> + + <move element="no_name3" destination="block_container"/> + <block type="Mage_Core_Block_Text" name="no_name3"/> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_alias_broken.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_alias_broken.xml new file mode 100644 index 00000000000..f8b7252018b --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_alias_broken.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="container1" label="Container 1"> + <block type="Mage_Core_Block_Text" name="no_name1" as="same_alias"/> + </container> + <move element="no_name3" destination="container1" as="same_alias"/> + <block type="Mage_Core_Block_Text" name="no_name3" as="same_alias"/> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/local.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_broken.xml similarity index 85% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/local.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_broken.xml index 648546d88c1..0024fd3d4e9 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/local.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_broken.xml @@ -19,13 +19,12 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category Magento - * @package Magento_Core - * @subpackage integration_tests * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ --> -<root> - <value>local</value> -</root> +<layout> + <container name="container1" label="Container 1"/> + <move element="no_name3"/> + <block type="Mage_Core_Block_Text" name="no_name3"/> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_new_alias.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_new_alias.xml new file mode 100644 index 00000000000..50aa2e0b0e4 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_new_alias.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="container1" label="Container 1"> + <block type="Mage_Core_Block_Text" name="no_name1" as="same_alias"/> + </container> + <move element="no_name3" destination="container1" as="new_alias"/> + <block type="Mage_Core_Block_Text" name="no_name3" as="same_alias"/> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_the_same_alias.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_the_same_alias.xml new file mode 100644 index 00000000000..349d77c0c34 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/move_the_same_alias.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="container1" label="Container 1"> + <block type="Mage_Core_Block_Text" name="no_name1" as="same_alias"/> + </container> + <move element="no_name3" destination="container1"/> + <block type="Mage_Core_Block_Text" name="no_name3" as="same_alias"/> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove.xml new file mode 100644 index 00000000000..2fc0f35048b --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="container1" label="Container 1"> + <block type="Mage_Core_Block_Text" name="no_name2"/> + </container> + <remove name="container1"/> + + <remove name="child_block1"/> + <block type="Mage_Core_Block_Text" name="block_container" as="block.container"> + <block type="Mage_Core_Block_Text" name="child_block1"/> + <block type="Mage_Core_Block_Text" name="child_block2"/> + </block> + <remove name="not_exist"/> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove_broken.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove_broken.xml new file mode 100644 index 00000000000..65244c241ba --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/remove_broken.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <block name="test.broken.block" type="Mage_Core_Block_Text"/> + <remove name="test.broken.block"/> + <block type="Mage_Core_Block_Template" name="bug.without.name.action.is.ignored"> + <action method="insert"><element>test.broken.block</element></action> + <action method="append"><element>test.broken.block</element></action> + </block> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/render.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/render.xml new file mode 100644 index 00000000000..acae298c251 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/render.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <!-- Despite reference element is not declared yet, it will "save this action for later" --> + <reference name="block1"> + <action method="addText"><value>1</value></action> + </reference> + <container name="container1" label="Container 1"> + <block type="Mage_Core_Block_Text" name="block1"> + <action method="addText"><value>2</value></action> + </block> + <block type="Mage_Core_Block_Text" name="block2"> + <action method="setText"><value>3</value></action> + </block> + </container> + <!-- A conventional use of reference - after element is declared --> + <reference name="block2"> + <action method="setText"><value>4</value></action> + </reference> + <!-- Reference to non-existing element will remain ignored --> + <reference name="nonexistent"> + <action method="addText"><value>5</value></action> + </reference> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_after.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_after.xml new file mode 100644 index 00000000000..8e26cf42f4c --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_after.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="root" label="Root"> + <block type="Mage_Core_Block_Text" name="element1" after="element3"> + <action method="setText"><text>1</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element2" after="element1"> + <action method="setText"><text>2</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element3" after="element_non_existing"> + <action method="setText"><text>3</text></action> + </block> + </container> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_previous.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_previous.xml new file mode 100644 index 00000000000..361a8bb63fc --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_after_previous.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="root" label="Root"> + <block type="Mage_Core_Block_Text" name="element1" after="element2"> + <action method="setText"><text>1</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element2" after="element3"> + <action method="setText"><text>2</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element3"> + <!-- neither "before" or "after" specified, therefore insert before all elements --> + <action method="setText"><text>3</text></action> + </block> + </container> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_after.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_after.xml new file mode 100644 index 00000000000..b8c63968053 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_after.xml @@ -0,0 +1,38 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="root" label="Root"> + <block type="Mage_Core_Block_Text" name="element1" before="element2"> + <action method="setText"><text>1</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element2" after="element3"> + <action method="setText"><text>2</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element3" after="-"> + <action method="setText"><text>3</text></action> + </block> + </container> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_before.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_before.xml new file mode 100644 index 00000000000..7dc8ed80e22 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/layout_directives_test/sort_before_before.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<layout> + <container name="root" label="Root"> + <block type="Mage_Core_Block_Text" name="element1" before="element3"> + <action method="setText"><text>1</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element2" before="element1"> + <action method="setText"><text>2</text></action> + </block> + <block type="Mage_Core_Block_Text" name="element3" before="element_non_existing"> + <!-- element_non_existing doesn't exist, so element3 is generated at the end --> + <action method="setText"><text>3</text></action> + </block> + </container> +</layout> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_no_custom_config/local.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/custom/local.xml similarity index 82% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_no_custom_config/local.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/custom/local.xml index 648546d88c1..d0dbcd3f538 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_no_custom_config/local.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/custom/local.xml @@ -27,5 +27,13 @@ */ --> <root> - <value>local</value> + <global> + <resources> + <core_setup> + <connection> + <model>custom</model> + </connection> + </core_setup> + </resources> + </global> </root> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/custom/prohibited.filename.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/custom/prohibited.filename.xml new file mode 100644 index 00000000000..12bcb4b28dd --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/custom/prohibited.filename.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Core + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <global> + <resources> + <core_setup> + <connection> + <model>prohibited_value</model> + </connection> + </core_setup> + </resources> + </global> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/custom/local.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/local.xml similarity index 82% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/custom/local.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/local.xml index ddf145258c0..c6d0fea0602 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_custom_config/custom/local.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/local.xml @@ -27,5 +27,13 @@ */ --> <root> - <value>custom</value> + <global> + <resources> + <core_setup> + <connection> + <model>local</model> + </connection> + </core_setup> + </resources> + </global> </root> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_no_custom_config/z.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/z.xml similarity index 82% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_no_custom_config/z.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/z.xml index ef72118fde4..d01f67dedc6 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config_no_custom_config/z.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/local_config/z.xml @@ -27,5 +27,13 @@ */ --> <root> - <value>z</value> + <global> + <resources> + <core_setup> + <connection> + <model>z</model> + </connection> + </core_setup> + </resources> + </global> </root> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_custom_config/a.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/a.xml similarity index 82% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_custom_config/a.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/a.xml index 64c1d4b50d4..9a1523b665f 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_custom_config/a.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/a.xml @@ -27,5 +27,13 @@ */ --> <root> - <a/> + <global> + <resources> + <core_setup> + <connection> + <model>a</model> + </connection> + </core_setup> + </resources> + </global> </root> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_no_custom_config/b.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/b.xml similarity index 82% rename from dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_no_custom_config/b.xml rename to dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/b.xml index 27130671a08..12376c1e653 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_no_custom_config/b.xml +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/b.xml @@ -27,7 +27,13 @@ */ --> <root> - <a> - <value>b</value> - </a> + <global> + <resources> + <core_setup> + <connection> + <model>b</model> + </connection> + </core_setup> + </resources> + </global> </root> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/custom/local.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/custom/local.xml new file mode 100644 index 00000000000..d0dbcd3f538 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config/custom/local.xml @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<!-- +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Magento_Core + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +--> +<root> + <global> + <resources> + <core_setup> + <connection> + <model>custom</model> + </connection> + </core_setup> + </resources> + </global> +</root> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_custom_config/custom/local.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_custom_config/custom/local.xml deleted file mode 100644 index 1430dc32c05..00000000000 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/local_config/no_local_config_custom_config/custom/local.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Academic Free License (AFL 3.0) - * that is bundled with this package in the file LICENSE_AFL.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/afl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Magento_Core - * @subpackage integration_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) - */ ---> -intentionally non-well-formed XML diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/sort_special_cases.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/sort_special_cases.xml deleted file mode 100644 index 4829969301f..00000000000 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/sort_special_cases.xml +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Academic Free License (AFL 3.0) - * that is bundled with this package in the file LICENSE_AFL.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/afl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Magento_Core - * @subpackage integration_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) - */ ---> -<layouts> - <before_after> - <container name="root" label="Root"> - <block type="Mage_Core_Block_Text" name="element1" before="element2"> - <action method="setText"><text>1</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element2" after="element3"> - <action method="setText"><text>2</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element3" after="-"> - <action method="setText"><text>3</text></action> - </block> - </container> - </before_after> - <before_before> - <container name="root" label="Root"> - <block type="Mage_Core_Block_Text" name="element1" before="element3"> - <action method="setText"><text>1</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element2" before="element1"> - <action method="setText"><text>2</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element3" before="element_non_existing"> - <!-- element_non_existing doesn't exist, so element3 is generated at the end --> - <action method="setText"><text>3</text></action> - </block> - </container> - </before_before> - <after_after> - <container name="root" label="Root"> - <block type="Mage_Core_Block_Text" name="element1" after="element3"> - <action method="setText"><text>1</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element2" after="element1"> - <action method="setText"><text>2</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element3" after="element_non_existing"> - <action method="setText"><text>3</text></action> - </block> - </container> - </after_after> - <after_previous> - <container name="root" label="Root"> - <block type="Mage_Core_Block_Text" name="element1" after="element2"> - <action method="setText"><text>1</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element2" after="element3"> - <action method="setText"><text>2</text></action> - </block> - <block type="Mage_Core_Block_Text" name="element3"> - <!-- neither "before" or "after" specified, therefore insert before all elements --> - <action method="setText"><text>3</text></action> - </block> - </container> - </after_previous> -</layouts> diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/_files/valid_layout_updates.xml b/dev/tests/integration/testsuite/Mage/Core/Model/_files/valid_layout_updates.xml deleted file mode 100644 index 90693d68ad3..00000000000 --- a/dev/tests/integration/testsuite/Mage/Core/Model/_files/valid_layout_updates.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Academic Free License (AFL 3.0) - * that is bundled with this package in the file LICENSE_AFL.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/afl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Magento_Core - * @subpackage integration_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) - */ ---> -<layouts> - <first_handle> - <!-- Despite reference element is not declared yet, it will "save this action for later" --> - <reference name="block1"> - <action method="setReferenceValue"><value>1.1</value></action> - </reference> - </first_handle> - - <a_handle> - <container name="container1" label="Container 1"> - <block type="Mage_Core_Block_Template" name="block1" template="Mage_Core::test.phtml"> - <action method="setTestValue"><value>1</value></action> - </block> - <block type="Mage_Core_Block_Template" name="block2" template="Mage_Core::test.phtml"> - <action method="setTestValue"><value>2</value></action> - </block> - </container> - </a_handle> - - <another_handle> - <!-- A conventional use of reference - after element is declared --> - <reference name="block2"> - <action method="setReferenceValue"><value>2.2</value></action> - </reference> - - <!-- Reference to non-existing element will remain ignored --> - <reference name="nonexistent"> - <action method="setReferenceValue"><value>3.3</value></action> - </reference> - </another_handle> - - <get_block_special_case> - <block name="block1" type="Mage_Core_Block_Text"> - <action method="getChildBlock"><value>block2</value></action> - <block name="block2" type="Mage_Core_Block_Text"/> - </block> - </get_block_special_case> - - <get_block_special_case_exception> - <block name="block1" type="Mage_Core_Block_Text"> - <container name="container" label="Container"/> - <action method="getChildBlock"><value>container</value></action> - </block> - </get_block_special_case_exception> -</layouts> diff --git a/dev/tests/integration/testsuite/Mage/Core/Utility/Theme.php b/dev/tests/integration/testsuite/Mage/Core/Utility/Theme.php deleted file mode 100644 index 28f449b2d6e..00000000000 --- a/dev/tests/integration/testsuite/Mage/Core/Utility/Theme.php +++ /dev/null @@ -1,211 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Magento - * @subpackage integration_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -/** - * Core theme utility - */ -class Mage_Core_Utility_Theme -{ - /** - * @var string - */ - protected $_designDir; - - /** - * @var Mage_Core_Model_Design_Package - */ - protected $_design; - - /** - * @var Mage_Core_Model_Theme_Registration - */ - protected $_register; - - /** - * @var Mage_Core_Model_Theme - */ - protected $_theme; - - /** - * @var Mage_Core_Model_Resource_Theme_Collection - */ - protected $_themesCollection; - - /** - * @param string $designDir - * @param Mage_Core_Model_Design_Package $design - * @param Mage_Core_Model_Theme_Registration $registration - * @param Mage_Core_Model_Theme $theme - */ - public function __construct( - $designDir = null, - Mage_Core_Model_Design_Package $design = null, - Mage_Core_Model_Theme_Registration $registration, - Mage_Core_Model_Theme $theme - ) { - $this->_designDir = $designDir; - $this->_design = $design ? $design : Mage::getDesign(); - $this->_register = $registration; - $this->_theme = $theme; - } - - /** - * @return Mage_Core_Model_Design_Package - */ - public function getDesign() - { - return $this->_design; - } - - /** - * Register mocked package model in di - * - * @static - */ - public static function registerDesignMock() - { - /** @var $packageMock Mage_Core_Model_Design_Package|PHPUnit_Framework_MockObject_MockObject */ - $packageMock = PHPUnit_Framework_MockObject_Generator::getMock( - 'Mage_Core_Model_Design_Package', array('getConfigurationDesignTheme'), - array(self::_createFilesystem()) - ); - $package = Mage::getModel('Mage_Core_Model_Design_Package', array('filesystem' => self::_createFilesystem())); - - $callBackFixture = function ($area, $params) use ($package, $packageMock) { - $area = $area ? $area : $packageMock->getArea(); - if (isset($params['useId']) && $params['useId'] === false) { - return $package->getConfigurationDesignTheme($area, $params); - } else { - $params['useId'] = false; - /** @var $package Mage_Core_Model_Design_Package */ - $configPath = $package->getConfigurationDesignTheme($area, $params); - return Mage_Core_Utility_Theme::getTheme($configPath, $area)->getId(); - } - }; - - $packageMock->expects(new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount) - ->method('getConfigurationDesignTheme') - ->will(new PHPUnit_Framework_MockObject_Stub_ReturnCallback($callBackFixture)); - - /** @var $objectManager Magento_Test_ObjectManager */ - $objectManager = Mage::getObjectManager(); - $objectManager->addSharedInstance($packageMock, 'Mage_Core_Model_Design_Package'); - } - - - /** - * @return Magento_Filesystem - */ - protected static function _createFilesystem() - { - return new Magento_Filesystem(new Magento_Filesystem_Adapter_Local()); - } - - /** - * @return Mage_Core_Utility_Theme - */ - public function registerThemes() - { - Mage::app()->getConfig()->getOptions()->setDesignDir($this->_designDir); - $this->_register->register(); - $this->_design->setDefaultDesignTheme(); - return $this; - } - - /** - * @return Mage_Core_Model_Resource_Theme_Collection - */ - protected function _getCollection() - { - if (!$this->_themesCollection) { - $this->_themesCollection = $this->_theme->getCollection()->load(); - } - return $this->_themesCollection; - } - - /** - * @param string $themePath - * @param string|null $area - * @return Mage_Core_Model_Theme - */ - public function getThemeByParams($themePath, $area) - { - /** @var $theme Mage_Core_Model_Theme */ - foreach ($this->_getCollection() as $theme) { - if ($theme->getThemePath() === $themePath && $theme->getArea() === $area) { - return $theme; - } - } - return $this->_theme; - } - - /** - * @param string $themePath - * @param string|null $area - * @return Mage_Core_Model_Theme - */ - public static function getTheme($themePath, $area) - { - /** @var $theme Mage_Core_Model_Theme */ - $theme = Mage::getSingleton('Mage_Core_Model_Theme'); - $collection = $theme->getCollection() - ->addFieldToFilter('theme_path', $themePath) - ->addFieldToFilter('area', $area) - ->load(); - return $collection->getFirstItem(); - } - - /** - * @param string $themePath - * @param null $area - * @return Mage_Core_Utility_Theme - */ - public function setDesignTheme($themePath, $area = null) - { - if (empty($area)) { - $area = $this->_design->getArea(); - } - $theme = $this->getThemeByParams($themePath, $area); - $this->_design->setDesignTheme($theme, $area); - return $this; - } - - /** - * @return array - */ - public function getStructure() - { - $structure = array(); - /** @var $theme Mage_Core_Model_Theme */ - foreach ($this->_getCollection() as $theme) { - if ($theme->getId() && $theme->getThemePath()) { - $structure[$theme->getArea()][$theme->getThemePath()] = $theme; - } - } - return $structure; - } -} diff --git a/dev/tests/integration/testsuite/Mage/Core/Model/LayoutTestBase.php b/dev/tests/integration/testsuite/Mage/Core/_files/media_for_change.php similarity index 50% rename from dev/tests/integration/testsuite/Mage/Core/Model/LayoutTestBase.php rename to dev/tests/integration/testsuite/Mage/Core/_files/media_for_change.php index ec8e60fa7cc..a658ac04edd 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Model/LayoutTestBase.php +++ b/dev/tests/integration/testsuite/Mage/Core/_files/media_for_change.php @@ -25,35 +25,23 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -/** - * Layout integration tests - */ -class Mage_Core_Model_LayoutTestBase extends PHPUnit_Framework_TestCase -{ - /** - * @var Mage_Core_Model_Layout - */ - protected $_layout; - - protected function setUp() - { - /** @var $themeUtility Mage_Core_Utility_Theme */ - $themeUtility = Mage::getModel('Mage_Core_Utility_Theme', array( - dirname(__FILE__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'design', - Mage::getDesign() - )); - $themeUtility->registerThemes()->setDesignTheme('test/default', 'frontend'); +$designDir = Magento_Test_Bootstrap::getInstance()->getInstallDir() . '/media_for_change'; +$themeDir = $designDir . DIRECTORY_SEPARATOR . '/frontend/test/default'; +$sourcePath = dirname(__DIR__) . '/Model/_files/design/frontend/test/publication/'; - /* Disable loading and saving layout cache */ - Mage::app()->getCacheInstance()->banUse('layout'); +mkdir($themeDir . '/images', 0777, true); - $this->_layout = Mage::getModel('Mage_Core_Model_Layout'); - $this->_layout->getUpdate()->addHandle('layout_test_handle_main'); - $this->_layout->getUpdate()->load('layout_test_handle_extra'); - } - - protected function tearDown() - { - $this->_layout = null; - } +// Copy all files to fixture location +$mTime = time() - 10; // To ensure that all files, changed later in test, will be recognized for publication +$files = array('theme.xml', 'style.css', 'sub.css', 'images/square.gif', 'images/rectangle.gif'); +foreach ($files as $file) { + copy($sourcePath . $file, $themeDir . DIRECTORY_SEPARATOR . $file); + touch($themeDir . DIRECTORY_SEPARATOR . $file, $mTime); } + +/** @var $registration Mage_Core_Model_Theme_Registration */ +$registration = Mage::getModel('Mage_Core_Model_Theme_Registration'); +$registration->register( + $designDir, + implode(DIRECTORY_SEPARATOR, array('*', '*', '*', 'theme.xml')) +); diff --git a/dev/tests/integration/testsuite/Mage/Core/_files/media_for_change_rollback.php b/dev/tests/integration/testsuite/Mage/Core/_files/media_for_change_rollback.php new file mode 100644 index 00000000000..ba8bf37418a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Core/_files/media_for_change_rollback.php @@ -0,0 +1,29 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Core + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +$designDir = Magento_Test_Bootstrap::getInstance()->getInstallDir() . '/media_for_change'; +Varien_Io_File::rmdirRecursive($designDir); diff --git a/dev/tests/integration/testsuite/Mage/Customer/Model/Address/ApiTest.php b/dev/tests/integration/testsuite/Mage/Customer/Model/Address/ApiTest.php new file mode 100644 index 00000000000..1531f1a021d --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Customer/Model/Address/ApiTest.php @@ -0,0 +1,232 @@ +<?php +/** + * Test class for Mage_Customer_Model_Address_Api. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Customer/_files/customer.php + * @magentoDataFixture Mage/Customer/_files/customer_two_addresses.php + */ +class Mage_Customer_Model_Address_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test for customer address list + */ + public function testCustomerAddressList() + { + // Get the customer's addresses + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'customerAddressList', + array( + 'customerId' => 1 + ) + ); + + $this->assertNotEmpty($soapResult, 'Error during customer address list via API call'); + $this->assertCount(2, $soapResult, 'Result did not contain 2 addresses'); + + /** @var $firstAddress Mage_Customer_Model_Address */ + $firstAddress = Mage::getModel('Mage_Customer_Model_Address'); + $firstAddress->load(1); + $this->_verifyAddress($firstAddress->getData(), $soapResult[0]); + + /** @var $secondAddress Mage_Customer_Model_Address */ + $secondAddress = Mage::getModel('Mage_Customer_Model_Address'); + $secondAddress->load(2); + $this->_verifyAddress($secondAddress->getData(), $soapResult[1]); + } + + /** + * Test for customer address info + */ + public function testCustomerAddressInfo() + { + /** @var $customerAddress Mage_Customer_Model_Address */ + $customerAddress = Mage::getModel('Mage_Customer_Model_Address'); + $customerAddress->load(1); + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'customerAddressInfo', + array( + 'addressId' => $customerAddress->getId() + ) + ); + + $this->assertNotEmpty($soapResult, 'Error during customer address info via API call'); + $this->_verifyAddress($customerAddress->getData(), $soapResult); + } + + /** + * Test customer address create + * + * @magentoDbIsolation enabled + */ + public function testCustomerAddressCreate() + { + $customerId = 1; + + // New address to create + $newAddressData = array( + 'city' => 'Kyle', + 'company' => 'HBM', + 'country_id' => 'US', + 'fax' => '5125551234', + 'firstname' => 'Sherry', + 'lastname' => 'Berry', + 'middlename' => 'Kari', + 'postcode' => '77777', + 'prefix' => 'Ms', + 'region_id' => 35, + 'region' => 'Mississippi', + 'street' => array('123 FM 101'), + 'suffix' => 'M', + 'telephone' => '5', + 'is_default_billing' => false, + 'is_default_shipping' => false + ); + + // Call api to create the address + $newAddressId = Magento_Test_Helper_Api::call( + $this, + 'customerAddressCreate', + array( + 'customerId' => $customerId, + 'addressData' => (object)$newAddressData + ) + ); + + // Verify the new address was added + /** @var $newAddressModel Mage_Customer_Model_Address */ + $newAddressModel = Mage::getModel('Mage_Customer_Model_Address'); + $newAddressModel->load($newAddressId); + + // Verify all field values were correctly set + $newAddressData['street'] = trim(implode("\n", $newAddressData['street'])); + $newAddressData['customer_address_id'] = $newAddressId; + $this->_verifyAddress($newAddressData, $newAddressModel->getData()); + } + + /** + * Test customer address delete + * + * @magentoDbIsolation enabled + */ + public function testCustomerAddressDelete() + { + $addressId = 1; + + // Delete address + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'customerAddressDelete', + array( + 'addressId' => $addressId + ) + ); + $this->assertTrue($soapResult, 'Error during customer address delete via API call'); + + /** @var Mage_Customer_Model_Address $address */ + $address = Mage::getModel('Mage_Customer_Model_Address')->load($addressId); + $this->assertNull($address->getEntityId()); + } + + /** + * Test customer address update + * + * @magentoDbIsolation enabled + */ + public function testCustomerAddressUpdate() + { + $addressId = 1; + $newFirstname = 'Eric'; + $newTelephone = '888-555-8888'; + + // Data to set in existing address + $updateData = (object)array( + 'firstname' => $newFirstname, + 'telephone' => $newTelephone + ); + + // update a customer's address + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'customerAddressUpdate', + array( + 'addressId' => $addressId, + 'addressData' => $updateData + ) + ); + + $this->assertTrue($soapResult, 'Error during customer address update via API call'); + + // Verify all field values were correctly set + /** @var $customerAddress Mage_Customer_Model_Address */ + $customerAddress = Mage::getModel('Mage_Customer_Model_Address'); + $customerAddress->load($addressId); + + $this->assertEquals( + $newFirstname, + $customerAddress->getFirstname(), + 'First name is not updated.' + ); + $this->assertEquals( + $newTelephone, + $customerAddress->getTelephone(), + 'Telephone is not updated.' + ); + } + + /** + * Verify fields in an address array + * + * Compares two arrays containing address data. Throws assertion error if + * data does not match. + * + * @param array $expectedData Expected values of address array + * @param array $actualData Values that are to be tested + */ + protected function _verifyAddress($expectedData, $actualData) + { + $fieldsToCompare = array( + 'entity_id' => 'customer_address_id', + 'city', + 'country_id', + 'fax', + 'firstname', + 'lastname', + 'middlename', + 'postcode', + 'region', + 'region_id', + 'street', + 'telephone' + ); + + Magento_Test_Helper_Api::checkEntityFields( + $this, + $expectedData, + $actualData, + $fieldsToCompare + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Customer/Model/Customer/ApiTest.php b/dev/tests/integration/testsuite/Mage/Customer/Model/Customer/ApiTest.php new file mode 100644 index 00000000000..b07e4f8c085 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Customer/Model/Customer/ApiTest.php @@ -0,0 +1,166 @@ +<?php +/** + * Test for customer API. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Customer_Model_Customer_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test create method. + * + * @magentoDbIsolation enabled + */ + public function testCreate() + { + $customerEmail = uniqid() . '@example.org'; + $customerData = (object)array( + 'email' => $customerEmail, + 'firstname' => 'Firstname', + 'lastname' => 'Lastname', + 'password' => 'password', + 'website_id' => 0, + 'group_id' => 1 + ); + /** Create new customer. */ + $customerId = Magento_Test_Helper_Api::call( + $this, + 'customerCustomerCreate', + array('customerData' => $customerData) + ); + /** Load created customer. */ + /** @var Mage_Customer_Model_Customer $customer */ + $customer = Mage::getModel('Mage_Customer_Model_Customer'); + $customer->load($customerId); + /** Assert main customers fields are set. */ + $this->assertEquals($customerEmail, $customer->getEmail(), 'Customer email is not set.'); + $this->assertEquals('Firstname', $customer->getFirstname(), 'Customer first name is not set.'); + $this->assertEquals('Lastname', $customer->getLastname(), 'Customer last name is not set.'); + } + + /** + * Test info method. + * + * @magentoDataFixture Mage/Customer/_files/customer.php + */ + public function testInfo() + { + $customerId = 1; + /** Retrieve customer data. */ + $customerData = Magento_Test_Helper_Api::call( + $this, + 'customerCustomerInfo', + array($customerId) + ); + /** Assert customer email is set. */ + $this->assertEquals('customer@example.com', $customerData['email'], 'Customer email is invalid.'); + /** Assert response contains base fields. */ + $expectedFields = array('customer_id', 'email', 'firstname', 'lastname', 'password_hash'); + $missingFields = array_diff_key($expectedFields, array_keys($customerData)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in response: %s.", implode(', ', $missingFields)) + ); + } + + /** + * Test list method. + * + * @magentoDataFixture Mage/Customer/_files/two_customers.php + */ + public function testList() + { + /** Retrieve the list of customers. */ + $customersList = Magento_Test_Helper_Api::call( + $this, + 'customerCustomerList', + array() + ); + /** Assert returned customers quantity. */ + $this->assertCount(2, $customersList, 'Returned customers quantity are wrong.'); + /** Assert response contains base fields. */ + $expectedFields = array('customer_id', 'email', 'firstname', 'lastname', 'password_hash'); + $customerData = reset($customersList); + $missingFields = array_diff_key($expectedFields, array_keys($customerData)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in response: %s.", implode(', ', $missingFields)) + ); + } + + /** + * Test update method. + * + * @magentoDataFixture Mage/Customer/_files/customer.php + */ + public function testUpdate() + { + $customerId = 1; + $updateCustomerData = (object)array( + 'firstname' => 'new_firstname', + 'email' => 'new_email@example.org' + ); + /** Update customer. */ + $updateResult = Magento_Test_Helper_Api::call( + $this, + 'customerCustomerUpdate', + array('customerId' => $customerId, 'customerData' => $updateCustomerData) + ); + /** Assert API update operation result. */ + $this->assertTrue($updateResult, 'Customer update is failed.'); + /** Assert fields are updated. */ + /** @var Mage_Customer_Model_Customer $customer */ + $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId); + $this->assertEquals( + 'new_firstname', + $customer->getFirstname(), + 'First name is not updated.' + ); + $this->assertEquals( + 'new_email@example.org', + $customer->getEmail(), + 'Email is not updated.' + ); + } + + /** + * Test delete method. + * + * @magentoDataFixture Mage/Customer/_files/customer.php + */ + public function testDelete() + { + $customerId = 1; + /** Delete customer. */ + $deleteResult = Magento_Test_Helper_Api::call( + $this, + 'customerCustomerDelete', + array('customerId' => $customerId) + ); + /** Assert delete operation result. */ + $this->assertTrue($deleteResult, 'Customer is not deleted.'); + /** Assert customer is deleted. */ + /** @var Mage_Customer_Model_Customer $customer */ + $customer = Mage::getModel('Mage_Customer_Model_Customer')->load($customerId); + $this->assertNull($customer->getEntityId()); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Customer/Model/Group/ApiTest.php b/dev/tests/integration/testsuite/Mage/Customer/Model/Group/ApiTest.php new file mode 100644 index 00000000000..1c89ba13d65 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Customer/Model/Group/ApiTest.php @@ -0,0 +1,46 @@ +<?php +/** + * Test customer group Api. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Customer_Model_Group_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test item method. + */ + public function testList() + { + /** Retrieve the list of customer groups. */ + $groupsList = Magento_Test_Helper_Api::call($this, 'customerGroupList', array()); + /** Assert customers group list is not empty. */ + $this->assertNotEmpty($groupsList, 'Customers list retrieving was unsuccessful.'); + /** Assert base fields are present in the response. */ + $groupInfo = reset($groupsList); + $expectedFields = array('customer_group_id', 'customer_group_code'); + $missingFields = array_diff($expectedFields, array_keys($groupInfo)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in response: %s.", implode(', ', $missingFields)) + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Customer/_files/customer_address.php b/dev/tests/integration/testsuite/Mage/Customer/_files/customer_address.php index 0202e67f88a..f48cb6ec0e9 100644 --- a/dev/tests/integration/testsuite/Mage/Customer/_files/customer_address.php +++ b/dev/tests/integration/testsuite/Mage/Customer/_files/customer_address.php @@ -26,6 +26,7 @@ /** @var Mage_Customer_Model_Address $customerAddress */ $customerAddress = Mage::getModel('Mage_Customer_Model_Address'); +$customerAddress->isObjectNew(true); $customerAddress->setCustomerId(1) ->setData(array( 'entity_id' => 1, @@ -36,7 +37,6 @@ $customerAddress->setCustomerId(1) 'street' => 'Green str, 67', 'lastname' => 'Smith', 'firstname' => 'John', - 'parent_id' => 1, - 'created_at' => date('YYY-MM-DD hh:mm:ss') + 'parent_id' => 1 )); $customerAddress->save(); diff --git a/dev/tests/integration/testsuite/Mage/Customer/_files/customer_two_addresses.php b/dev/tests/integration/testsuite/Mage/Customer/_files/customer_two_addresses.php index e25d22008ea..f442029147d 100644 --- a/dev/tests/integration/testsuite/Mage/Customer/_files/customer_two_addresses.php +++ b/dev/tests/integration/testsuite/Mage/Customer/_files/customer_two_addresses.php @@ -28,6 +28,7 @@ require 'customer_address.php'; /** @var Mage_Customer_Model_Address $customerAddress */ $customerAddress = Mage::getModel('Mage_Customer_Model_Address'); +$customerAddress->isObjectNew(true); $customerAddress->setCustomerId(1) ->setData(array( 'entity_id' => 2, @@ -38,7 +39,6 @@ $customerAddress->setCustomerId(1) 'street' => 'Black str, 48', 'lastname' => 'Smith', 'firstname' => 'John', - 'parent_id' => 1, - 'created_at' => date('YYY-MM-DD hh:mm:ss') + 'parent_id' => 1 )); $customerAddress->save(); diff --git a/dev/tests/integration/testsuite/Mage/Customer/_files/two_customers.php b/dev/tests/integration/testsuite/Mage/Customer/_files/two_customers.php new file mode 100644 index 00000000000..85194571644 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Customer/_files/two_customers.php @@ -0,0 +1,45 @@ +<?php +/** + * Fixture for Customer List method. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +require 'customer.php'; + +$customer = Mage::getModel('Mage_Customer_Model_Customer'); +$customer + ->setWebsiteId(1) + ->setEntityId(2) + ->setEntityTypeId(1) + ->setAttributeSetId(0) + ->setEmail('customer_two@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/Mage/Directory/Model/Country/ApiTest.php b/dev/tests/integration/testsuite/Mage/Directory/Model/Country/ApiTest.php new file mode 100644 index 00000000000..89f8dcef17a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Directory/Model/Country/ApiTest.php @@ -0,0 +1,43 @@ +<?php +/** + * Directory country API test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Directory_Model_Country_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test 'items' method of directory country API. + */ + public function testList() + { + $countries = Magento_Test_Helper_Api::call($this, 'directoryCountryList'); + $this->assertGreaterThan(200, count($countries), "The list of countries seems to be not full."); + $countryData = reset($countries); + $expectedFields = array('country_id', 'iso2_code', 'iso3_code', 'name'); + $missingFields = array_diff($expectedFields, array_keys($countryData)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in country data: %s.", implode(', ', $missingFields)) + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Directory/Model/Region/ApiTest.php b/dev/tests/integration/testsuite/Mage/Directory/Model/Region/ApiTest.php new file mode 100644 index 00000000000..906da30f39d --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Directory/Model/Region/ApiTest.php @@ -0,0 +1,43 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** + * Test Directory Region operations + */ +class Mage_Directory_Model_Region_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test directoryRegionList API method + */ + public function testList() + { + $data = Magento_Test_Helper_Api::call($this, 'directoryRegionList', array('country' => 'US')); + $this->assertTrue(is_array($data), 'Region list is not array'); + $this->assertNotEmpty($data, 'Region list is empty'); + $region = reset($data); + $this->assertTrue( + is_string($region['name']) && strlen($region['name']), + 'Region name is empty or not a string' + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Eav/Block/Adminhtml/Attribute/Edit/Main/AbstractTest.php b/dev/tests/integration/testsuite/Mage/Eav/Block/Adminhtml/Attribute/Edit/Main/AbstractTest.php index 17bb6ebd4da..477d27ce120 100644 --- a/dev/tests/integration/testsuite/Mage/Eav/Block/Adminhtml/Attribute/Edit/Main/AbstractTest.php +++ b/dev/tests/integration/testsuite/Mage/Eav/Block/Adminhtml/Attribute/Edit/Main/AbstractTest.php @@ -54,6 +54,8 @@ class Mage_Eav_Block_Adminhtml_Attribute_Edit_Main_AbstractTest Mage::getObjectManager()->get('Mage_Core_Model_Store_Config'), Mage::getObjectManager()->get('Mage_Core_Controller_Varien_Front'), Mage::getObjectManager()->get('Mage_Core_Model_Factory_Helper'), + Mage::getObjectManager()->get('Mage_Core_Model_Dir'), + Mage::getObjectManager()->get('Mage_Core_Model_Logger'), Mage::getObjectManager()->get('Magento_Filesystem'), ); $block = $this->getMockForAbstractClass('Mage_Eav_Block_Adminhtml_Attribute_Edit_Main_Abstract', $arguments) diff --git a/dev/tests/integration/testsuite/Mage/GiftMessage/Model/ApiTest.php b/dev/tests/integration/testsuite/Mage/GiftMessage/Model/ApiTest.php new file mode 100644 index 00000000000..24de10e28ae --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/GiftMessage/Model/ApiTest.php @@ -0,0 +1,167 @@ +<?php +/** + * Test case for gift message assigning to the shopping cart via API. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_GiftMessage_Model_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test setting gift message fot the whole shopping cart. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testSetForQuote() + { + /** Prepare data. */ + $quoteId = $this->_getQuote()->getId(); + + /** Call tested method. */ + $status = Magento_Test_Helper_Api::call( + $this, + 'giftMessageSetForQuote', + array($quoteId, $this->_getGiftMessageData()) + ); + $expectedStatus = array('entityId' => $quoteId, 'result' => true, 'error' => ''); + $this->assertEquals($expectedStatus, (array)$status, 'Gift message was not added to the quote.'); + + /** Ensure that messages were actually added and saved to DB. */ + /** @var Mage_Sales_Model_Quote $updatedQuote */ + $updatedQuote = Mage::getModel('Mage_Sales_Model_Quote')->load($quoteId); + $this->assertGreaterThan(0, (int)$updatedQuote->getGiftMessageId(), "Gift message was not added."); + $this->_checkCreatedGiftMessage($updatedQuote->getGiftMessageId(), $this->_getGiftMessageData()); + } + + /** + * Test setting gift message fot the specific quote item. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testSetForQuoteItem() + { + /** Prepare data. */ + $quoteItems = $this->_getQuote()->getAllItems(); + /** @var Mage_Sales_Model_Quote_Item $quoteItem */ + $quoteItem = reset($quoteItems); + + /** Call tested method. */ + $status = Magento_Test_Helper_Api::call( + $this, + 'giftMessageSetForQuoteItem', + array($quoteItem->getId(), $this->_getGiftMessageData()) + ); + $expectedStatus = array('entityId' => $quoteItem->getId(), 'result' => true, 'error' => ''); + $this->assertEquals($expectedStatus, (array)$status, 'Gift message was not added to the quote.'); + + /** Ensure that messages were actually added and saved to DB. */ + /** @var Mage_Sales_Model_Quote_Item $updatedQuoteItem */ + $updatedQuoteItem = Mage::getModel('Mage_Sales_Model_Quote_Item')->load($quoteItem->getId()); + $this->assertGreaterThan(0, (int)$updatedQuoteItem->getGiftMessageId(), "Gift message was not added."); + $this->_checkCreatedGiftMessage($updatedQuoteItem->getGiftMessageId(), $this->_getGiftMessageData()); + + } + + /** + * Test setting gift message fot the specified products in shopping cart. + * + * @magentoDataFixture Mage/Checkout/_files/quote_with_simple_product.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testSetForQuoteProduct() + { + /** Prepare data. */ + $quoteItems = $this->_getQuote()->getAllItems(); + /** @var Mage_Sales_Model_Quote_Item $quoteItem */ + $quoteItem = reset($quoteItems); + + /** Call tested method. */ + $status = Magento_Test_Helper_Api::call( + $this, + 'giftMessageSetForQuoteProduct', + array( + $this->_getQuote()->getId(), + array( + (object)array( + 'product' => (object)array('product_id' => $quoteItem->getProductId()), + 'message' => $this->_getGiftMessageData() + ) + ) + ) + ); + $expectedStatus = array((object)array('entityId' => $quoteItem->getId(), 'result' => true, 'error' => '')); + $this->assertEquals($expectedStatus, $status, 'Gift message was not added to the quote.'); + + /** Ensure that messages were actually added and saved to DB. */ + /** @var Mage_Sales_Model_Quote_Item $updatedQuoteItem */ + $updatedQuoteItem = Mage::getModel('Mage_Sales_Model_Quote_Item')->load($quoteItem->getId()); + $this->assertGreaterThan(0, (int)$updatedQuoteItem->getGiftMessageId(), "Gift message was not added."); + $this->_checkCreatedGiftMessage($updatedQuoteItem->getGiftMessageId(), $this->_getGiftMessageData()); + } + + /** + * Prepare gift message data for tests. + * + * @return object + */ + protected function _getGiftMessageData() + { + $giftMessageData = (object)array( + 'from' => 'from@null.null', + 'to' => 'to@null.null', + 'message' => 'Gift message content.' + ); + return $giftMessageData; + } + + /** + * Ensure that added gift message was successfully stored in DB. + * + * @param int $giftMessageId + * @param object $giftMessageData + */ + protected function _checkCreatedGiftMessage($giftMessageId, $giftMessageData) + { + $giftMessage = Mage::getModel('Mage_GiftMessage_Model_Message')->load($giftMessageId); + $this->assertEquals($giftMessageData->message, $giftMessage['message'], 'Message stored in DB is invalid.'); + $this->assertEquals($giftMessageData->to, $giftMessage['recipient'], 'Recipient stored in DB is invalid.'); + $this->assertEquals($giftMessageData->from, $giftMessage['sender'], 'Sender stored in DB is invalid.'); + } + + /** + * Retrieve quote created in fixture. + * + * @return Mage_Sales_Model_Quote + */ + protected function _getQuote() + { + /** @var $session Mage_Checkout_Model_Session */ + $session = Mage::getModel('Mage_Checkout_Model_Session'); + /** @var Mage_Sales_Model_Quote $quote */ + $quote = $session->getQuote(); + return $quote; + } +} diff --git a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Export/Entity/ProductTest.php b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Export/Entity/ProductTest.php index 90f3cd1da10..ab1f0ee49fe 100644 --- a/dev/tests/integration/testsuite/Mage/ImportExport/Model/Export/Entity/ProductTest.php +++ b/dev/tests/integration/testsuite/Mage/ImportExport/Model/Export/Entity/ProductTest.php @@ -154,7 +154,6 @@ class Mage_ImportExport_Model_Export_Entity_ProductTest extends PHPUnit_Framewor * Verify header columns (that stock item attributes column headers are present) * * @param array $headerColumns - * @return void */ public function verifyHeaderColumns(array $headerColumns) { @@ -169,7 +168,6 @@ class Mage_ImportExport_Model_Export_Entity_ProductTest extends PHPUnit_Framewor * Verify row data (stock item attribute values) * * @param array $rowData - * @return void */ public function verifyRow(array $rowData) { diff --git a/dev/tests/integration/testsuite/Mage/Index/Model/Process/FileTest.php b/dev/tests/integration/testsuite/Mage/Index/Model/Process/FileTest.php index 3c993f0710d..e786cfb1139 100644 --- a/dev/tests/integration/testsuite/Mage/Index/Model/Process/FileTest.php +++ b/dev/tests/integration/testsuite/Mage/Index/Model/Process/FileTest.php @@ -59,9 +59,9 @@ class Mage_Index_Model_Process_FileTest extends PHPUnit_Framework_TestCase { $this->_objectManager = Mage::getObjectManager(); $this->_model = $this->_objectManager->create('Mage_Index_Model_Process_File'); - /** @var $configuration Mage_Core_Model_Config */ - $configuration = $this->_objectManager->get('Mage_Core_Model_Config'); - $this->_fileDirectory = $configuration->getVarDir('locks'); + /** @var $dir Mage_Core_Model_Dir */ + $dir = $this->_objectManager->get('Mage_Core_Model_Dir'); + $this->_fileDirectory = $dir->getDir(Mage_Core_Model_Dir::VAR_DIR) . DIRECTORY_SEPARATOR . 'locks'; $fullFileName = $this->_fileDirectory . DIRECTORY_SEPARATOR . self::FILE_NAME; $this->_testFileHandler = fopen($fullFileName, 'w'); } diff --git a/dev/tests/integration/testsuite/Mage/Install/IndexControllerTest.php b/dev/tests/integration/testsuite/Mage/Install/IndexControllerTest.php new file mode 100644 index 00000000000..f731b954c24 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Install/IndexControllerTest.php @@ -0,0 +1,39 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Install_IndexControllerTest extends Magento_Test_TestCase_ControllerAbstract +{ + public function testIndexAction() + { + $this->dispatch('install/index/index'); + $request = $this->getRequest(); + $this->assertEquals('begin', $request->getActionName()); + $this->assertEquals('wizard', $request->getControllerName()); + $this->assertEquals('install', $request->getModuleName()); + /** + * Make sure that preDispatch() didn't cleanup var directory (by asserting presence of anything there), + * because in integration testing environment the application is considered "installed" + */ + $this->assertFileExists(Mage::getBaseDir(Mage_Core_Model_Dir::TMP)); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Install/Model/Installer/ConfigTest.php b/dev/tests/integration/testsuite/Mage/Install/Model/Installer/ConfigTest.php new file mode 100644 index 00000000000..fe5a40f947f --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Install/Model/Installer/ConfigTest.php @@ -0,0 +1,70 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Install_Model_Installer_ConfigTest extends PHPUnit_Framework_TestCase +{ + /** + * @var string + */ + protected static $_tmpDir = ''; + + public static function setUpBeforeClass() + { + self::$_tmpDir = Mage::getBaseDir(Mage_Core_Model_Dir::VAR_DIR) . DIRECTORY_SEPARATOR . __CLASS__; + mkdir(self::$_tmpDir); + } + + public static function tearDownAfterClass() + { + Varien_Io_File::rmdirRecursive(self::$_tmpDir); + } + + public function testInstall() + { + file_put_contents(self::$_tmpDir . '/local.xml.template', "test; {{date}}; {{base_url}}; {{unknown}}"); + $expectedFile = self::$_tmpDir . '/local.xml'; + + $config = $this->getMock('Mage_Core_Model_Config', array('getDistroBaseUrl'), array(), '', false); + $config->expects($this->once())->method('getDistroBaseUrl')->will($this->returnValue('http://example.com/')); + $expectedContents = "test; <![CDATA[d-d-d-d-d]]>; <![CDATA[http://example.com/]]>; {{unknown}}"; + $dirs = new Mage_Core_Model_Dir(self::$_tmpDir, array(), array(Mage_Core_Model_Dir::CONFIG => self::$_tmpDir)); + + $this->assertFileNotExists($expectedFile); + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + $model = new Mage_Install_Model_Installer_Config($config, $dirs, $filesystem); + $model->install(); + $this->assertFileExists($expectedFile); + $this->assertStringEqualsFile($expectedFile, $expectedContents); + } + + public function testGetFormData() + { + /** @var $model Mage_Install_Model_Installer_Config */ + $model = Mage::getModel('Mage_Install_Model_Installer_Config'); + /** @var $result Varien_Object */ + $result = $model->getFormData(); + $this->assertInstanceOf('Varien_Object', $result); + $data = $result->getData(); + $this->assertArrayHasKey('db_host', $data); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Install/controllers/WizardControllerTest.php b/dev/tests/integration/testsuite/Mage/Install/controllers/WizardControllerTest.php index aaae218c7ed..bc7771d6842 100644 --- a/dev/tests/integration/testsuite/Mage/Install/controllers/WizardControllerTest.php +++ b/dev/tests/integration/testsuite/Mage/Install/controllers/WizardControllerTest.php @@ -30,59 +30,53 @@ class Mage_Install_WizardControllerTest extends Magento_Test_TestCase_Controller /** * @var string */ - protected static $_tmpMediaDir; + protected static $_mediaDir; /** * @var string */ - protected static $_tmpThemeDir; + protected static $_themeDir; public static function setUpBeforeClass() { parent::setUpBeforeClass(); - self::$_tmpMediaDir = realpath(Magento_Test_Bootstrap::getInstance()->getTmpDir()) - . DIRECTORY_SEPARATOR . 'media'; - self::$_tmpThemeDir = self::$_tmpMediaDir . DIRECTORY_SEPARATOR . 'theme'; + self::$_mediaDir = Mage::getBaseDir(Mage_Core_Model_Dir::MEDIA); + self::$_themeDir = self::$_mediaDir . DIRECTORY_SEPARATOR . 'theme'; } public function setUp() { parent::setUp(); // emulate non-installed application - $this->_runOptions[Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_DATA] + $this->_runOptions[Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA] = sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'invalid'); } public function tearDown() { - Varien_Io_File::rmdirRecursive(self::$_tmpMediaDir); + if (is_dir(self::$_mediaDir)) { + chmod(self::$_mediaDir, 0777); + } + if (is_dir(self::$_themeDir)) { + chmod(self::$_themeDir, 0777); + } parent::tearDown(); } - /** - * @magentoAppIsolation enabled - */ public function testPreDispatch() { - $this->dispatch('install/index'); + $this->dispatch('install/wizard'); $this->assertEquals(200, $this->getResponse()->getHttpResponseCode()); } public function testPreDispatchNonWritableMedia() { - mkdir(self::$_tmpMediaDir, 0444); - $this->_runOptions['media_dir'] = self::$_tmpMediaDir; - - $this->_testInstallProhibitedWhenNonWritable(self::$_tmpMediaDir); + $this->_testInstallProhibitedWhenNonWritable(self::$_mediaDir); } public function testPreDispatchNonWritableTheme() { - mkdir(self::$_tmpMediaDir, 0777); - $this->_runOptions['media_dir'] = self::$_tmpMediaDir; - - mkdir(self::$_tmpThemeDir, 0444); - $this->_testInstallProhibitedWhenNonWritable(self::$_tmpThemeDir); + $this->_testInstallProhibitedWhenNonWritable(self::$_themeDir); } /** @@ -93,13 +87,23 @@ class Mage_Install_WizardControllerTest extends Magento_Test_TestCase_Controller */ protected function _testInstallProhibitedWhenNonWritable($nonWritableDir) { + if (file_exists($nonWritableDir) && !is_dir($nonWritableDir)) { + $this->markTestSkipped("Incorrect file structure. $nonWritableDir should be a directory"); + } + + if (is_dir($nonWritableDir)) { + chmod($nonWritableDir, 0444); + } else { + mkdir($nonWritableDir, 0444); + } + if (is_writable($nonWritableDir)) { $this->markTestSkipped("Current OS doesn't support setting write-access for folders via mode flags"); } - $this->dispatch('install/index'); + $this->dispatch('install/wizard'); $this->assertEquals(503, $this->getResponse()->getHttpResponseCode()); - $this->assertContains(self::$_tmpThemeDir, $this->getResponse()->getBody()); + $this->assertContains(self::$_themeDir, $this->getResponse()->getBody()); } } diff --git a/dev/tests/integration/testsuite/Mage/Newsletter/Model/QueueTest.php b/dev/tests/integration/testsuite/Mage/Newsletter/Model/QueueTest.php index 8fb652ca4c2..6cbb315ac0e 100644 --- a/dev/tests/integration/testsuite/Mage/Newsletter/Model/QueueTest.php +++ b/dev/tests/integration/testsuite/Mage/Newsletter/Model/QueueTest.php @@ -29,13 +29,16 @@ class Mage_Newsletter_Model_QueueTest extends PHPUnit_Framework_TestCase { /** * @magentoDataFixture Mage/Newsletter/_files/queue.php - * @magentoConfigFixture current_store design/theme/full_name default/demo_blue - * @magentoConfigFixture fixturestore_store design/theme/full_name default/demo + * @magentoConfigFixture frontend/design/theme/full_name default/demo_blue * @magentoConfigFixture fixturestore_store general/locale/code de_DE * @magentoAppIsolation enabled */ public function testSendPerSubscriber() { + $collection = new Mage_Core_Model_Resource_Theme_Collection; + $themeId = $collection->getThemeByFullPath('frontend/default/demo')->getId(); + Mage::app()->getStore('fixturestore')->setConfig('design/theme/theme_id', $themeId); + $subscriberOne = $this->getMock('Zend_Mail', array('send', 'setBodyHTML'), array('utf-8')); $subscriberOne->expects($this->any())->method('send'); $subscriberTwo = clone $subscriberOne; diff --git a/dev/tests/integration/testsuite/Mage/Page/Block/HtmlTest.php b/dev/tests/integration/testsuite/Mage/Page/Block/HtmlTest.php new file mode 100644 index 00000000000..7eda712c0f0 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Page/Block/HtmlTest.php @@ -0,0 +1,81 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Page + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Page_Block_HtmlTest extends PHPUnit_Framework_TestCase +{ + /** + * + * @dataProvider getConfigValuesDataProvider + */ + public function testGetPrintLogoUrl($configData, $returnValue) + { + $storeConfig = $this->getMock('Mage_Core_Model_Store_Config'); + $storeConfig->expects($this->any()) + ->method('getConfig') + ->will($this->returnValueMap($configData)); + + $urlBuilder = $this->getMock('Mage_Core_Model_Url', array('getBaseUrl')); + $urlBuilder->expects($this->any()) + ->method('getBaseUrl') + ->will($this->returnValue('http://localhost/pub/media/')); + + $arguments = array( + 'storeConfig' => $storeConfig, + 'urlBuilder' => $urlBuilder, + ); + + $block = Mage::getObjectManager()->create('Mage_Page_Block_Html', $arguments); + + $this->assertEquals($returnValue, $block->getPrintLogoUrl()); + } + + public function getConfigValuesDataProvider() + { + return array( + 'sales_identity_logo_html' => array( + array(array('sales/identity/logo_html', null, 'image.gif')), + 'http://localhost/pub/media/sales/store/logo_html/image.gif' + ), + 'sales_identity_logo' => array( + array(array('sales/identity/logo', null, 'image.gif')), + 'http://localhost/pub/media/sales/store/logo/image.gif' + ), + 'sales_identity_logoTif' => array( + array(array('sales/identity/logo', null, 'image.tif')), + '' + ), + 'sales_identity_logoTiff' => array( + array(array('sales/identity/logo', null, 'image.tiff')), + '' + ), + 'no_logo' => array( + array(), + '' + ), + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Paypal/Adminhtml/Paypal/ReportsControllerTest.php b/dev/tests/integration/testsuite/Mage/Paypal/Adminhtml/Paypal/ReportsControllerTest.php new file mode 100644 index 00000000000..d2729f76afd --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Paypal/Adminhtml/Paypal/ReportsControllerTest.php @@ -0,0 +1,47 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Paypal_Adminhtml_Paypal_ReportsControllerTest extends Mage_Backend_Utility_Controller +{ + /** + * @magentoConfigFixture current_store paypal/fetch_reports/active 1 + * @magentoConfigFixture current_store paypal/fetch_reports/ftp_ip 127.0.0.1 + * @magentoConfigFixture current_store paypal/fetch_reports/ftp_path /tmp + * @magentoConfigFixture current_store paypal/fetch_reports/ftp_login login + * @magentoConfigFixture current_store paypal/fetch_reports/ftp_password password + * @magentoConfigFixture current_store paypal/fetch_reports/ftp_sandbox 0 + * @magentoDbIsolation enabled + */ + public function testFetchAction() + { + $this->dispatch('backend/admin/paypal_reports/fetch'); + /** @var $session Mage_Backend_Model_Session */ + $session = Mage::getSingleton('Mage_Backend_Model_Session'); + $this->assertEquals(1, $session->getMessages()->count()); + /** @var $message Mage_Core_Model_Message_Error */ + foreach ($session->getMessages() as $message) { + $this->assertInstanceOf('Mage_Core_Model_Message_Error', $message); + $this->assertContains('login@127.0.0.1', $message->getText()); + } + } +} diff --git a/dev/tests/integration/testsuite/Mage/Paypal/Model/Report/SettlementTest.php b/dev/tests/integration/testsuite/Mage/Paypal/Model/Report/SettlementTest.php new file mode 100644 index 00000000000..1420b3057a1 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Paypal/Model/Report/SettlementTest.php @@ -0,0 +1,63 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Paypal_Model_Report_SettlementTest extends PHPUnit_Framework_TestCase +{ + /** + * @magentoDbIsolation enabled + */ + public function testFetchAndSave() + { + /** @var $model Mage_Paypal_Model_Report_Settlement; */ + $model = Mage::getModel('Mage_Paypal_Model_Report_Settlement'); + $connection = $this->getMock('Varien_Io_Sftp', array('rawls', 'read'), array(), '', false); + $filename = 'STL-00000000.00.abc.CSV'; + $connection->expects($this->once())->method('rawls')->will($this->returnValue(array($filename => array()))); + $connection->expects($this->once())->method('read')->with($filename, $this->anything()); + $model->fetchAndSave($connection); + } + + /** + * @param array $config + * @expectedException InvalidArgumentException + * @dataProvider createConnectionExceptionDataProvider + */ + public function testCreateConnectionException($config) + { + Mage_Paypal_Model_Report_Settlement::createConnection($config); + } + + /** + * @return array + */ + public function createConnectionExceptionDataProvider() + { + return array( + array(array()), + array(array('username' => 'test', 'password' => 'test', 'path' => '/')), + array(array('hostname' => 'example.com', 'password' => 'test', 'path' => '/')), + array(array('hostname' => 'example.com', 'username' => 'test', 'path' => '/')), + array(array('hostname' => 'example.com', 'username' => 'test', 'password' => 'test')), + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer.php new file mode 100644 index 00000000000..97cded705ab --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer.php @@ -0,0 +1,65 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +$customer = Mage::getModel('Mage_Customer_Model_Customer'); +$customer->setStoreId(1) + ->setCreatedIn('Default Store View') + ->setDefaultBilling(1) + ->setDefaultShipping(1) + ->setEmail('mr.test.creditmemo.' . uniqid() . '@test.com') + ->setFirstname('Test') + ->setLastname('Test') + ->setMiddlename('Test') + ->setGroupId(1) + ->setRewardUpdateNotification(1) + ->setRewardWarningNotification(1) + ->save(); +Mage::register('customer', $customer); + +$customerAddress = Mage::getModel('Mage_Customer_Model_Address'); +$customerAddress->setData( + array( + 'city' => 'New York', + 'country_id' => 'US', + 'fax' => '56-987-987', + 'firstname' => 'Jacklin', + 'lastname' => 'Sparrow', + 'middlename' => 'John', + 'postcode' => '10012', + 'region' => 'New York', + 'region_id' => '43', + 'street' => 'Main Street', + 'telephone' => '718-452-9207', + 'is_default_billing' => true, + 'is_default_shipping' => true + ) +); +$customerAddress->setCustomer($customer); +$customerAddress->save(); +Mage::register('customer_address', $customerAddress); + +//Set customer default shipping and billing address +$customer->addAddress($customerAddress); +$customer->setDefaultShipping($customerAddress->getId()); +$customer->setDefaultBilling($customerAddress->getId()); +$customer->save(); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer_rollback.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer_rollback.php new file mode 100644 index 00000000000..0b0a82e14d6 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/customer_rollback.php @@ -0,0 +1,25 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +Mage::unregister('customer'); +Mage::unregister('customer_address'); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices.php new file mode 100644 index 00000000000..a48ea09a908 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices.php @@ -0,0 +1,50 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +if (!Mage::registry('order')) { + require 'order.php'; +} +/** @var $order Mage_Sales_Model_Order */ +$order = Mage::registry('order'); + +$orderService = new Mage_Sales_Model_Service_Order($order); +$invoice = $orderService->prepareInvoice(); +$invoice->register(); +$invoice->getOrder()->setIsInProcess(true); +$transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction'); +$transactionSave->addObject($invoice) + ->addObject($invoice->getOrder()) + ->save(); + +Mage::register('invoice', $invoice); +$order2 = Mage::registry('order2'); +$orderService2 = new Mage_Sales_Model_Service_Order($order2); +$invoice2 = $orderService2->prepareInvoice(); +$invoice2->register(); +$invoice2->getOrder()->setIsInProcess(true); +$transactionSave2 = Mage::getModel('Mage_Core_Model_Resource_Transaction'); +$transactionSave2->addObject($invoice2) + ->addObject($invoice2->getOrder()) + ->save(); + +Mage::register('invoice2', $invoice2); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices_rollback.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices_rollback.php new file mode 100644 index 00000000000..524f9439451 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/multiple_invoices_rollback.php @@ -0,0 +1,25 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +Mage::unregister('invoice'); +Mage::unregister('invoice2'); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order.php new file mode 100644 index 00000000000..f84998f168a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order.php @@ -0,0 +1,78 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +//Set up customer fixture +require 'customer.php'; +/** @var $customer Mage_Customer_Model_Customer */ +$customer = Mage::registry('customer'); +//Set up virtual product fixture +require 'product_virtual.php'; +/** @var $product Mage_Catalog_Model_Product */ +$product = Mage::registry('product_virtual'); + +//Create quote +$quote = Mage::getModel('Mage_Sales_Model_Quote'); +$quote->setStoreId(1) + ->setCustomerEmail($customer->getEmail()) + ->setIsActive(false) + ->setIsMultiShipping(false) + ->assignCustomerWithAddressChange($customer) + ->setCheckoutMethod($customer->getMode()) + ->setPasswordHash($customer->encryptPassword($customer->getPassword())) + ->addProduct($product->load($product->getId()), 2); + +$quote->collectTotals(); +$quote->save(); +Mage::register('quote', $quote); + +//Create order +$quoteService = new Mage_Sales_Model_Service_Quote($quote); +//Set payment method to check/money order +$quoteService->getQuote()->getPayment()->setMethod('checkmo'); +$order = $quoteService->submitOrder(); +$order->place(); +$order->save(); +Mage::register('order', $order); + +//Create order +$quote2 = Mage::getModel('Mage_Sales_Model_Quote'); +$quote2->setStoreId(1) + ->setCustomerEmail($customer->getEmail()) + ->setIsActive(false) + ->setIsMultiShipping(false) + ->assignCustomerWithAddressChange($customer) + ->setCheckoutMethod($customer->getMode()) + ->setPasswordHash($customer->encryptPassword($customer->getPassword())) + ->addProduct($product->load($product->getId()), 2); + +$quote2->collectTotals(); +$quote2->save(); +Mage::register('quote2', $quote2); + +$quoteService2 = new Mage_Sales_Model_Service_Quote($quote2); +//Set payment method to check/money order +$quoteService2->getQuote()->getPayment()->setMethod('checkmo'); +$order2 = $quoteService2->submitOrder(); +$order2->place(); +$order2->save(); +Mage::register('order2', $order2); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_rollback.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_rollback.php new file mode 100644 index 00000000000..b2ff2ba6d18 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_rollback.php @@ -0,0 +1,28 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('quote'); +Mage::unregister('order'); +Mage::unregister('quote2'); +Mage::unregister('order2'); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping.php new file mode 100644 index 00000000000..04a70899b26 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping.php @@ -0,0 +1,71 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +//Set up customer fixture +require 'customer.php'; +/** @var $customer Mage_Customer_Model_Customer */ +//Set up customer address fixture +$customer = Mage::registry('customer'); +/** @var $customerAddress Mage_Customer_Model_Address */ +$customerAddress = Mage::registry('customer_address'); +/*//$customerAddress->addShippingRate($rate); +$customerAddress->setShippingMethod('freeshipping_freeshipping'); +$customerAddress->addShippingRate($method); //$rate +$customerAddress->save();*/ + +//Set up simple product fixture +require 'product_simple.php'; +/** @var $product Mage_Catalog_Model_Product */ +$product = Mage::registry('product_simple'); + + +//Create quote +$quote = Mage::getModel('Mage_Sales_Model_Quote'); +$quote->setStoreId(1) + ->setIsActive(false) + ->setIsMultiShipping(false) + ->assignCustomerWithAddressChange($customer) + ->setCheckoutMethod($customer->getMode()) + ->setPasswordHash($customer->encryptPassword($customer->getPassword())) + ->addProduct($product->load($product->getId()), 2); + +/** @var $rate Mage_Sales_Model_Quote_Address_Rate */ +$rate = Mage::getModel('Mage_Sales_Model_Quote_Address_Rate'); +$rate->setCode('freeshipping_freeshipping'); +$rate->getPrice(1); + +$quote->getShippingAddress()->setShippingMethod('freeshipping_freeshipping'); +$quote->getShippingAddress()->addShippingRate($rate); + +$quote->collectTotals(); +$quote->save(); +Mage::register('quote', $quote); + +//Create order +$quoteService = new Mage_Sales_Model_Service_Quote($quote); +//Set payment method to check/money order +$quoteService->getQuote()->getPayment()->setMethod('checkmo'); +$order = $quoteService->submitOrder(); +$order->place(); +$order->save(); +Mage::register('order', $order); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping_rollback.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping_rollback.php new file mode 100644 index 00000000000..e2696eca8f9 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/order_with_shipping_rollback.php @@ -0,0 +1,31 @@ +<?php +/** + * Fixture roll back logic. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('quote'); +Mage::unregister('order'); +Mage::unregister('product_simple'); +Mage::unregister('customer'); +Mage::unregister('customer_address'); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple.php new file mode 100644 index 00000000000..de2ce774043 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple.php @@ -0,0 +1,48 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +$product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->setTypeId('simple') + ->setAttributeSetId(4) + ->setStoreId(0) + ->setName('Simple Product') + ->setSku('simple-product-' . uniqid()) + ->setPrice(10) + ->setTaxClassId(0) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH) + ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED) + ->setStockData( + array( + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ) +) + ->save(); +// to make stock item visible from created product it should be reloaded +$product = Mage::getModel('Mage_Catalog_Model_Product')->load($product->getId()); +Mage::register('product_simple', $product); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple_rollback.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple_rollback.php new file mode 100644 index 00000000000..b34f865fafd --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_simple_rollback.php @@ -0,0 +1,24 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +Mage::unregister('product_simple'); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual.php new file mode 100644 index 00000000000..01041a27780 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual.php @@ -0,0 +1,46 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +$product = Mage::getModel('Mage_Catalog_Model_Product'); +$product->setTypeId('virtual') + ->setAttributeSetId(4) + ->setStoreId(0) + ->setName('Simple Product') + ->setSku('virtual-creditmemo-' . uniqid()) + ->setPrice(10) + ->setTaxClassId(0) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH) + ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_ENABLED) + ->setStockData( + array( + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ) +); +$product->save(); +Mage::register('product_virtual', $product); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual_rollback.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual_rollback.php new file mode 100644 index 00000000000..cc17167bae1 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/product_virtual_rollback.php @@ -0,0 +1,24 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +Mage::unregister('product_virtual'); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment.php new file mode 100644 index 00000000000..ad6bd240bc5 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment.php @@ -0,0 +1,35 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +include 'order_with_shipping.php'; +/** @var Mage_Sales_Model_Order $order */ + +$shipment = $order->prepareShipment(); +$shipment->register(); +$shipment->getOrder()->setIsInProcess(true); +/** @var Mage_Core_Model_Resource_Transaction $transaction */ +$transaction = Mage::getModel('Mage_Core_Model_Resource_Transaction'); +$transaction->addObject($shipment)->addObject($order)->save(); + +Mage::register('shipment', $shipment); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment_rollback.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment_rollback.php new file mode 100644 index 00000000000..16074db5ed9 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Api/_files/shipment_rollback.php @@ -0,0 +1,32 @@ +<?php +/** + * Fixture roll back logic. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +Mage::unregister('quote'); +Mage::unregister('order'); +Mage::unregister('product_simple'); +Mage::unregister('customer'); +Mage::unregister('customer_address'); +Mage::unregister('shipment'); diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/ApiTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/ApiTest.php new file mode 100644 index 00000000000..87d6411318a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/ApiTest.php @@ -0,0 +1,221 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** + * Test API getting orders list method + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/order.php + */ +class Mage_Sales_Model_Order_ApiTest extends PHPUnit_Framework_TestCase +{ + const STATUS_PENDING = 'pending'; + + /** + * Test info method of sales order API. + */ + public function testInfo() + { + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + $orderInfo = Magento_Test_Helper_Api::call( + $this, + 'salesOrderInfo', + array( + $order->getIncrementId() + ) + ); + /** Check availability of some important fields in response */ + $expectedArrayFields = array('shipping_address', 'billing_address', 'items', 'payment', 'status_history'); + $missingFields = array_diff($expectedArrayFields, array_keys($orderInfo)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in response: %s.", implode(', ', $missingFields)) + ); + + /** Check values of some fields received from order info */ + $fieldsToCompare = array( + 'entity_id' => 'order_id', + 'state', + 'status', + 'customer_id', + 'store_id', + 'base_grand_total', + 'increment_id', + 'customer_email', + 'order_currency_code' + ); + + Magento_Test_Helper_Api::checkEntityFields($this, $order->getData(), $orderInfo, $fieldsToCompare); + } + + /** + * Test 'addComment' method of sales order API. + */ + public function testAddComment() + { + $this->markTestSkipped("Skipped due to bug in addComment implementation: MAGETWO-6895."); + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + + $historySizeBefore = count($order->getAllStatusHistory()); + $newOrderStatus = self::STATUS_PENDING; + $statusChangeComment = "Order status change comment."; + $isAdded = Magento_Test_Helper_Api::call( + $this, + 'salesOrderAddComment', + array( + $order->getIncrementId(), + $newOrderStatus, + $statusChangeComment, + true + ) + ); + $this->assertTrue($isAdded, "Comment was not added"); + + /** @var Mage_Sales_Model_Order $orderAfter */ + $orderAfter = Mage::getModel('Mage_Sales_Model_Order')->load($order->getId()); + $historyAfter = $orderAfter->getAllStatusHistory(); + $this->assertCount($historySizeBefore + 1, $historyAfter, "History item was not created."); + /** @var Mage_Sales_Model_Order_Status_History $createdHistoryItem */ + $createdHistoryItem = end($historyAfter); + $this->assertEquals($statusChangeComment, $createdHistoryItem->getComment(), 'Comment is invalid.'); + } + + /** + * Test getting sales order list in other methods + */ + public function testList() + { + if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { + $this->markTestIncomplete('Legacy API is expected to support MySQL only.'); + } + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + + $filters = array( + 'filters' => (object)array( + 'filter' => array( + (object)array('key' => 'status', 'value' => $order->getData('status')), + (object)array('key' => 'created_at', 'value' => $order->getData('created_at')) + ), + 'complex_filter' => array( + (object)array( + 'key' => 'order_id', + 'value' => (object)array('key' => 'in', 'value' => "{$order->getId()},0") + ), + array( + 'key' => 'protect_code', + 'value' => (object)array('key' => 'in', 'value' => $order->getData('protect_code')) + ) + ) + ) + ); + + $result = Magento_Test_Helper_Api::call($this, 'salesOrderList', $filters); + + if (!isset($result[0])) { // workaround for WS-I + $result = array($result); + } + //should be got array with one order item + $this->assertInternalType('array', $result); + $this->assertEquals(1, count($result)); + $this->assertEquals($order->getId(), $result[0]['order_id']); + } + + /** + * Test for salesOrderCancel when order is in 'pending' status + */ + public function testCancelPendingOrder() + { + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + + $order->setStatus(self::STATUS_PENDING) + ->save(); + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'salesOrderCancel', + array( + 'orderIncrementId' => $order->getIncrementId() + ) + ); + + $this->assertTrue((bool)$soapResult, 'API call result in not TRUE'); + + // reload order to obtain new status + $order->load($order->getId()); + + $this->assertEquals(Mage_Sales_Model_Order::STATE_CANCELED, $order->getStatus(), 'Status is not CANCELED'); + } + + /** + * Test for salesOrderHold when order is in 'processing' status + */ + public function testHoldProcessingOrder() + { + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + + $order->setState(Mage_Sales_Model_Order::STATE_NEW, self::STATUS_PENDING) + ->save(); + + $soapResult = Magento_Test_Helper_Api::call( + $this, + 'salesOrderHold', + array( + 'orderIncrementId' => $order->getIncrementId() + ) + ); + + $this->assertTrue((bool)$soapResult, 'API call result in not TRUE'); + + // reload order to obtain new status + $order->load($order->getId()); + + $this->assertEquals(Mage_Sales_Model_Order::STATE_HOLDED, $order->getStatus(), 'Status is not HOLDED'); + } + + /** + * Test for 'unhold' method of sales order API. + * + * @depends testHoldProcessingOrder + */ + public function testUnhold() + { + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + $isUnholded = Magento_Test_Helper_Api::call( + $this, + 'salesOrderUnhold', + array( + $order->getIncrementId() + ) + ); + $this->assertTrue($isUnholded, "The order was not unholded."); + /** @var Mage_Sales_Model_Order $updatedOrder */ + $updatedOrder = Mage::getModel('Mage_Sales_Model_Order'); + $updatedOrder->load($order->getId()); + $this->assertEquals(self::STATUS_PENDING, $updatedOrder->getStatus(), 'Order was not unholded.'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Creditmemo/ApiTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Creditmemo/ApiTest.php new file mode 100644 index 00000000000..c3ed61fe52a --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Creditmemo/ApiTest.php @@ -0,0 +1,357 @@ +<?php +/** + * Creditmemo API model test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Sales_Model_Order_Creditmemo_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test sales order credit memo list, info, create, cancel + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/multiple_invoices.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ + public function testCRUD() + { + $creditmemoInfo = $this->_createCreditmemo(); + list($product, $qtys, $adjustmentPositive, $adjustmentNegative, $creditMemoIncrement) = $creditmemoInfo; + + //Test list + $creditmemoList = Magento_Test_Helper_Api::call($this, 'salesOrderCreditmemoList'); + $this->assertInternalType('array', $creditmemoList); + $this->assertNotEmpty($creditmemoList, 'Creditmemo list is empty'); + + //Test add comment + $commentText = 'Creditmemo comment'; + $this->assertTrue( + (bool)Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoAddComment', + array( + 'creditmemoIncrementId' => $creditMemoIncrement, + 'comment' => $commentText + ) + ) + ); + + //Test info + $creditmemoInfo = Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoInfo', + array( + 'creditmemoIncrementId' => $creditMemoIncrement + ) + ); + + $this->assertInternalType('array', $creditmemoInfo); + $this->assertNotEmpty($creditmemoInfo); + $this->assertEquals($creditMemoIncrement, $creditmemoInfo['increment_id']); + + //Test adjustments fees were added + $this->assertEquals($adjustmentPositive, $creditmemoInfo['adjustment_positive']); + $this->assertEquals($adjustmentNegative, $creditmemoInfo['adjustment_negative']); + + //Test order items were refunded + $this->assertArrayHasKey('items', $creditmemoInfo); + $this->assertInternalType('array', $creditmemoInfo['items']); + $this->assertGreaterThan(0, count($creditmemoInfo['items'])); + + if (!isset($creditmemoInfo['items'][0])) { // workaround for WSI plain array response + $creditmemoInfo['items'] = array($creditmemoInfo['items']); + } + + $this->assertEquals($creditmemoInfo['items'][0]['order_item_id'], $qtys[0]['order_item_id']); + $this->assertEquals($product->getId(), $creditmemoInfo['items'][0]['product_id']); + + if (!isset($creditmemoInfo['comments'][0])) { // workaround for WSI plain array response + $creditmemoInfo['comments'] = array($creditmemoInfo['comments']); + } + + //Test comment was added correctly + $this->assertArrayHasKey('comments', $creditmemoInfo); + $this->assertInternalType('array', $creditmemoInfo['comments']); + $this->assertGreaterThan(0, count($creditmemoInfo['comments'])); + $this->assertEquals($commentText, $creditmemoInfo['comments'][0]['comment']); + + //Test cancel + //Situation when creditmemo is possible to cancel was not found + $this->setExpectedException('SoapFault'); + Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoCancel', + array('creditmemoIncrementId' => $creditMemoIncrement) + ); + } + + /** + * Test Exception when refund amount greater than available to refund amount + * + * @expectedException SoapFault + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/multiple_invoices.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ + public function testNegativeRefundException() + { + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + $overRefundAmount = $order->getGrandTotal() + 10; + + Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoCreate', + array( + 'creditmemoIncrementId' => $order->getIncrementId(), + 'creditmemoData' => (object)array( + 'adjustment_positive' => $overRefundAmount + ) + ) + ); + } + + /** + * Test filtered list empty if filter contains incorrect order id + */ + public function testListEmptyFilter() + { + $filter = array( + 'filter' => array((object)array('key' => 'order_id', 'value' => 'invalid-id')) + ); + $creditmemoList = Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoList', + (object)array('filters' => $filter) + ); + $this->assertEquals(0, count($creditmemoList)); + } + + /** + * Test Exception on invalid creditmemo create data + * + * @expectedException SoapFault + */ + public function testCreateInvalidOrderException() + { + Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoCreate', + array( + 'orderIncrementId' => 'invalid-id', + 'creditmemoData' => array() + ) + ); + } + + /** + * Test Exception on invalid credit memo while adding comment + * + * @expectedException SoapFault + */ + public function testAddCommentInvalidCreditmemoException() + { + Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoAddComment', + array( + 'creditmemoIncrementId' => 'invalid-id', + 'comment' => 'Comment' + ) + ); + } + + /** + * Test Exception on invalid credit memo while getting info + * + * @expectedException SoapFault + */ + public function testInfoInvalidCreditmemoException() + { + Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoInfo', + array('creditmemoIncrementId' => 'invalid-id') + ); + } + + /** + * Test exception on invalid credit memo cancel + * + * @expectedException SoapFault + */ + public function testCancelInvalidIdException() + { + Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoCancel', + array('creditmemoIncrementId' => 'invalid-id') + ); + } + + /** + * Test credit memo create API call results + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/multiple_invoices.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ + public function testAutoIncrementType() + { + // Set creditmemo increment id prefix + $prefix = '01'; + Magento_Test_Helper_Eav::setIncrementIdPrefix('creditmemo', $prefix); + + $order = Mage::registry('order2'); + + $orderItems = $order->getAllItems(); + $qtys = array(); + + /** @var $orderItem Mage_Sales_Model_Order_Item */ + foreach ($orderItems as $orderItem) { + $qtys[] = array('order_item_id' => $orderItem->getId(), 'qty' => 1); + } + $adjustmentPositive = 2; + $adjustmentNegative = 1; + $data = array( + 'qtys' => $qtys, + 'adjustment_positive' => $adjustmentPositive, + 'adjustment_negative' => $adjustmentNegative + ); + $orderIncrementalId = $order->getIncrementId(); + + //Test create + $creditMemoIncrement = Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoCreate', + array( + 'creditmemoIncrementId' => $orderIncrementalId, + 'creditmemoData' => $data + ) + ); + Mage::register('creditmemoIncrementId', $creditMemoIncrement); + + $this->assertTrue(is_string($creditMemoIncrement), 'Increment Id is not a string'); + $this->assertStringStartsWith( + $prefix, + $creditMemoIncrement, + 'Increment Id returned by API is not correct' + ); + } + + /** + * Test order creditmemo list. With filters + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/multiple_invoices.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @depends testCRUD + */ + public function testListWithFilters() + { + $creditmemoInfo = $this->_createCreditmemo(); + $creditMemoIncrement = end($creditmemoInfo); + + /** @var $creditmemo Mage_Sales_Model_Order_Creditmemo */ + $creditmemo = Mage::getModel('Mage_Sales_Model_Order_Creditmemo')->load($creditMemoIncrement, 'increment_id'); + + $filters = array( + 'filters' => (object)array( + 'filter' => array( + (object)array('key' => 'state', 'value' => $creditmemo->getData('state')), + (object)array('key' => 'created_at', 'value' => $creditmemo->getData('created_at')) + ), + 'complex_filter' => array( + (object)array( + 'key' => 'creditmemo_id', + 'value' => (object)array('key' => 'in', 'value' => array($creditmemo->getId(), 0)) + ), + ) + ) + ); + + $result = Magento_Test_Helper_Api::call($this, 'salesOrderCreditmemoList', $filters); + + if (!isset($result[0])) { // workaround for WS-I + $result = array($result); + } + $this->assertInternalType('array', $result, "Response has invalid format"); + $this->assertEquals(1, count($result), "Invalid creditmemos quantity received"); + foreach (reset($result) as $field => $value) { + if ($field == 'creditmemo_id') { + // process field mapping + $field = 'entity_id'; + } + $this->assertEquals($creditmemo->getData($field), $value, "Field '{$field}' has invalid value"); + } + } + + /** + * Create creditmemo using API. Invoice fixture must be initialized for this method + * + * @return array + */ + protected function _createCreditmemo() + { + /** @var $product Mage_Catalog_Model_Product */ + $product = Mage::registry('product_virtual'); + + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + + $orderItems = $order->getAllItems(); + $qtys = array(); + + /** @var $orderItem Mage_Sales_Model_Order_Item */ + foreach ($orderItems as $orderItem) { + $qtys[] = array('order_item_id' => $orderItem->getId(), 'qty' => 1); + } + + $adjustmentPositive = 2; + $adjustmentNegative = 3; + $data = array( + 'qtys' => $qtys, + 'adjustment_positive' => $adjustmentPositive, + 'adjustment_negative' => $adjustmentNegative + ); + $orderIncrementalId = $order->getIncrementId(); + + //Test create + $creditMemoIncrement = Magento_Test_Helper_Api::call( + $this, + 'salesOrderCreditmemoCreate', + array( + 'creditmemoIncrementId' => $orderIncrementalId, + 'creditmemoData' => (object)$data + ) + ); + + /** Add creditmemo to fixtures to ensure that it is removed in teardown. */ + /** @var Mage_Sales_Model_Order_Creditmemo $createdCreditmemo */ + $createdCreditmemo = Mage::getModel('Mage_Sales_Model_Order_Creditmemo'); + $createdCreditmemo->load($creditMemoIncrement, 'increment_id'); + Mage::register('creditmemo', $createdCreditmemo); + + $this->assertNotEmpty($creditMemoIncrement, 'Creditmemo was not created'); + return array($product, $qtys, $adjustmentPositive, $adjustmentNegative, $creditMemoIncrement); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/CreditmemoTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/CreditmemoTest.php index a061b1a909a..98c69769eb8 100644 --- a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/CreditmemoTest.php +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/CreditmemoTest.php @@ -28,7 +28,7 @@ class Mage_Sales_Model_Order_CreditmemoTest extends PHPUnit_Framework_TestCase { /** - * @magentoConfigFixture current_store design/theme/full_name default/demo + * @magentoConfigFixture frontend/design/theme/full_name default/demo * @magentoDataFixture Mage/Sales/_files/order.php */ public function testSendEmail() diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Invoice/ApiTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Invoice/ApiTest.php new file mode 100644 index 00000000000..c6da08418ba --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Invoice/ApiTest.php @@ -0,0 +1,319 @@ +<?php +/** + * Tests for invoice API. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Sales_Model_Order_Invoice_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test create and read created invoice + * + * @magentoDataFixture Mage/Sales/_files/order.php + * @magentoDbIsolation enabled + */ + public function testCreate() + { + /** Prepare data. */ + $order = $this->_getFixtureOrder(); + $this->assertCount( + 0, + $order->getInvoiceCollection(), + 'There must be 0 invoices before invoice creation via API.' + ); + + /** Create new invoice via API. */ + $newInvoiceId = Magento_Test_Helper_Api::call( + $this, + 'salesOrderInvoiceCreate', + array( + 'orderIncrementId' => $order->getIncrementId(), + 'itemsQty' => array(), + 'comment' => 'invoice Created', + 'email' => true, + 'includeComment' => true + ) + ); + $this->assertGreaterThan(0, (int)$newInvoiceId, 'Invoice was not created.'); + + /** Ensure that invoice was created. */ + /** @var Mage_Sales_Model_Order $invoicedOrder */ + $invoicedOrder = Mage::getModel('Mage_Sales_Model_Order'); + $invoicedOrder->loadByIncrementId($order->getIncrementId()); + $invoiceCollection = $invoicedOrder->getInvoiceCollection(); + $this->assertCount(1, $invoiceCollection->getItems(), 'Invoice was not created.'); + /** @var Mage_Sales_Model_Order_Invoice $createdInvoice */ + $createdInvoice = $invoiceCollection->getFirstItem(); + $this->assertEquals( + $createdInvoice->getIncrementId(), + $newInvoiceId, + 'Invoice ID in call response is invalid.' + ); + } + + /** + * Test create and read created invoice + * + * @magentoDataFixture Mage/Sales/_files/invoice.php + */ + public function testInfo() + { + /** Retrieve invoice data via API. */ + $invoiceData = Magento_Test_Helper_Api::call( + $this, + 'salesOrderInvoiceInfo', + array( + $this->_getFixtureInvoice()->getIncrementId(), + ) + ); + + /** Check received data validity. */ + $fieldsToCheck = array( + 'increment_id', + 'parent_id', + 'store_id', + 'order_id', + 'state', + 'entity_id' => 'invoice_id', + 'base_grand_total' + ); + Magento_Test_Helper_Api::checkEntityFields( + $this, + $this->_getFixtureInvoice()->getData(), + $invoiceData, + $fieldsToCheck + ); + } + + /** + * Test adding comment to invoice via API. + * + * @magentoDataFixture Mage/Sales/_files/invoice.php + * @magentoDbIsolation enabled + */ + public function testAddComment() + { + /** Prepare data. */ + $commentText = "Test invoice comment."; + + /** Retrieve invoice data via API. */ + $isAdded = Magento_Test_Helper_Api::call( + $this, + 'salesOrderInvoiceAddComment', + array( + $this->_getFixtureInvoice()->getIncrementId(), + $commentText, + true, // send invoice via email + true // include comment in email + ) + ); + $this->assertTrue($isAdded, "Comment was not added to the invoice."); + + /** Verify that comment was actually added. */ + /** @var Mage_Sales_Model_Resource_Order_Invoice_Comment_Collection $commentsCollection */ + $commentsCollection = $this->_getFixtureInvoice()->getCommentsCollection(true); + $this->assertCount(1, $commentsCollection->getItems(), "There must be exactly 1 invoice comment."); + /** @var Mage_Sales_Model_Order_Invoice_Comment $createdComment */ + $createdComment = $commentsCollection->getFirstItem(); + $this->assertEquals($commentText, $createdComment->getComment(), 'Invoice comment text is invalid.'); + } + + /** + * Test capturing invoice via API. + * + * @magentoDataFixture Mage/Sales/_files/invoice_verisign.php + */ + public function testCapture() + { + /** + * To avoid complicated environment emulation for online payment, + * we can check if proper error message from payment gateway was received or not. + */ + $this->setExpectedException('SoapFault', 'Invalid vendor account'); + + /** Capture invoice data via API. */ + $invoiceBefore = $this->_getFixtureInvoice(); + $this->assertTrue($invoiceBefore->canCapture(), "Invoice fixture cannot be captured."); + Magento_Test_Helper_Api::call($this, 'salesOrderInvoiceCapture', array($invoiceBefore->getIncrementId())); + } + + /** + * Test voiding captured invoice via API. + * + * @magentoDataFixture Mage/Sales/_files/invoice_verisign.php + */ + public function testVoid() + { + /** + * To avoid complicated environment emulation for online voiding, + * we can check if proper error message from payment gateway was received or not. + */ + $this->setExpectedException('SoapFault', 'Invalid vendor account'); + + /** Prepare data. Make invoice voidable. */ + $invoiceBefore = $this->_getFixtureInvoice(); + $invoiceBefore->setState(Mage_Sales_Model_Order_Invoice::STATE_PAID)->setCanVoidFlag(true)->save(); + + /** Capture invoice data via API. */ + $this->assertTrue($invoiceBefore->canVoid(), "Invoice fixture cannot be voided."); + Magento_Test_Helper_Api::call($this, 'salesOrderInvoiceVoid', array($invoiceBefore->getIncrementId())); + } + + /** + * Test cancelling invoice via API. + * + * @magentoDataFixture Mage/Sales/_files/invoice_verisign.php + */ + public function testCancel() + { + /** Capture invoice data via API. */ + $invoiceBefore = $this->_getFixtureInvoice(); + $this->assertTrue($invoiceBefore->canCancel(), "Invoice fixture cannot be cancelled."); + $isCanceled = Magento_Test_Helper_Api::call( + $this, + 'salesOrderInvoiceCancel', + array($invoiceBefore->getIncrementId()) + ); + $this->assertTrue($isCanceled, "Invoice was not canceled successfully."); + + /** Ensure that invoice was actually cancelled. */ + $invoiceAfter = $this->_getFixtureInvoice(); + $this->assertEquals( + Mage_Sales_Model_Order_Invoice::STATE_CANCELED, + $invoiceAfter->getState(), + "Invoice was not cancelled." + ); + } + + /** + * Retrieve invoice declared in fixture. + * + * This method reloads data and creates new object with each call. + * + * @return Mage_Sales_Model_Order_Invoice + */ + protected function _getFixtureInvoice() + { + $order = $this->_getFixtureOrder(); + $invoiceCollection = $order->getInvoiceCollection(); + $this->assertCount(1, $invoiceCollection->getItems(), 'There must be exactly 1 invoice assigned to the order.'); + /** @var Mage_Sales_Model_Order_Invoice $invoice */ + $invoice = $invoiceCollection->getFirstItem(); + return $invoice; + } + + /** + * Retrieve order declared in fixture. + * + * This method reloads data and creates new object with each call. + * + * @return Mage_Sales_Model_Order + */ + protected function _getFixtureOrder() + { + $orderIncrementId = '100000001'; + /** @var Mage_Sales_Model_Order $order */ + $order = Mage::getModel('Mage_Sales_Model_Order'); + $order->loadByIncrementId($orderIncrementId); + return $order; + } + + /** + * Test credit memo create API call results + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/order.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ + public function testAutoIncrementType() + { + /** @var $quote Mage_Sales_Model_Quote */ + $order = Mage::registry('order2'); + $incrementId = $order->getIncrementId(); + + // Set invoice increment id prefix + $prefix = '01'; + Magento_Test_Helper_Eav::setIncrementIdPrefix('invoice', $prefix); + + // Create new invoice + $newInvoiceId = Magento_Test_Helper_Api::call( + $this, + 'salesOrderInvoiceCreate', + array( + 'orderIncrementId' => $incrementId, + 'itemsQty' => array(), + 'comment' => 'invoice Created', + 'email' => true, + 'includeComment' => true + ) + ); + + $this->assertTrue(is_string($newInvoiceId), 'Increment Id is not a string'); + $this->assertStringStartsWith($prefix, $newInvoiceId, 'Increment Id returned by API is not correct'); + Mage::register('invoiceIncrementId', $newInvoiceId); + } + + /** + * Test order invoice list. With filters + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/multiple_invoices.php + * @magentoAppIsolation enabled + */ + public function testListWithFilters() + { + /** @var $invoice Mage_Sales_Model_Order_Invoice */ + $invoice = Mage::registry('invoice'); + + $filters = array( + 'filters' => (object)array( + 'filter' => array( + (object)array('key' => 'state', 'value' => $invoice->getData('state')), + (object)array('key' => 'created_at', 'value' => $invoice->getData('created_at')) + ), + 'complex_filter' => array( + (object)array( + 'key' => 'invoice_id', + 'value' => (object)array('key' => 'in', 'value' => array($invoice->getId(), 0)) + ), + ) + ) + ); + + $result = Magento_Test_Helper_Api::call($this, 'salesOrderInvoiceList', $filters); + + if (!isset($result[0])) { // workaround for WS-I + $result = array($result); + } + $this->assertInternalType('array', $result, "Response has invalid format"); + $this->assertEquals(1, count($result), "Invalid invoices quantity received"); + + /** Reload invoice data to ensure it is up to date. */ + $invoice->load($invoice->getId()); + foreach (reset($result) as $field => $value) { + if ($field == 'invoice_id') { + // process field mapping + $field = 'entity_id'; + } + $this->assertEquals($invoice->getData($field), $value, "Field '{$field}' has invalid value"); + } + } +} diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/InvoiceTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/InvoiceTest.php index d3e741bb3e8..f0e82db4d90 100644 --- a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/InvoiceTest.php +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/InvoiceTest.php @@ -28,7 +28,7 @@ class Mage_Sales_Model_Order_InvoiceTest extends PHPUnit_Framework_TestCase { /** - * @magentoConfigFixture current_store design/theme/full_name default/demo + * @magentoConfigFixture frontend/design/theme/full_name default/demo * @magentoDataFixture Mage/Sales/_files/order.php */ public function testSendEmail() diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/OrderTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/OrderTest.php index 3ac50925631..22171182e7a 100644 --- a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/OrderTest.php +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/OrderTest.php @@ -28,7 +28,7 @@ class Mage_Sales_Model_OrderTest extends PHPUnit_Framework_TestCase { /** - * @magentoConfigFixture current_store design/theme/full_name default/demo + * @magentoConfigFixture frontend/design/theme/full_name default/demo * @magentoDataFixture Mage/Sales/_files/order.php */ public function testSendNewOrderEmail() diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Shipment/ApiTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Shipment/ApiTest.php new file mode 100644 index 00000000000..f6e72eef056 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/Shipment/ApiTest.php @@ -0,0 +1,279 @@ +<?php +/** + * Tests for shipment API. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Sales_Model_Order_Shipment_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test retrieving the list of shipments related to the order via API. + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/shipment.php + */ + public function testItems() + { + /** Prepare data. */ + $shipmentFixture = $this->_getShipmentFixture(); + $filters = array( + 'filters' => (object)array( + 'filter' => array( + (object)array('key' => 'increment_id', 'value' => $shipmentFixture->getIncrementId()), + ) + ) + ); + + /** Retrieve list of shipments via API. */ + $shipmentsList = Magento_Test_Helper_Api::call($this, 'salesOrderShipmentList', $filters); + + /** Verify received list of shipments. */ + $this->assertCount(1, $shipmentsList, "Exactly 1 shipment is expected to be in the list results."); + $fieldsToCompare = array('increment_id', 'total_qty', 'entity_id' => 'shipment_id'); + Magento_Test_Helper_Api::checkEntityFields( + $this, + $shipmentFixture->getData(), + reset($shipmentsList), + $fieldsToCompare + ); + } + + /** + * Test retrieving available carriers for the specified order. + * + * @magentoDataFixture Mage/Sales/_files/order.php + */ + public function testGetCarriers() + { + /** Prepare data. */ + /** @var Mage_Sales_Model_Order $order */ + $order = Mage::getModel('Mage_Sales_Model_Order'); + $order->loadByIncrementId('100000001'); + + /** Retrieve carriers list */ + $carriersList = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentGetCarriers', + array($order->getIncrementId()) + ); + + /** Verify carriers list. */ + $this->assertCount(6, $carriersList, "Carriers list contains unexpected quantity of items."); + $dhlCarrierData = end($carriersList); + $expectedDhlData = array('key' => 'dhlint', 'value' => 'DHL'); + $this->assertEquals($expectedDhlData, $dhlCarrierData, "Carriers list item is invalid."); + } + + /** + * Test adding comment to shipment via API. + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/shipment.php + */ + public function testAddComment() + { + if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { + $this->markTestIncomplete('Legacy API is expected to support MySQL only.'); + } + /** Add comment to shipment via API. */ + $commentText = 'Shipment test comment.'; + $isAdded = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentAddComment', + array( + $this->_getShipmentFixture()->getIncrementId(), + $commentText, + true, // should email be sent? + true, // should comment be included into email body? + ) + ); + $this->assertTrue($isAdded, "Comment was not added to the shipment."); + + /** Ensure that comment was actually added to the shipment. */ + /** @var Mage_Sales_Model_Resource_Order_Shipment_Comment_Collection $commentsCollection */ + $commentsCollection = $this->_getShipmentFixture()->getCommentsCollection(true); + $this->assertCount(1, $commentsCollection->getItems(), "Exactly 1 shipment comment is expected to exist."); + /** @var Mage_Sales_Model_Order_Shipment_Comment $comment */ + $comment = $commentsCollection->getFirstItem(); + $this->assertEquals($commentText, $comment->getComment(), 'Comment text was saved to DB incorrectly.'); + } + + /** + * Test adding and removing tracking information via shipment API. + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/shipment.php + */ + public function testTrackOperations() + { + if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { + $this->markTestIncomplete('Legacy API is expected to support MySQL only.'); + } + /** Prepare data. */ + $carrierCode = 'ups'; + $trackingTitle = 'Tracking title'; + $trackingNumber = 'N123456'; + + /** Add tracking information via API. */ + $trackingNumberId = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentAddTrack', + array($this->_getShipmentFixture()->getIncrementId(), $carrierCode, $trackingTitle, $trackingNumber) + ); + $this->assertGreaterThan(0, (int)$trackingNumberId, "Tracking information was not added."); + + /** Ensure that tracking data was saved correctly. */ + $tracksCollection = $this->_getShipmentFixture()->getTracksCollection(); + $this->assertCount(1, $tracksCollection->getItems(), "Tracking information was not saved to DB."); + /** @var Mage_Sales_Model_Order_Shipment_Track $track */ + $track = $tracksCollection->getFirstItem(); + $this->assertEquals( + array($carrierCode, $trackingTitle, $trackingNumber), + array($track->getCarrierCode(), $track->getTitle(), $track->getNumber()), + 'Tracking data was saved incorrectly.' + ); + + /** Remove tracking information via API. */ + $isRemoved = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentRemoveTrack', + array($this->_getShipmentFixture()->getIncrementId(), $trackingNumberId) + ); + $this->assertTrue($isRemoved, "Tracking information was not removed."); + + /** Ensure that tracking data was saved correctly. */ + /** @var Mage_Sales_Model_Order_Shipment $updatedShipment */ + $updatedShipment = Mage::getModel('Mage_Sales_Model_Order_Shipment'); + $updatedShipment->load($this->_getShipmentFixture()->getId()); + $tracksCollection = $updatedShipment->getTracksCollection(); + $this->assertCount(0, $tracksCollection->getItems(), "Tracking information was not removed from DB."); + } + + /** + * Test shipment create and info via API. + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/order_with_shipping.php + * @magentoDbIsolation enabled + */ + public function testCRUD() + { + // Create new shipment + $newShipmentId = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentCreate', + array( + 'orderIncrementId' => $this->_getOrderFixture()->getIncrementId(), + 'itemsQty' => array(), + 'comment' => 'Shipment Created', + 'email' => true, + 'includeComment' => true + ) + ); + Mage::register('shipmentIncrementId', $newShipmentId); + + // View new shipment + $shipment = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentInfo', + array( + 'shipmentIncrementId' => $newShipmentId + ) + ); + + $this->assertEquals($newShipmentId, $shipment['increment_id']); + } + + /** + * Test shipment create API. + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/order_with_shipping.php + * @magentoDbIsolation enabled + */ + public function testAutoIncrementType() + { + // Set shipping increment id prefix + $prefix = '01'; + Magento_Test_Helper_Eav::setIncrementIdPrefix('shipment', $prefix); + + // Create new shipment + $newShipmentId = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentCreate', + array( + 'orderIncrementId' => $this->_getOrderFixture()->getIncrementId(), + 'itemsQty' => array(), + 'comment' => 'Shipment Created', + 'email' => true, + 'includeComment' => true + ) + ); + Mage::unregister('shipmentIncrementId'); + Mage::register('shipmentIncrementId', $newShipmentId); + + $this->assertTrue(is_string($newShipmentId), 'Increment Id is not a string'); + $this->assertStringStartsWith($prefix, $newShipmentId, 'Increment Id returned by API is not correct'); + } + + /** + * Test send shipping info API + * + * @magentoDataFixture Mage/Sales/Model/Order/Api/_files/shipment.php + * @magentoDbIsolation enabled + */ + public function testSendInfo() + { + if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { + $this->markTestIncomplete('Legacy API is expected to support MySQL only.'); + } + $isSent = Magento_Test_Helper_Api::call( + $this, + 'salesOrderShipmentSendInfo', + array( + 'shipmentIncrementId' => $this->_getShipmentFixture()->getIncrementId(), + 'comment' => 'Comment text.' + ) + ); + + $this->assertTrue((bool)$isSent); + } + + /** + * Retrieve order from fixture. + * + * @return Mage_Sales_Model_Order + */ + protected function _getOrderFixture() + { + /** @var $order Mage_Sales_Model_Order */ + $order = Mage::registry('order'); + return $order; + } + + /** + * Retrieve shipment from fixture. + * + * @return Mage_Sales_Model_Order_Shipment + */ + protected function _getShipmentFixture() + { + /** @var $shipment Mage_Sales_Model_Order_Shipment */ + $shipment = Mage::registry('shipment'); + return $shipment; + } +} diff --git a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/ShipmentTest.php b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/ShipmentTest.php index f1a5823b9f5..e86b076a52c 100644 --- a/dev/tests/integration/testsuite/Mage/Sales/Model/Order/ShipmentTest.php +++ b/dev/tests/integration/testsuite/Mage/Sales/Model/Order/ShipmentTest.php @@ -28,7 +28,7 @@ class Mage_Sales_Model_Order_ShipmentTest extends PHPUnit_Framework_TestCase { /** - * @magentoConfigFixture current_store design/theme/full_name default/demo + * @magentoConfigFixture frontend/design/theme/full_name default/demo * @magentoDataFixture Mage/Sales/_files/order.php */ public function testSendEmail() diff --git a/dev/tests/integration/testsuite/Mage/Sales/_files/invoice.php b/dev/tests/integration/testsuite/Mage/Sales/_files/invoice.php new file mode 100644 index 00000000000..70881cf68c4 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/_files/invoice.php @@ -0,0 +1,35 @@ +<?php +/** + * Paid invoice fixture. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +require 'order.php'; +/** @var Mage_Sales_Model_Order $order */ + +$orderService = new Mage_Sales_Model_Service_Order($order); +$invoice = $orderService->prepareInvoice(); +$invoice->register(); +$order->setIsInProcess(true); +$transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction'); +$transactionSave->addObject($invoice)->addObject($order)->save(); diff --git a/dev/tests/integration/testsuite/Mage/Sales/_files/invoice_verisign.php b/dev/tests/integration/testsuite/Mage/Sales/_files/invoice_verisign.php new file mode 100644 index 00000000000..a38c3eef184 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Sales/_files/invoice_verisign.php @@ -0,0 +1,36 @@ +<?php +/** + * Not paid invoice fixture for online payment method. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +require 'order_paid_with_verisign.php'; +/** @var Mage_Sales_Model_Order $order */ + +$orderService = new Mage_Sales_Model_Service_Order($order); +$invoice = $orderService->prepareInvoice(); +/** To allow invoice cancelling it should be created without capturing. */ +$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::NOT_CAPTURE)->register(); +$order->setIsInProcess(true); +$transactionSave = Mage::getModel('Mage_Core_Model_Resource_Transaction'); +$transactionSave->addObject($invoice)->addObject($order)->save(); diff --git a/dev/tests/integration/testsuite/Mage/Sales/_files/order.php b/dev/tests/integration/testsuite/Mage/Sales/_files/order.php index 25460f62ab0..30bd4bd363c 100644 --- a/dev/tests/integration/testsuite/Mage/Sales/_files/order.php +++ b/dev/tests/integration/testsuite/Mage/Sales/_files/order.php @@ -25,6 +25,9 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ +require __DIR__ . '/../../Catalog/_files/product_simple.php'; +/** @var Mage_Catalog_Model_Product $product */ + $addressData = include(__DIR__ . '/address_data.php'); $billingAddress = Mage::getModel('Mage_Sales_Model_Order_Address', array('data' => $addressData)); $billingAddress->setAddressType('billing'); @@ -36,6 +39,11 @@ $shippingAddress->setId(null) $payment = Mage::getModel('Mage_Sales_Model_Order_Payment'); $payment->setMethod('checkmo'); +/** @var Mage_Sales_Model_Order_Item $orderItem */ +$orderItem = Mage::getModel('Mage_Sales_Model_Order_Item'); +$orderItem->setProductId($product->getId())->setQtyOrdered(2); + +/** @var Mage_Sales_Model_Order $order */ $order = Mage::getModel('Mage_Sales_Model_Order'); $order->setIncrementId('100000001') ->setSubtotal(100) @@ -43,7 +51,8 @@ $order->setIncrementId('100000001') ->setCustomerIsGuest(true) ->setBillingAddress($billingAddress) ->setShippingAddress($shippingAddress) + ->setCustomerEmail('customer@null.com') ->setStoreId(Mage::app()->getStore()->getId()) - ->setPayment($payment) -; + ->addItem($orderItem) + ->setPayment($payment); $order->save(); diff --git a/dev/tests/integration/testsuite/Mage/Sitemap/Model/Resource/Catalog/ProductTest.php b/dev/tests/integration/testsuite/Mage/Sitemap/Model/Resource/Catalog/ProductTest.php index 122fbb88acd..efac2a414ea 100644 --- a/dev/tests/integration/testsuite/Mage/Sitemap/Model/Resource/Catalog/ProductTest.php +++ b/dev/tests/integration/testsuite/Mage/Sitemap/Model/Resource/Catalog/ProductTest.php @@ -160,7 +160,6 @@ class Mage_Sitemap_Model_Resource_Catalog_ProductTest extends PHPUnit_Framework_ * @param array $products * @param int $expectedCount * @param array $expectedKeys - * @return void */ protected function _checkProductCollection(array $products, $expectedCount, array $expectedKeys) { diff --git a/dev/tests/integration/testsuite/Mage/Tag/Model/Api/_files/tag.php b/dev/tests/integration/testsuite/Mage/Tag/Model/Api/_files/tag.php new file mode 100644 index 00000000000..e91c9feedfb --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Tag/Model/Api/_files/tag.php @@ -0,0 +1,29 @@ +<?php +/** + * Fixture for tag. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +/** @var Mage_Tag_Model_Tag $tag */ +$tag = Mage::getModel('Mage_Tag_Model_Tag'); +$tag->setName('tag_name')->setStatus(Mage_Tag_Model_Tag::STATUS_APPROVED); +$tag->save(); diff --git a/dev/tests/integration/testsuite/Mage/Tag/Model/ApiTest.php b/dev/tests/integration/testsuite/Mage/Tag/Model/ApiTest.php new file mode 100644 index 00000000000..9312b2493b0 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Tag/Model/ApiTest.php @@ -0,0 +1,81 @@ +<?php +/** + * Product tag API test. + * + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @magentoDataFixture Mage/Tag/Model/Api/_files/tag.php + */ +class Mage_Tag_Model_ApiTest extends PHPUnit_Framework_TestCase +{ + /** + * Test info method. + */ + public function testInfo() + { + $tagName = 'tag_name'; + $tagStatus = Mage_Tag_Model_Tag::STATUS_APPROVED; + /** @var Mage_Tag_Model_Tag $tag */ + $tag = Mage::getModel('Mage_Tag_Model_Tag'); + $tagId = $tag->loadByName($tagName)->getTagId(); + /** Retrieve tag info. */ + $tagInfo = Magento_Test_Helper_Api::call( + $this, + 'catalogProductTagInfo', + array($tagId) + ); + /** Assert response is not empty. */ + $this->assertNotEmpty($tagInfo, 'Tag info is not retrieved.'); + /** Assert base fields are present in the response. */ + $expectedFields = array('status', 'name', 'base_popularity', 'products'); + $missingFields = array_diff($expectedFields, array_keys($tagInfo)); + $this->assertEmpty( + $missingFields, + sprintf("The following fields must be present in response: %s.", implode(', ', $missingFields)) + ); + /** Assert retrieved tag data is correct. */ + $this->assertEquals($tagInfo->name, $tagName, 'Tag name is incorrect.'); + $this->assertEquals($tagInfo->status, $tagStatus, 'Tag status is incorrect.'); + } + + /** + * Test update method. + */ + public function testUpdate() + { + /** @var Mage_Tag_Model_Tag $tag */ + $tagId = Mage::getModel('Mage_Tag_Model_Tag')->loadByName('tag_name')->getTagId(); + $updateData = array('name' => 'new_tag_name', 'status' => Mage_Tag_Model_Tag::STATUS_DISABLED); + /** Update tag. */ + $tagUpdateResponse = Magento_Test_Helper_Api::call( + $this, + 'catalogProductTagUpdate', + array($tagId, (object)$updateData) + ); + /** Check tag update result. */ + $this->assertTrue((bool)$tagUpdateResponse, 'Tag update was unsuccessful.'); + /** Assert updated fields. */ + /** @var Mage_Tag_Model_Tag $updatedTag */ + $updatedTag = Mage::getModel('Mage_Tag_Model_Tag')->loadByName($updateData['name']); + $this->assertNotEmpty($updatedTag->getTagId(), 'Tag name update was unsuccessful.'); + $this->assertEquals($updateData['status'], $updatedTag->getStatus(), 'Tag status update was unsuccessful.'); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Usa/Block/Adminhtml/Dhl/UnitofmeasureTest.php b/dev/tests/integration/testsuite/Mage/Usa/Block/Adminhtml/Dhl/UnitofmeasureTest.php new file mode 100644 index 00000000000..552e6cf4f57 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Usa/Block/Adminhtml/Dhl/UnitofmeasureTest.php @@ -0,0 +1,37 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Usa_Block_Adminhtml_Dhl_UnitofmeasureTest extends PHPUnit_Framework_TestCase +{ + /** + * @magentoAppIsolation enabled + */ + public function testToHtml() + { + /** @var $layout Mage_Core_Model_Layout */ + $layout = Mage::getSingleton('Mage_Core_Model_Layout', array('area' => 'adminhtml')); + /** @var $block Mage_Usa_Block_Adminhtml_Dhl_Unitofmeasure */ + $block = $layout->createBlock('Mage_Usa_Block_Adminhtml_Dhl_Unitofmeasure'); + $this->assertNotEmpty($block->toHtml()); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/FormTestAbstract.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/FormTestAbstract.php index e8d011c797f..4422ea35384 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/FormTestAbstract.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/FormTestAbstract.php @@ -78,11 +78,11 @@ class Mage_Webapi_Block_Adminhtml_FormTestAbstract extends PHPUnit_Framework_Tes } /** - * Test _prepareForm method + * Test _prepareForm method. */ public function testPrepareForm() { - // TODO Move to unit tests after MAGETWO-4015 complete + // TODO: Move to unit tests after MAGETWO-4015 complete. $this->assertEmpty($this->_block->getForm()); $this->_urlBuilder->expects($this->once()) diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/FormTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/FormTest.php index a3b86fa4304..4cecb1c70a6 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/FormTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/FormTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Block_Adminhtml_Role_Edit_Form block + * Test for Mage_Webapi_Block_Adminhtml_Role_Edit_Form block. * * Magento * diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/MainTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/MainTest.php index 0efee579d1c..4af05990574 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/MainTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/MainTest.php @@ -62,7 +62,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_MainTest extends PHPUnit_Framewo } /** - * Test _prepareForm method + * Test _prepareForm method. * * @dataProvider prepareFormDataProvider * @param Varien_Object $apiRole @@ -70,7 +70,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_MainTest extends PHPUnit_Framewo */ public function testPrepareForm($apiRole, array $formElements) { - // TODO Move to unit tests after MAGETWO-4015 complete + // TODO: Move to unit tests after MAGETWO-4015 complete $this->assertEmpty($this->_block->getForm()); $this->_block->setApiRole($apiRole); @@ -84,7 +84,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_MainTest extends PHPUnit_Framewo $elements = $fieldset->getElements(); foreach ($formElements as $elementId) { $element = $elements->searchById($elementId); - $this->assertNotEmpty($element, "Element '$elementId' not found in form fieldset"); + $this->assertNotEmpty($element, "Element '$elementId' is not found in form fieldset"); $this->assertEquals($apiRole->getData($elementId), $element->getValue()); } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php index d392f5f7bb7..76d918f3ea2 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_Resource block + * Test for Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_Resource block. * * Magento * @@ -84,7 +84,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_ResourceTest extends PHPUnit_Fra } /** - * Test _prepareForm method + * Test _prepareForm method. * * @dataProvider prepareFormDataProvider * @param array $originResTree @@ -93,7 +93,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_ResourceTest extends PHPUnit_Fra */ public function testPrepareForm($originResTree, $selectedRes, $expectedRes) { - // TODO Move to unit tests after MAGETWO-4015 complete + // TODO: Move to unit tests after MAGETWO-4015 complete. $apiRole = new Varien_Object(array( 'role_id' => 1 )); diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/FormTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/FormTest.php index aa29ac04c83..d2c222801ab 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/FormTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/FormTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Block_Adminhtml_User_Edit_Form block + * Test for Mage_Webapi_Block_Adminhtml_User_Edit_Form block. * * Magento * diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/Tab/MainTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/Tab/MainTest.php index ac50ebd6857..0df9ce33c94 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/Tab/MainTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/Tab/MainTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Block_Adminhtml_User_Edit_Tab_Main block + * Test for Mage_Webapi_Block_Adminhtml_User_Edit_Tab_Main block. * * Magento * @@ -61,7 +61,7 @@ class Mage_Webapi_Block_Adminhtml_User_Edit_Tab_MainTest extends PHPUnit_Framewo } /** - * Test _prepareForm method + * Test _prepareForm method. * * @dataProvider prepareFormDataProvider * @param Varien_Object $apiUser @@ -69,7 +69,7 @@ class Mage_Webapi_Block_Adminhtml_User_Edit_Tab_MainTest extends PHPUnit_Framewo */ public function testPrepareForm($apiUser, array $formElements) { - // TODO Move to unit tests after MAGETWO-4015 complete + // TODO: Move to unit tests after MAGETWO-4015 complete. $this->assertEmpty($this->_block->getForm()); $this->_block->setApiUser($apiUser); @@ -83,7 +83,7 @@ class Mage_Webapi_Block_Adminhtml_User_Edit_Tab_MainTest extends PHPUnit_Framewo $elements = $fieldset->getElements(); foreach ($formElements as $elementId) { $element = $elements->searchById($elementId); - $this->assertNotEmpty($element, "Element '$elementId' not found in form fieldset"); + $this->assertNotEmpty($element, "Element '$elementId' is not found in form fieldset"); $this->assertEquals($apiUser->getData($elementId), $element->getValue()); } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/TabsTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/TabsTest.php index c582c9d0053..d07cb7f778c 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/TabsTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/Edit/TabsTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Block_Adminhtml_User_Edit_Tabs block + * Test for Mage_Webapi_Block_Adminhtml_User_Edit_Tabs block. * * Magento * @@ -55,11 +55,11 @@ class Mage_Webapi_Block_Adminhtml_User_Edit_TabsTest extends PHPUnit_Framework_T } /** - * Test _beforeToHtml method + * Test _beforeToHtml method. */ public function testBeforeToHtml() { - // TODO Move to unit tests after MAGETWO-4015 complete + // TODO: Move to unit tests after MAGETWO-4015 complete. /** @var Mage_Webapi_Block_Adminhtml_User_Edit_Tab_Main $mainTabBlock */ $mainTabBlock = $this->_layout->addBlock( 'Mage_Core_Block_Text', @@ -107,7 +107,7 @@ class Mage_Webapi_Block_Adminhtml_User_Edit_TabsTest extends PHPUnit_Framework_T } /** - * Get protected _tabs property of Mage_Backend_Block_Widget_Tabs block + * Get protected _tabs property of Mage_Backend_Block_Widget_Tabs block. * * @param Mage_Backend_Block_Widget_Tabs $tabs * @return array @@ -124,7 +124,7 @@ class Mage_Webapi_Block_Adminhtml_User_Edit_TabsTest extends PHPUnit_Framework_T $this->fail('Cannot get tabs value'); } - $this->assertInternalType('array', $result, 'Tabs value expected to be an array'); + $this->assertInternalType('array', $result, 'Tabs value is expected to be an array'); return $result; } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php index 4179520f747..a98babbaa95 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Block_Adminhtml_User_Edit block + * Test for Mage_Webapi_Block_Adminhtml_User_Edit block. * * Magento * @@ -41,7 +41,7 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa protected $_block; /** - * Initialize block + * Initialize block. */ protected function setUp() { @@ -51,7 +51,7 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa } /** - * Clear clock + * Clear block. */ protected function tearDown() { @@ -59,11 +59,11 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa } /** - * Test _beforeToHtml method + * Test _beforeToHtml method. */ public function testBeforeToHtml() { - // TODO Move to unit tests after MAGETWO-4015 complete + // TODO: Move to unit tests after MAGETWO-4015 complete. $apiUser = new Varien_Object(); $this->_block->setApiUser($apiUser); $this->_block->toHtml(); diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Helper/ConfigTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Helper/ConfigTest.php index 5b9399fefa7..049cb051766 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Helper/ConfigTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Helper/ConfigTest.php @@ -175,7 +175,7 @@ class Mage_Webapi_Helper_ConfigTest extends PHPUnit_Framework_TestCase $this->assertEquals( $expectedParts, $this->_helper->getResourceNameParts($className), - "Resource parts for rest route were identified incorrectly." + "Resource parts for REST route were identified incorrectly." ); } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Helper/DataTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Helper/DataTest.php index dd878c4534e..6def23b3b88 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Helper/DataTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Helper/DataTest.php @@ -29,6 +29,7 @@ */ include_once __DIR__ . '/../_files/data_types/Customer/AddressData.php'; include_once __DIR__ . '/../_files/data_types/CustomerData.php'; +include_once __DIR__ . '/../_files/autodiscovery/resource_class_fixture.php'; include_once __DIR__ . '/../_files/autodiscovery/subresource_class_fixture.php'; /**#@-*/ @@ -59,7 +60,12 @@ class Mage_Webapi_Helper_DataTest extends PHPUnit_Framework_TestCase /** Prepare arguments for SUT constructor. */ $pathToFixtures = __DIR__ . '/../_files/autodiscovery'; /** @var Mage_Webapi_Model_Config_Reader_Soap $reader */ - $reader = $objectManager->get('Mage_Webapi_Model_Config_Reader_Soap'); + $reader = $objectManager->get( + 'Mage_Webapi_Model_Config_Reader_Soap', + array( + 'cache' => $this->getMock('Mage_Core_Model_Cache', array(), array(), '', false) + ) + ); $reader->setDirectoryScanner(new Zend\Code\Scanner\DirectoryScanner($pathToFixtures)); /** Initialize SUT. */ self::$_apiConfig = $objectManager->create('Mage_Webapi_Model_Config_Soap', array('reader' => $reader)); @@ -111,49 +117,49 @@ class Mage_Webapi_Helper_DataTest extends PHPUnit_Framework_TestCase $optionalNotSetOutput->password = "123123q"; return array( - // Test valid data that does not need transformations + // Test valid data that does not need transformations. array( 'Vendor_Module_Controller_Webapi_Resource_Subresource', 'createV1', array('param1' => 1, 'param2' => 2, 'param3' => array($customerDataObject), 'param4' => 4), array('param1' => 1, 'param2' => 2, 'param3' => array($customerDataObject), 'param4' => 4), ), - // Test filtering unnecessary data + // Test filtering unnecessary data. array( 'Vendor_Module_Controller_Webapi_Resource_Subresource', 'createV2', array('param1' => 1, 'param2' => 2, 'param3' => array($customerDataObject), 'param4' => 4), array('param1' => 1, 'param2' => 2), ), - // Test parameters sorting + // Test parameters sorting. array( 'Vendor_Module_Controller_Webapi_Resource_Subresource', 'createV1', array('param4' => 4, 'param2' => 2, 'param3' => array($customerDataObject), 'param1' => 1), array('param1' => 1, 'param2' => 2, 'param3' => array($customerDataObject), 'param4' => 4), ), - // Test default values setting + // Test default values setting. array( 'Vendor_Module_Controller_Webapi_Resource_Subresource', 'createV1', array('param1' => 1, 'param2' => 2), array('param1' => 1, 'param2' => 2, 'param3' => array(), 'param4' => 'default_value'), ), - // Test with object instead of class name + // Test with object instead of class name. array( new Vendor_Module_Controller_Webapi_Resource_Subresource(), 'createV2', array('param2' => 2, 'param1' => 1), array('param1' => 1, 'param2' => 2), ), - // Test passing of partially formatted objects + // Test passing of partially formatted objects. array( new Vendor_Module_Controller_Webapi_Resource_Subresource(), 'updateV1', array('param1' => 1, 'param2' => get_object_vars($customerDataObject)), array('param1' => 1, 'param2' => $customerDataObject), ), - // Test passing of complex type parameter with optional field not set + // Test passing of complex type parameter with optional field not set. array( new Vendor_Module_Controller_Webapi_Resource_Subresource(), 'updateV1', @@ -225,7 +231,7 @@ class Mage_Webapi_Helper_DataTest extends PHPUnit_Framework_TestCase 'email' => "test_email@example.com" ); return array( - // Test exception in case of missing required parameter + // Test exception in case of missing required parameter. array( 'Vendor_Module_Controller_Webapi_Resource_Subresource', 'createV1', @@ -233,7 +239,7 @@ class Mage_Webapi_Helper_DataTest extends PHPUnit_Framework_TestCase 'Mage_Webapi_Exception', 'Required parameter "param1" is missing.' ), - // Test passing of complex type parameter with not specified required field + // Test passing of complex type parameter with not specified required field. array( new Vendor_Module_Controller_Webapi_Resource_Subresource(), 'updateV1', diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RoleTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RoleTest.php index 76a426447fa..a491dd257ce 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RoleTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RoleTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Model_Acl_Role model + * Test for Mage_Webapi_Model_Acl_Role model. * * Magento * @@ -37,7 +37,7 @@ class Mage_Webapi_Model_Acl_RoleTest extends PHPUnit_Framework_TestCase protected $_model; /** - * Initialize model + * Initialize model. */ protected function setUp() { @@ -46,7 +46,7 @@ class Mage_Webapi_Model_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Cleanup model instance + * Cleanup model instance. */ protected function tearDown() { @@ -54,7 +54,7 @@ class Mage_Webapi_Model_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test Web API Role CRUD + * Test Web API Role CRUD. */ public function testCRUD() { diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RuleTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RuleTest.php index ffbc421e402..b10fb7f3cd0 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RuleTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/RuleTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Model_Acl_Rule model + * Test for Mage_Webapi_Model_Acl_Rule model. * * Magento * @@ -49,7 +49,7 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Cleanup model instance + * Cleanup model instance. */ protected function tearDown() { @@ -57,7 +57,7 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Test Web API Rule CRUD + * Test Web API Role CRUD. */ public function testCRUD() { @@ -72,7 +72,7 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Test method Mage_Webapi_Model_Acl_Rule::saveResources() + * Test Mage_Webapi_Model_Acl_Rule::saveResources() method. */ public function testSaveResources() { diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/UserTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/UserTest.php index c5cc69f88ae..c347ebb66c5 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/UserTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Acl/UserTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Model_Acl_User model + * Test for Mage_Webapi_Model_Acl_User model. * * Magento * @@ -42,7 +42,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase protected $_roleFactory; /** - * Initialize model + * Initialize model. */ protected function setUp() { @@ -52,7 +52,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Cleanup model instance + * Cleanup model instance. */ protected function tearDown() { @@ -60,7 +60,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Test Web API User CRUD + * Test Web API User CRUD. */ public function testCRUD() { diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Reader/Rest/RouteGeneratorTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Reader/Rest/RouteGeneratorTest.php index a3abc195eed..5f88e81087a 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Reader/Rest/RouteGeneratorTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Reader/Rest/RouteGeneratorTest.php @@ -1,6 +1,6 @@ <?php /** - * File with unit tests for REST routes generator class: Mage_Webapi_Model_Config_Reader_Rest_RouteGenerator + * File with unit tests for REST routes generator class: Mage_Webapi_Model_Config_Reader_Rest_RouteGenerator. * * Magento * @@ -204,7 +204,7 @@ class Mage_Webapi_Model_Config_Reader_Rest_RouteGeneratorTest extends PHPUnit_Fr } /** - * Check if list of REST routes are equal. + * Check if list of REST routes is equal. * * @param array $expectedRoutes * @param array $actualRoutes diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/RestTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/RestTest.php index a6e389e4a63..473e39df392 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/RestTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/RestTest.php @@ -1,6 +1,6 @@ <?php /** - * File with unit tests for API configuration class: Mage_Webapi_Model_Config_Rest + * File with unit tests for API configuration class: Mage_Webapi_Model_Config_Rest. * * Magento * @@ -37,18 +37,28 @@ require_once __DIR__ . '/../_files/resource_with_invalid_name.php'; /** - * Test of API configuration class: Mage_Webapi_Model_Config + * Test of API configuration class: Mage_Webapi_Model_Config. */ class Mage_Webapi_Model_Config_RestTest extends PHPUnit_Framework_TestCase { + const WEBAPI_AREA_FRONT_NAME = 'webapi'; + /** * @var Mage_Webapi_Model_Config_Rest */ protected static $_apiConfig; + /** + * App mock clone usage helps to improve performance. It is required because mock will be removed in tear down. + * + * @var Mage_Core_Model_App + */ + protected static $_appClone; + public static function tearDownAfterClass() { self::$_apiConfig = null; + self::$_appClone = null; parent::tearDownAfterClass(); } @@ -96,9 +106,9 @@ class Mage_Webapi_Model_Config_RestTest extends PHPUnit_Framework_TestCase /** * Vendor_Module_Controller_Webapi_Resource fixture contains two methods getV2 and deleteV3 that have * different names of ID param. - * If there will be two different routes generated for these methods with different ID param names, + * If there are two different routes generated for these methods with different ID param names, * it will be impossible to identify which route should be used as they both will match the same requests. - * E.g. DELETE /resource/:deleteId and GET /resource/:getId will match same requests. + * E.g. DELETE /resource/:deleteId and GET /resource/:getId will match the same requests. */ $this->assertNotCount( $expectedRoutesCount + 1, @@ -106,7 +116,7 @@ class Mage_Webapi_Model_Config_RestTest extends PHPUnit_Framework_TestCase "Some resource methods seem to have different routes, in case when should have the same ones." ); - $this->assertCount($expectedRoutesCount, $actualRoutes, "Routes quantity does not equal to expected one."); + $this->assertCount($expectedRoutesCount, $actualRoutes, "Routes quantity is not equal to expected one."); /** @var $actualRoute Mage_Webapi_Controller_Router_Route_Rest */ foreach ($actualRoutes as $actualRoute) { $this->assertInstanceOf('Mage_Webapi_Controller_Router_Route_Rest', $actualRoute); @@ -161,12 +171,22 @@ class Mage_Webapi_Model_Config_RestTest extends PHPUnit_Framework_TestCase /** Prepare arguments for SUT constructor. */ /** @var Mage_Core_Model_Cache $cache */ $cache = $this->getMockBuilder('Mage_Core_Model_Cache')->disableOriginalConstructor()->getMock(); + $configMock = $this->getMockBuilder('Mage_Core_Model_Config')->disableOriginalConstructor()->getMock(); + $configMock->expects($this->any())->method('getAreaFrontName')->will( + $this->returnValue(self::WEBAPI_AREA_FRONT_NAME) + ); + $appMock = $this->getMockBuilder('Mage_Core_Model_App')->disableOriginalConstructor()->getMock(); + $appMock->expects($this->any())->method('getConfig')->will($this->returnValue($configMock)); + self::$_appClone = clone $appMock; /** @var Mage_Webapi_Model_Config_Reader_Rest $reader */ $reader = $objectManager->get('Mage_Webapi_Model_Config_Reader_Rest', array('cache' => $cache)); $reader->setDirectoryScanner(new Zend\Code\Scanner\DirectoryScanner($pathToResources)); /** Initialize SUT. */ - $apiConfig = $objectManager->create('Mage_Webapi_Model_Config_Rest', array('reader' => $reader)); + $apiConfig = $objectManager->create( + 'Mage_Webapi_Model_Config_Rest', + array('reader' => $reader, 'application' => self::$_appClone) + ); return $apiConfig; } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Soap/DataTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Soap/DataTest.php index c2ea7457eec..b6c65bcf2e0 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Soap/DataTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/Soap/DataTest.php @@ -44,7 +44,7 @@ class Mage_Webapi_Model_Config_Soap_DataTest extends PHPUnit_Framework_TestCase protected $_config; /** - * Set up config with fixture controllers directory scanner + * Set up config with fixture controllers directory scanner. */ protected function setUp() { diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/SoapTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/SoapTest.php index 07d0d2e50df..a53f1e51f91 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/SoapTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Config/SoapTest.php @@ -1,6 +1,6 @@ <?php /** - * File with unit tests for API configuration class: Mage_Webapi_Model_Config_Soap + * File with unit tests for API configuration class: Mage_Webapi_Model_Config_Soap. * * Magento * @@ -42,7 +42,7 @@ require_once __DIR__ . '/../_files/autodiscovery/reference_to_invalid_type/class /**#@-*/ /** - * Test of API configuration class: Mage_Webapi_Model_Config + * Test of API configuration class: Mage_Webapi_Model_Config. */ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase { @@ -137,8 +137,13 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase public function dataProviderTestGetResourceNameByOperationNegative() { return array( - array('customerUpdate', 'v1', false, "In case when resource not found 'false' is expected."), - array('vendorModuleResourceCreate', 'v100', false, "In case when version not found 'false' is expected."), + array('customerUpdate', 'v1', false, "In case when resource is not found, 'false' is expected."), + array( + 'vendorModuleResourceCreate', + 'v100', + false, + "In case when version is not found, 'false' is expected." + ), ); } @@ -160,7 +165,7 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase { return array( array('customerMultiDeleteExcessiveSuffix', 'v2', 'Excessive suffix is ignored.'), - array('customerInvalid', 'v1', "In case when operation not found 'false' is expected."), + array('customerInvalid', 'v1', "In case when operation is not found, 'false' is expected."), ); } @@ -189,7 +194,7 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase 'vendorModuleResourceMultiUpdate', 'v2', 'multiUpdate', - 'Compound method names seem be be identified incorrectly or version processing is broken.' + 'Compound method names seem to be identified incorrectly or version processing is broken.' ), array( 'vendorModuleResourceSubresourceMultiDelete', @@ -197,7 +202,12 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase 'multiDelete', "If version is not set - no check must be performed for operation existence in resource." ), - array('vendorModuleResourceUpdate', 'v100', false, "In case when version not found 'false' is expected."), + array( + 'vendorModuleResourceUpdate', + 'v100', + false, + "In case when version is not found, 'false' is expected." + ), ); } @@ -219,7 +229,7 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase { return array( array('vendorModuleResourceMultiUpdateExcessiveSuffix', 'v2', 'Excessive suffix is ignored.'), - array('vendorModuleResourceInvalid', 'v1', "In case when operation not found 'false' is expected."), + array('vendorModuleResourceInvalid', 'v1', "In case when operation is not found, 'false' is expected."), ); } @@ -247,7 +257,7 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase { return array( array('customerMultiDeleteExcessiveSuffix', 'Excessive suffix is ignored.'), - array('customerInvalid', "In case when operation not found 'false' is expected."), + array('customerInvalid', "In case when operation is not found, 'false' is expected."), ); } @@ -270,7 +280,7 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase $this->assertEquals( $expectedMaxVersion, $this->_getModel()->getResourceMaxVersion($resourceName), - "Resource Maximum available version was identified incorrectly." + "Resource maximum available version was identified incorrectly." ); } @@ -457,7 +467,7 @@ class Mage_Webapi_Model_Config_SoapTest extends PHPUnit_Framework_TestCase ), '@apiDeprecated vendorModuleResource::listV3' ), - array('vendorModuleResource', 'list', 3, false, 'No policy defined.'), + array('vendorModuleResource', 'list', 3, false, 'No policy is defined.'), array( 'vendorModuleResource', 'delete', diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php index 93d8aa38aef..d40957ab062 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Model_Resource_Acl_Role + * Test for Mage_Webapi_Model_Resource_Acl_Role. * * Magento * @@ -26,7 +26,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends PHPUnit_Framework_TestCase { /** - * Test for Mage_Webapi_Model_Resource_Acl_Role::getRolesIds() + * Test for Mage_Webapi_Model_Resource_Acl_Role::getRolesIds(). * * @magentoDataFixture Mage/Webapi/_files/role.php * @magentoDataFixture Mage/Webapi/_files/role_with_rule.php @@ -47,7 +47,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test for Mage_Webapi_Model_Resource_Acl_Role::getRolesList() + * Test for Mage_Webapi_Model_Resource_Acl_Role::getRolesList(). * * @magentoDataFixture Mage/Webapi/_files/role.php * @magentoDataFixture Mage/Webapi/_files/role_with_rule.php @@ -66,7 +66,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test for Mage_Webapi_Model_Resource_Acl_Role::_initUniqueFields() + * Test for Mage_Webapi_Model_Resource_Acl_Role::_initUniqueFields(). * * @expectedException Mage_Core_Exception * @expectedExceptionMessage Role Name already exists. @@ -91,7 +91,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test for Mage_Webapi_Model_Resource_Acl_Role::delete() + * Test for Mage_Webapi_Model_Resource_Acl_Role::delete(). * * @magentoDataFixture Mage/Webapi/_files/user_with_role.php */ diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php index c01442b937f..d16419e7e65 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php @@ -1,6 +1,6 @@ <?php /** - * Test for Mage_Webapi_Model_Resource_Acl_Rule + * Test for Mage_Webapi_Model_Resource_Acl_Rule. * * Magento * @@ -49,7 +49,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Test for Mage_Webapi_Model_Resource_Acl_Role::getRolesIds() + * Test for Mage_Webapi_Model_Resource_Acl_Role::getRolesIds(). */ public function testGetRuleList() { @@ -63,7 +63,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Test for Mage_Webapi_Model_Resource_Acl_Role::getResourceIdsByRole() + * Test for Mage_Webapi_Model_Resource_Acl_Role::getResourceIdsByRole(). */ public function testGetResourceIdsByRole() { diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php index 35863f1542b..032f01ae7fc 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php @@ -77,7 +77,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase protected $_xpath; /** - * Set up config with fixture controllers directory scanner + * Set up config with fixture controllers directory scanner. */ protected function setUp() { @@ -87,7 +87,12 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase $app = $this->getMockBuilder('Mage_Core_Model_App')->disableOriginalConstructor()->getMock(); $objectManager = new Magento_Test_ObjectManager(); $this->_helper = $objectManager->get('Mage_Webapi_Helper_Config'); - $reader = $objectManager->get('Mage_Webapi_Model_Config_Reader_Soap'); + $reader = $objectManager->get( + 'Mage_Webapi_Model_Config_Reader_Soap', + array( + 'cache' => $this->getMock('Mage_Core_Model_Cache', array(), array(), '', false) + ) + ); $reader->setDirectoryScanner($directoryScanner); $this->_config = new Mage_Webapi_Model_Config_Soap($reader, $this->_helper, $app); $objectManager->addSharedInstance($this->_config, 'Mage_Webapi_Model_Config_Soap'); @@ -116,7 +121,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase * Test WSDL operations Generation. * Generate WSDL XML using AutoDiscover and prepared config. * Walk through all methods from "vendorModuleB resource" (_files/controllers/AutoDiscover/ModuleBController.php) - * Assert that service, portType and binding has been generated correctly for resource. + * Assert that service, portType and binding have been generated correctly for resource. * Assert that each method from controller has generated operations in portType and binding nodes. * Assert that each method has input and output messages and complexTypes generated correctly. */ @@ -274,7 +279,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert docInstructions appinfo node and it's subnodes. + * Assert docInstructions appinfo node and its subnodes. * * @param DOMElement $appInfoNode * @param array $appInfoData @@ -297,7 +302,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert 'seeLink' annotation node and it's subnodes. + * Assert 'seeLink' annotation node and its subnodes. * * @param DOMElement $appInfoNode * @param array $appInfoData @@ -324,7 +329,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert 'callInfo' annotation node and it's subnodes. + * Assert 'callInfo' annotation node and its subnodes. * * @param DOMElement $appInfoNode * @param array $appInfoData @@ -360,7 +365,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase $conditionNode = $this->_xpath->query("{$infNs}:{$direction}[text()='{$condition}']", $callNode->parentNode) ->item(0); $this->assertNotNull($conditionNode, - sprintf('"%s" node with value "%s" not found for callName "%s" in element "%s"', $direction, + sprintf('"%s" node with value "%s" was not found for callName "%s" in element "%s"', $direction, $condition, $callName, $elementName)); } } @@ -384,7 +389,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert operation message (input/output) and that message node is present in WSDL + * Assert operation message (input/output) and that message node is present in WSDL. * * @param DOMElement $operationMessage * @param $methodName @@ -412,16 +417,16 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase /** @var DOMElement $message */ $expression = "//{$wsdlNs}:message[@name='{$messageName}']"; $message = $this->_xpath->query($expression)->item(0); - $this->assertNotNull($message, sprintf('Message "%s" not found in WSDL.', $messageName)); + $this->assertNotNull($message, sprintf('Message "%s" is not found in WSDL.', $messageName)); $partXpath = "{$wsdlNs}:part[@element='{$tns}:{$messageName}']"; $messagePart = $this->_xpath->query($partXpath, $message)->item(0); - $this->assertNotNull($messagePart, sprintf('Message part not found in "%s".', $messageName)); + $this->assertNotNull($messagePart, sprintf('Message part is not found in "%s".', $messageName)); return $messageComplexType; } /** - * Assert operation is present in portType node and return it. + * Assert that operation is present in portType node and return it. * * @param $operationName * @param DOMElement $portType @@ -438,7 +443,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert operation is present in binding node. + * Assert that operation is present in binding node. * * @param string $operationName * @param DOMElement $binding @@ -453,7 +458,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert binding node is present and return it. + * Assert that binding node is present and return it. * * @return DOMElement */ @@ -473,7 +478,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase /** @var DOMElement $soapBinding */ $soapBinding = $binding->getElementsByTagNameNS(Wsdl::SOAP_12_NS_URI, 'binding') ->item(0); - $this->assertNotNull($soapBinding, sprintf('Missing soap binding in "%s"', $bindingName)); + $this->assertNotNull($soapBinding, sprintf('SOAP binding in "%s" is missing', $bindingName)); $this->assertTrue($soapBinding->hasAttribute('style')); $this->assertEquals('document', $soapBinding->getAttribute('style')); @@ -481,7 +486,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert port type node is present and return it. + * Assert that portType node is present and return it. * * @return DOMElement */ @@ -499,7 +504,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert port node is present within service node. + * Assert that port node is present within service node. * * @param DOMElement $service */ @@ -507,7 +512,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase { /** @var DOMElement $port */ $port = $service->getElementsByTagName('port')->item(0); - $this->assertNotNull($port, 'port node not found within service node.'); + $this->assertNotNull($port, 'port node is not found within service node.'); $this->assertTrue($port->hasAttribute('name')); $this->assertEquals($this->_autoDiscover->getPortName($this->_resourceName), $port->getAttribute('name')); $bindingName = $this->_autoDiscover->getBindingName($this->_resourceName); @@ -515,7 +520,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Assert service node is present in xml. + * Assert that service node is present in XML. * * @return DOMElement */ @@ -523,7 +528,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase { /** @var DOMElement $service */ $service = $this->_dom->getElementsByTagNameNS(Wsdl::WSDL_NS_URI, 'service')->item(0); - $this->assertNotNull($service, 'service node not found in WSDL.'); + $this->assertNotNull($service, 'service node is not found in WSDL.'); $this->assertTrue($service->hasAttribute('name')); $this->assertEquals($this->_autoDiscover->getServiceName($this->_resourceName), $service->getAttribute('name')); diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php index df1184f2a08..112cfe7bb6e 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php @@ -35,8 +35,8 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor */ protected $_objectManager; - /** @var Mage_Webapi_Model_Acl_User_Factory */ - protected $_userFactory; + /** @var Mage_Webapi_Model_Acl_User */ + protected $_user; /** * Set up object manager and user factory. @@ -44,7 +44,13 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor protected function setUp() { $this->_objectManager = new Magento_Test_ObjectManager(); - $this->_userFactory = new Mage_Webapi_Model_Acl_User_Factory($this->_objectManager); + $this->_objectManager->addSharedInstance( + Mage::getObjectManager()->get('Mage_Core_Model_Dir'), + 'Mage_Core_Model_Dir' + ); + $userFactory = new Mage_Webapi_Model_Acl_User_Factory($this->_objectManager); + $this->_user = $userFactory->create(); + $this->_user->load('test_username', 'api_key'); } /** @@ -53,16 +59,14 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor protected function tearDown() { unset($this->_objectManager); - unset($this->_userFactory); + unset($this->_user); } /** - * Test positive authenticate with text password type. + * Test positive authentication with text password type. */ public function testAuthenticatePasswordText() { - $user = $this->_userFactory->create(); - $user->load('test_username', 'api_key'); /** @var Mage_Webapi_Model_Soap_Security_UsernameToken $usernameToken */ $usernameToken = $this->_objectManager->create('Mage_Webapi_Model_Soap_Security_UsernameToken', array( 'passwordType' => Mage_Webapi_Model_Soap_Security_UsernameToken::PASSWORD_TYPE_TEXT @@ -70,26 +74,25 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor $created = date('c'); $nonce = base64_encode(mt_rand()); - $authenticatedUser = $usernameToken->authenticate($user->getApiKey(), $user->getSecret(), $created, $nonce); - $this->assertEquals($user->getRoleId(), $authenticatedUser->getRoleId()); + $authenticatedUser = $usernameToken->authenticate($this->_user->getApiKey(), $this->_user->getSecret(), + $created, $nonce); + $this->assertEquals($this->_user->getRoleId(), $authenticatedUser->getRoleId()); } /** - * Test positive authenticate with digest password type + * Test positive authentication with digest password type. */ public function testAuthenticatePasswordDigest() { - $user = $this->_userFactory->create(); - $user->load('test_username', 'api_key'); /** @var Mage_Webapi_Model_Soap_Security_UsernameToken $usernameToken */ $usernameToken = $this->_objectManager->create('Mage_Webapi_Model_Soap_Security_UsernameToken'); $created = date('c'); $nonce = mt_rand(); - $password = base64_encode(hash('sha1', $nonce . $created . $user->getSecret(), true)); + $password = base64_encode(hash('sha1', $nonce . $created . $this->_user->getSecret(), true)); $nonce = base64_encode($nonce); - $authenticatedUser = $usernameToken->authenticate($user->getApiKey(), $password, $created, $nonce); - $this->assertEquals($user->getRoleId(), $authenticatedUser->getRoleId()); + $authenticatedUser = $usernameToken->authenticate($this->_user->getApiKey(), $password, $created, $nonce); + $this->assertEquals($this->_user->getRoleId(), $authenticatedUser->getRoleId()); } /** @@ -99,18 +102,16 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor */ public function testAuthenticateWithNonceUsed() { - $user = $this->_userFactory->create(); - $user->load('test_username', 'api_key'); /** @var Mage_Webapi_Model_Soap_Security_UsernameToken $usernameToken */ $usernameToken = $this->_objectManager->create('Mage_Webapi_Model_Soap_Security_UsernameToken'); $created = date('c'); $nonce = mt_rand(); - $password = base64_encode(hash('sha1', $nonce . $created . $user->getSecret(), true)); + $password = base64_encode(hash('sha1', $nonce . $created . $this->_user->getSecret(), true)); $nonce = base64_encode($nonce); - $authenticatedUser = $usernameToken->authenticate($user->getApiKey(), $password, $created, $nonce); - $this->assertEquals($user, $authenticatedUser); + $authenticatedUser = $usernameToken->authenticate($this->_user->getApiKey(), $password, $created, $nonce); + $this->assertEquals($this->_user, $authenticatedUser); // Try to authenticate with the same nonce and timestamp - $usernameToken->authenticate($user->getApiKey(), $password, $created, $nonce); + $usernameToken->authenticate($this->_user->getApiKey(), $password, $created, $nonce); } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/ServerTest.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/ServerTest.php index 928bfe7f8bd..091d243b9f3 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/ServerTest.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/Soap/ServerTest.php @@ -1,6 +1,6 @@ <?php /** - * Test Soap server model. + * Test SOAP server model. * * Magento * @@ -61,38 +61,38 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase } /** - * Test Soap server construction with WSDL cache enabling. + * Test SOAP server construction with WSDL cache enabling. */ public function testConstructEnableWsdlCache() { /** Mock getConfig method to return true. */ $this->_storeMock->expects($this->any())->method('getConfig')->will($this->returnValue(true)); - /** Create Soap server object. */ + /** Create SOAP server object. */ $server = new Mage_Webapi_Model_Soap_Server( $this->_applicationMock, $this->_requestMock, $this->_domDocumentFactory ); $server->initWsdlCache(); - /** Assert soap wsdl caching option was enabled after soap server initialization. */ + /** Assert that SOAP WSDL caching option was enabled after SOAP server initialization. */ $this->assertTrue((bool)ini_get('soap.wsdl_cache_enabled'), 'WSDL caching was not enabled.'); } /** - * Test Soap server construction with WSDL cache disabling. + * Test SOAP server construction with WSDL cache disabling. */ public function testConstructDisableWsdlCache() { /** Mock getConfig method to return false. */ $this->_storeMock->expects($this->any())->method('getConfig')->will($this->returnValue(false)); - /** Create Soap server object. */ + /** Create SOAP server object. */ $server = new Mage_Webapi_Model_Soap_Server( $this->_applicationMock, $this->_requestMock, $this->_domDocumentFactory ); $server->initWsdlCache(); - /** Assert soap wsdl caching option was disabled after soap server initialization. */ + /** Assert that SOAP WSDL caching option was disabled after SOAP server initialization. */ $this->assertFalse((bool)ini_get('soap.wsdl_cache_enabled'), 'WSDL caching was not disabled.'); } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_property_description/class.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_property_description/class.php index c19be66f841..552532e7a0c 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_property_description/class.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_property_description/class.php @@ -31,6 +31,6 @@ class Vendor_Module_Controller_Webapi_Empty_Property_Description */ public function createV1($data) { - // Body is intentionally left empty + // Body is intentionally left empty. } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/class.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/class.php index d0ea0828715..ce5da5bc2ed 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/class.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/class.php @@ -31,6 +31,6 @@ class Vendor_Module_Controller_Webapi_Empty_Var_Tag */ public function createV1($data) { - // Body is intentionally left empty + // Body is intentionally left empty. } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/data_type.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/data_type.php index 116005c9984..822511c2dd3 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/data_type.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/empty_var_tags/data_type.php @@ -26,7 +26,7 @@ class Vendor_Module_Model_Webapi_Property_Without_Var { /** - * Property without var tag + * Property without var tag. */ public $propertyWithoutVar; diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/invalid_deprecation_policy/class.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/invalid_deprecation_policy/class.php index d9183b141a6..50267f1e169 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/invalid_deprecation_policy/class.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/invalid_deprecation_policy/class.php @@ -31,7 +31,7 @@ class Invalid_Deprecation_Controller_Webapi_Policy */ public function getV1() { - // Body was intentionally left empty + // Body was intentionally left empty. } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/no_resources/class.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/no_resources/class.php index 7d542a29406..e41d5994814 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/no_resources/class.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/no_resources/class.php @@ -31,6 +31,6 @@ class Invalid_Resource_Name */ public function createV1($data) { - // Body is intentionally left empty + // Body is intentionally left empty. } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/reference_to_invalid_type/class.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/reference_to_invalid_type/class.php index d0da23c5f47..69557f436f0 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/reference_to_invalid_type/class.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/reference_to_invalid_type/class.php @@ -31,6 +31,6 @@ class Vendor_Module_Controller_Webapi_Invalid_Type */ public function createV1($data) { - // Body is intentionally left empty + // Body is intentionally left empty. } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/several_classes_in_one_file/file_with_classes.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/several_classes_in_one_file/file_with_classes.php index 99c823a51f7..29c7ed4e210 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/several_classes_in_one_file/file_with_classes.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/autodiscovery/several_classes_in_one_file/file_with_classes.php @@ -25,10 +25,10 @@ */ class First_Class { - // Body was intentionally left empty + // Body was intentionally left empty. } class Second_Class { - // Body was intentionally left empty + // Body was intentionally left empty. } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_interface.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_interface.php index f9fc68ea3f1..3c010c77693 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_interface.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_interface.php @@ -33,17 +33,17 @@ class Vendor_Module_Controller_Webapi_Invalid_Interface */ public function updateV1($resourceId) { - // Body is intentionally left empty + // Body is intentionally left empty. } public function updateV2() { - // Body is intentionally left empty + // Body is intentionally left empty. } public function emptyInterfaceV2() { - // Body is intentionally left empty + // Body is intentionally left empty. } /** @@ -51,6 +51,6 @@ class Vendor_Module_Controller_Webapi_Invalid_Interface */ public function invalidMethodNameV2($resourceId) { - // Body is intentionally left empty + // Body is intentionally left empty. } } diff --git a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_name.php b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_name.php index 2eeb636d0f0..320154f5bff 100644 --- a/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_name.php +++ b/dev/tests/integration/testsuite/Mage/Webapi/Model/_files/resource_with_invalid_name.php @@ -33,6 +33,6 @@ class Vendor_Module_Webapi_Resource_Invalid */ public function updateV1($resourceId) { - // Body is intentionally left empty + // Body is intentionally left empty. } } diff --git a/dev/tests/integration/testsuite/Mage/Widget/Model/WidgetTest.php b/dev/tests/integration/testsuite/Mage/Widget/Model/WidgetTest.php index 4d73f963e32..819215a9309 100644 --- a/dev/tests/integration/testsuite/Mage/Widget/Model/WidgetTest.php +++ b/dev/tests/integration/testsuite/Mage/Widget/Model/WidgetTest.php @@ -97,11 +97,16 @@ class Mage_Widget_Model_WidgetTest extends PHPUnit_Framework_TestCase /** * Tests, that theme file is found anywhere in theme folders, not only in module directory. * + * @magentoDataFixture Mage/Widget/_files/themes.php * @magentoAppIsolation enabled */ public function testGetPlaceholderImageUrlAtTheme() { - Mage::getConfig()->getOptions()->setDesignDir(dirname(__DIR__) . '/_files/design'); + Magento_Test_Bootstrap::getInstance()->reinitialize(array( + Mage_Core_Model_App::INIT_OPTION_DIRS => array( + Mage_Core_Model_Dir::THEMES => dirname(__DIR__) . '/_files/design' + ) + )); $actualFile = $this->testGetPlaceholderImageUrl( 'Mage_Catalog_Block_Product_Widget_New', 'Mage_Catalog/images/product_widget_new.gif' diff --git a/dev/tests/integration/testsuite/Mage/Widget/_files/themes.php b/dev/tests/integration/testsuite/Mage/Widget/_files/themes.php new file mode 100644 index 00000000000..947fbd4ff83 --- /dev/null +++ b/dev/tests/integration/testsuite/Mage/Widget/_files/themes.php @@ -0,0 +1,33 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Widget + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +/** @var $registration Mage_Core_Model_Theme_Registration */ +$registration = Mage::getModel('Mage_Core_Model_Theme_Registration'); +$registration->register( + __DIR__ . DIRECTORY_SEPARATOR . 'design', + implode(DIRECTORY_SEPARATOR, array('*', '*', '*', 'theme.xml')) +); diff --git a/dev/tests/integration/testsuite/Mage/Wishlist/Block/AbstractTest.php b/dev/tests/integration/testsuite/Mage/Wishlist/Block/AbstractTest.php index 95a608042c3..d2ff23e03d8 100644 --- a/dev/tests/integration/testsuite/Mage/Wishlist/Block/AbstractTest.php +++ b/dev/tests/integration/testsuite/Mage/Wishlist/Block/AbstractTest.php @@ -44,6 +44,8 @@ class Mage_Wishlist_Block_AbstractTest extends PHPUnit_Framework_TestCase 'Mage_Core_Model_Store_Config', 'Mage_Core_Controller_Varien_Front', 'Mage_Core_Model_Factory_Helper', + 'Mage_Core_Model_Dir', + 'Mage_Core_Model_Logger', 'Magento_Filesystem', ); @@ -81,7 +83,7 @@ class Mage_Wishlist_Block_AbstractTest extends PHPUnit_Framework_TestCase { $arguments = array(); foreach ($this->_blockInjections as $injectionClass) { - $arguments[] = Mage::getModel($injectionClass); + $arguments[] = Mage::getObjectManager()->get($injectionClass); } return $arguments; } diff --git a/dev/tests/integration/testsuite/Magento/Di/GeneratorTest.php b/dev/tests/integration/testsuite/Magento/Di/GeneratorTest.php index 971b60ea01e..da42f8feb9a 100644 --- a/dev/tests/integration/testsuite/Magento/Di/GeneratorTest.php +++ b/dev/tests/integration/testsuite/Magento/Di/GeneratorTest.php @@ -47,9 +47,9 @@ class Magento_Di_GeneratorTest extends PHPUnit_Framework_TestCase { $this->_includePath = get_include_path(); - /** @var $config Mage_Core_Model_Config */ - $config = Mage::getObjectManager()->get('Mage_Core_Model_Config'); - $generationDirectory = $config->getVarDir() . '/generation'; + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = Mage::getObjectManager()->get('Mage_Core_Model_Dir'); + $generationDirectory = $dirs->getDir(Mage_Core_Model_Dir::VAR_DIR) . '/generation'; Magento_Autoload_IncludePath::addIncludePath($generationDirectory); @@ -63,9 +63,9 @@ class Magento_Di_GeneratorTest extends PHPUnit_Framework_TestCase protected function tearDown() { - /** @var $config Mage_Core_Model_Config */ - $config = Mage::getObjectManager()->get('Mage_Core_Model_Config'); - $generationDirectory = $config->getVarDir() . '/generation'; + /** @var $dirs Mage_Core_Model_Dir */ + $dirs = Mage::getObjectManager()->get('Mage_Core_Model_Dir'); + $generationDirectory = $dirs->getDir(Mage_Core_Model_Dir::VAR_DIR) . '/generation'; Varien_Io_File::rmdirRecursive($generationDirectory); set_include_path($this->_includePath); diff --git a/dev/tests/integration/testsuite/Magento/Filesystem/Adapter/LocalTest.php b/dev/tests/integration/testsuite/Magento/Filesystem/Adapter/LocalTest.php index 029feab6d87..1bccb1871ed 100644 --- a/dev/tests/integration/testsuite/Magento/Filesystem/Adapter/LocalTest.php +++ b/dev/tests/integration/testsuite/Magento/Filesystem/Adapter/LocalTest.php @@ -342,28 +342,32 @@ class Magento_Filesystem_Adapter_LocalTest extends PHPUnit_Framework_TestCase */ public function testGetNestedKeys($path, $expectedKeys) { - $this->assertEquals($expectedKeys, $this->_adapter->getNestedKeys($path)); + $actualKeys = $this->_adapter->getNestedKeys($path); + $this->assertEquals(sort($expectedKeys), sort($actualKeys)); } /** * @return array + * + * @SuppressWarnings(PHPMD.ShortVariable) */ public function getNestedKeysDataProvider() { + $ds = Magento_Filesystem::DIRECTORY_SEPARATOR; return array( array( $this->_getFixturesPath() . 'foo', array( - $this->_getFixturesPath() . 'foo' . DS . 'bar' . DS . 'baz' . DS . 'file_one.txt', - $this->_getFixturesPath() . 'foo' . DS . 'bar' . DS . 'baz', - $this->_getFixturesPath() . 'foo' . DS . 'bar' . DS . 'file_two.txt', - $this->_getFixturesPath() . 'foo' . DS . 'bar', - $this->_getFixturesPath() . 'foo' . DS . 'file_three.txt', + $this->_getFixturesPath() . 'foo' . $ds . 'bar' . $ds . 'baz' . $ds . 'file_one.txt', + $this->_getFixturesPath() . 'foo' . $ds . 'bar' . $ds . 'baz', + $this->_getFixturesPath() . 'foo' . $ds . 'bar' . $ds . 'file_two.txt', + $this->_getFixturesPath() . 'foo' . $ds . 'bar', + $this->_getFixturesPath() . 'foo' . $ds . 'file_three.txt', ) ), array( - $this->_getFixturesPath() . 'foo' . DS . 'bar' . DS . 'baz', - array($this->_getFixturesPath() . 'foo' . DS . 'bar' . DS . 'baz' . DS . 'file_one.txt') + $this->_getFixturesPath() . 'foo' . $ds . 'bar' . $ds . 'baz', + array($this->_getFixturesPath() . 'foo' . $ds . 'bar' . $ds . 'baz' . $ds . 'file_one.txt') ) ); } @@ -389,21 +393,24 @@ class Magento_Filesystem_Adapter_LocalTest extends PHPUnit_Framework_TestCase /** * @return array + * + * @SuppressWarnings(PHPMD.ShortVariable) */ public function getNestedFilesDataProvider() { + $ds = Magento_Filesystem::DIRECTORY_SEPARATOR; return array( array( $this->_getFixturesPath() . 'foo/*', array( - $this->_getFixturesPath() . 'foo' . DS . 'bar', - $this->_getFixturesPath() . 'foo' . DS . 'file_three.txt', + $this->_getFixturesPath() . 'foo' . $ds . 'bar', + $this->_getFixturesPath() . 'foo' . $ds . 'file_three.txt', ) ), array( $this->_getFixturesPath() . 'foo/*/file_*', array( - $this->_getFixturesPath() . 'foo' . DS . 'bar' . DS . 'file_two.txt', + $this->_getFixturesPath() . 'foo' . $ds . 'bar' . $ds . 'file_two.txt', ) ) ); diff --git a/dev/tests/integration/testsuite/MemoryUsageTest.php b/dev/tests/integration/testsuite/MemoryUsageTest.php new file mode 100644 index 00000000000..92b80dfade9 --- /dev/null +++ b/dev/tests/integration/testsuite/MemoryUsageTest.php @@ -0,0 +1,192 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Core + * @subpackage integration_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class MemoryUsageTest extends PHPUnit_Framework_TestCase +{ + /** + * Number of application reinitialization iterations to be conducted by tests + */ + const APP_REINITIALIZATION_LOOPS = 20; + + /** + * Test that application reinitialization produces no memory leaks + */ + public function testAppReinitializationNoMemoryLeak() + { + $this->_deallocateUnusedMemory(); + $actualMemoryUsage = $this->_getRealMemoryUsage(); + for ($i = 0; $i < self::APP_REINITIALIZATION_LOOPS; $i++) { + Magento_Test_Bootstrap::getInstance()->reinitialize(); + $this->_deallocateUnusedMemory(); + } + $actualMemoryUsage = $this->_getRealMemoryUsage() - $actualMemoryUsage; + $this->assertLessThanOrEqual($this->_getAllowedMemoryUsage(), $actualMemoryUsage, sprintf( + "Application reinitialization causes the memory leak of %u bytes per %u iterations.", + $actualMemoryUsage, + self::APP_REINITIALIZATION_LOOPS + )); + } + + /** + * Force to deallocate no longer used memory + */ + protected function _deallocateUnusedMemory() + { + gc_collect_cycles(); + } + + /** + * Retrieve the allowed memory usage in bytes, depending on the environment + * + * @return int + */ + protected function _getAllowedMemoryUsage() + { + // Memory usage limits should not be further increased, corresponding memory leaks have to be fixed instead! + if ($this->_isWindowsOs()) { + return $this->_convertToBytes('1M'); + } + return 0; + } + + /** + * Whether the operating system belongs to the Windows family + * + * @link http://php.net/manual/en/function.php-uname.php + * @return bool + */ + protected function _isWindowsOs() + { + return (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); + } + + /** + * Retrieve the effective memory usage of the current process + * + * memory_get_usage() cannot be used because of the bug + * @link https://bugs.php.net/bug.php?id=62467 + * + * @return int Memory usage in bytes + */ + protected function _getRealMemoryUsage() + { + $pid = getmypid(); + $shell = new Magento_Shell(); + if ($this->_isWindowsOs()) { + $result = $this->_getWinProcessMemoryUsage($shell, $pid); + } else { + $result = $this->_getUnixProcessMemoryUsage($shell, $pid); + } + return $result; + } + + /** + * Retrieve the current process' memory usage using Unix command line interface + * + * @param Magento_Shell $shell + * @param int $pid + * @return int Memory usage in bytes + */ + protected function _getUnixProcessMemoryUsage(Magento_Shell $shell, $pid) + { + /** + * @link http://linux.die.net/man/1/top + * + * Output format invariant: + * PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND + * 12345 root 20 0 215m 36m 10m S 98 0.5 0:32.96 php + */ + $output = $shell->execute('top -p %s -n 1 -b | grep PID -A 1', array($pid)); + + $output = preg_split('/\n+/', $output, -1, PREG_SPLIT_NO_EMPTY); + $keys = preg_split('/\s+/', $output[0], -1, PREG_SPLIT_NO_EMPTY); + $values = preg_split('/\s+/', $output[1], -1, PREG_SPLIT_NO_EMPTY); + $stats = array_combine($keys, $values); + + $result = $stats['RES']; // resident set size, the non-swapped physical memory + + if (is_numeric($result)) { + $result .= 'k'; // kilobytes by default + } + + return $this->_convertToBytes($result); + } + + /** + * Retrieve the current process' memory usage using Windows command line interface + * + * @param Magento_Shell $shell + * @param int $pid + * @return int Memory usage in bytes + */ + protected function _getWinProcessMemoryUsage(Magento_Shell $shell, $pid) + { + /** + * @link http://technet.microsoft.com/en-us/library/bb491010.aspx + * + * Output format invariant: + * "Image Name","PID","Session Name","Session#","Mem Usage" + * "php.exe","12345","N/A","0","26,321 K" + */ + $output = $shell->execute('tasklist /fi %s /fo CSV', array("PID eq $pid")); + + /** @link http://www.php.net/manual/en/wrappers.data.php */ + $csvStream = 'data://text/plain;base64,' . base64_encode($output); + $csvHandle = fopen($csvStream, 'r'); + $keys = fgetcsv($csvHandle); + $values = fgetcsv($csvHandle); + fclose($csvHandle); + $stats = array_combine($keys, $values); + + $result = $stats['Mem Usage']; + + return $this->_convertToBytes($result); + } + + /** + * Convert a number optionally followed by the unit symbol (B, K, M, G, etc.) to bytes + * + * @param string $number String representation of a number + * @return int + * @throws InvalidArgumentException + */ + protected function _convertToBytes($number) + { + $number = str_replace(array(',', ' '), '', $number); + $number = strtoupper($number); + $units = 'BKMGTPEZY'; + if (!preg_match("/^(\d+(?:\.\d+)?)([$units]?)$/", $number, $matches)) { + throw new InvalidArgumentException("Number format '$number' is not recognized."); + } + $result = (float)$matches[1]; + $unitSymbol = $matches[2]; + if ($unitSymbol) { + $result *= pow(1024, strpos($units, $unitSymbol)); + } + return (int)$result; + } +} diff --git a/dev/tests/integration/testsuite/Varien/Db/Adapter/Pdo/MysqlTest.php b/dev/tests/integration/testsuite/Varien/Db/Adapter/Pdo/MysqlTest.php index 79877153058..0036e5e65ed 100644 --- a/dev/tests/integration/testsuite/Varien/Db/Adapter/Pdo/MysqlTest.php +++ b/dev/tests/integration/testsuite/Varien/Db/Adapter/Pdo/MysqlTest.php @@ -31,23 +31,20 @@ class Varien_Db_Adapter_Pdo_MysqlTest extends PHPUnit_Framework_TestCase { /** - * DB connection instance + * Database adapter instance * * @var Varien_Db_Adapter_Pdo_Mysql */ - protected $_connection = null; - + protected $_dbAdapter = null; protected function tearDown() { - $this->_connection = null; + $this->_dbAdapter = null; } /** * Test lost connection re-initializing * - * @covers Varien_Db_Adapter_Pdo_Mysql::raw_query - * @covers Varien_Db_Adapter_Pdo_Mysql::query * @throws Exception */ public function testWaitTimeout() @@ -55,7 +52,7 @@ class Varien_Db_Adapter_Pdo_MysqlTest extends PHPUnit_Framework_TestCase if (Magento_Test_Bootstrap::getInstance()->getDbVendorName() != 'mysql') { $this->markTestSkipped('Test is designed to run on MySQL only.'); } - if (!($this->_getConnection() instanceof Varien_Db_Adapter_Pdo_Mysql)) { + if (!($this->_getDbAdapter() instanceof Varien_Db_Adapter_Pdo_Mysql)) { $this->markTestSkipped('This test is for Varien_Db_Adapter_Pdo_Mysql'); } try { @@ -66,14 +63,14 @@ class Varien_Db_Adapter_Pdo_MysqlTest extends PHPUnit_Framework_TestCase // Sleep for time greater than wait_timeout and try to perform query sleep($minWaitTimeout + 1); - $result = $this->_getConnection()->raw_query('SELECT 1'); + $result = $this->_executeQuery('SELECT 1'); $this->assertInstanceOf('Varien_Db_Statement_Pdo_Mysql', $result); // Restore wait_timeout $this->_setWaitTimeout($defaultWaitTimeout); $this->assertEquals($defaultWaitTimeout, $this->_getWaitTimeout(), 'Default wait timeout was not restored'); } catch (Exception $e) { // Reset connection on failure to restore global variables - $this->_getConnection()->closeConnection(); + $this->_getDbAdapter()->closeConnection(); throw $e; } } @@ -85,7 +82,8 @@ class Varien_Db_Adapter_Pdo_MysqlTest extends PHPUnit_Framework_TestCase */ protected function _getWaitTimeout() { - return (int) $this->_getConnection()->fetchOne('SELECT @@wait_timeout'); + $result = $this->_executeQuery('SELECT @@session.wait_timeout'); + return (int)$result->fetchColumn(); } /** @@ -95,21 +93,51 @@ class Varien_Db_Adapter_Pdo_MysqlTest extends PHPUnit_Framework_TestCase */ protected function _setWaitTimeout($waitTimeout) { - $this->_getConnection()->query("SET wait_timeout = {$waitTimeout}"); + $this->_executeQuery("SET @@session.wait_timeout = {$waitTimeout}"); + } + + /** + * Execute SQL query and return result statement instance + * + * @param string $sql + * @return Zend_Db_Statement_Interface + * @throws Exception + */ + protected function _executeQuery($sql) + { + /** + * Suppress PDO warnings to work around the bug + * @link https://bugs.php.net/bug.php?id=63812 + */ + $phpErrorReporting = error_reporting(); + /** @var $pdoConnection PDO */ + $pdoConnection = $this->_getDbAdapter()->getConnection(); + $pdoWarningsEnabled = $pdoConnection->getAttribute(PDO::ATTR_ERRMODE) & PDO::ERRMODE_WARNING; + if (!$pdoWarningsEnabled) { + error_reporting($phpErrorReporting & ~E_WARNING); + } + try { + $result = $this->_getDbAdapter()->query($sql); + error_reporting($phpErrorReporting); + } catch (Exception $e) { + error_reporting($phpErrorReporting); + throw $e; + } + return $result; } /** - * Get DB connection + * Retrieve database adapter instance * * @return Varien_Db_Adapter_Pdo_Mysql */ - protected function _getConnection() + protected function _getDbAdapter() { - if (is_null($this->_connection)) { + if (is_null($this->_dbAdapter)) { /** @var $coreResource Mage_Core_Model_Resource */ $coreResource = Mage::getSingleton('Mage_Core_Model_Resource'); - $this->_connection = $coreResource->getConnection(Mage_Core_Model_Resource::DEFAULT_WRITE_RESOURCE); + $this->_dbAdapter = $coreResource->getConnection(Mage_Core_Model_Resource::DEFAULT_WRITE_RESOURCE); } - return $this->_connection; + return $this->_dbAdapter; } } diff --git a/dev/tests/integration/testsuite/Varien/Image/Adapter/InterfaceTest.php b/dev/tests/integration/testsuite/Varien/Image/Adapter/InterfaceTest.php index 01cc27f9474..68e2c285706 100644 --- a/dev/tests/integration/testsuite/Varien/Image/Adapter/InterfaceTest.php +++ b/dev/tests/integration/testsuite/Varien/Image/Adapter/InterfaceTest.php @@ -244,7 +244,7 @@ class Varien_Image_Adapter_InterfaceTest extends PHPUnit_Framework_TestCase public function saveDataProvider() { - $dir = Magento_Test_Bootstrap::getInstance()->getTmpDir() . DIRECTORY_SEPARATOR; + $dir = Magento_Test_Bootstrap::getInstance()->getInstallDir() . DIRECTORY_SEPARATOR; return $this->_prepareData(array( array( $this->_getFixture('image_adapters_test.png'), diff --git a/dev/tests/integration/testsuite/integrity/modular/AclConfigFilesTest.php b/dev/tests/integration/testsuite/integrity/modular/AclConfigFilesTest.php index 4e69671d377..6ef04333c32 100644 --- a/dev/tests/integration/testsuite/integrity/modular/AclConfigFilesTest.php +++ b/dev/tests/integration/testsuite/integrity/modular/AclConfigFilesTest.php @@ -50,8 +50,6 @@ class Integrity_Modular_AclConfigFilesTest extends PHPUnit_Framework_TestCase /** * Prepare file list of ACL resources - * - * @return void */ protected function _prepareFileList() { diff --git a/dev/tests/integration/testsuite/integrity/modular/TemplateFilesTest.php b/dev/tests/integration/testsuite/integrity/modular/TemplateFilesTest.php index 762a3d49d30..4df52e3ad6d 100644 --- a/dev/tests/integration/testsuite/integrity/modular/TemplateFilesTest.php +++ b/dev/tests/integration/testsuite/integrity/modular/TemplateFilesTest.php @@ -57,8 +57,7 @@ class Integrity_Modular_TemplateFilesTest extends Magento_Test_TestCase_Integrit { /** @var $website Mage_Core_Model_Website */ $website = Mage::getModel('Mage_Core_Model_Website'); - Mage::app()->getStore()->setWebsiteId(0)->setWebsite($website); - + Mage::app()->getStore()->setWebsiteId(0); $templates = array(); foreach (Utility_Classes::collectModuleClasses('Block') as $blockClass => $module) { @@ -85,7 +84,8 @@ class Integrity_Modular_TemplateFilesTest extends Magento_Test_TestCase_Integrit $block = Mage::getModel($blockClass); $template = $block->getTemplate(); if ($template) { - $templates[] = array($module, $template, $blockClass, $area); + $templates[$module . ', ' . $template . ', ' . $blockClass . ', ' . $area] = + array($module, $template, $blockClass, $area); } } return $templates; diff --git a/dev/tests/performance/run_scenarios.php b/dev/tests/performance/run_scenarios.php index 0c98de2a57b..fce5308b7ab 100755 --- a/dev/tests/performance/run_scenarios.php +++ b/dev/tests/performance/run_scenarios.php @@ -29,7 +29,11 @@ /** @var $config Magento_Performance_Config */ $config = require_once __DIR__ . '/framework/bootstrap.php'; -$shell = new Magento_Shell(true); +$logWriter = new Zend_Log_Writer_Stream('php://output'); +$logWriter->setFormatter(new Zend_Log_Formatter_Simple('%message%' . PHP_EOL)); +$logger = new Zend_Log($logWriter); + +$shell = new Magento_Shell($logger); $scenarioHandler = new Magento_Performance_Scenario_Handler_FileFormat(); $scenarioHandler ->register('jmx', new Magento_Performance_Scenario_Handler_Jmeter($shell)) @@ -41,15 +45,17 @@ $testsuite = new Magento_Performance_Testsuite($config, new Magento_Application( $scenarioTotalCount = count($config->getScenarios()); $scenarioCount = 1; $scenarioFailCount = 0; -$testsuite->onScenarioRun(function (Magento_Performance_Scenario $scenario) use (&$scenarioCount, $scenarioTotalCount) { - echo "Scenario $scenarioCount of $scenarioTotalCount: '{$scenario->getTitle()}'" . PHP_EOL; - $scenarioCount++; -}); +$testsuite->onScenarioRun( + function (Magento_Performance_Scenario $scenario) use ($logger, &$scenarioCount, $scenarioTotalCount) { + $logger->log("Scenario $scenarioCount of $scenarioTotalCount: '{$scenario->getTitle()}'", Zend_Log::INFO); + $scenarioCount++; + } +); $testsuite->onScenarioFailure( - function (Magento_Performance_Scenario_FailureException $scenarioFailure) use (&$scenarioFailCount) { + function (Magento_Performance_Scenario_FailureException $scenarioFailure) use ($logger, &$scenarioFailCount) { $scenario = $scenarioFailure->getScenario(); - echo "Scenario '{$scenario->getTitle()}' has failed!" . PHP_EOL - . $scenarioFailure->getMessage() . PHP_EOL . PHP_EOL; + $logger->log("Scenario '{$scenario->getTitle()}' has failed!", Zend_Log::ERR); + $logger->log($scenarioFailure->getMessage(), Zend_Log::ERR); $scenarioFailCount++; } ); @@ -57,8 +63,8 @@ $testsuite->onScenarioFailure( $testsuite->run(); if ($scenarioFailCount) { - echo "Failed $scenarioFailCount of $scenarioTotalCount scenario(s)" . PHP_EOL; + $logger->log("Failed $scenarioFailCount of $scenarioTotalCount scenario(s)", Zend_Log::INFO); exit(1); } else { - echo 'Successful' . PHP_EOL; + $logger->log('Successful', Zend_Log::INFO); } diff --git a/dev/tests/static/framework/CodingStandard/Tool/CodeSniffer.php b/dev/tests/static/framework/CodingStandard/Tool/CodeSniffer.php index a2d11e997c3..13780feaecd 100644 --- a/dev/tests/static/framework/CodingStandard/Tool/CodeSniffer.php +++ b/dev/tests/static/framework/CodingStandard/Tool/CodeSniffer.php @@ -56,6 +56,7 @@ class CodingStandard_Tool_CodeSniffer implements CodingStandard_ToolInterface * * @param string $rulesetDir Directory that locates the inspection rules * @param string $reportFile Destination file to write inspection report to + * @param CodingStandard_Tool_CodeSniffer_Wrapper $wrapper */ public function __construct($rulesetDir, $reportFile, CodingStandard_Tool_CodeSniffer_Wrapper $wrapper) { @@ -110,4 +111,13 @@ class CodingStandard_Tool_CodeSniffer implements CodingStandard_ToolInterface return $result; } + /** + * Get report file + * + * @return string + */ + public function getReportFile() + { + return $this->_reportFile; + } } diff --git a/dev/tests/static/framework/tests/unit/testsuite/CodingStandard/Tool/CodeSnifferTest.php b/dev/tests/static/framework/tests/unit/testsuite/CodingStandard/Tool/CodeSnifferTest.php index baa50c33e45..47b475b5b2b 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/CodingStandard/Tool/CodeSnifferTest.php +++ b/dev/tests/static/framework/tests/unit/testsuite/CodingStandard/Tool/CodeSnifferTest.php @@ -82,4 +82,9 @@ class CodingStandard_Tool_CodeSnifferTest extends PHPUnit_Framework_TestCase $this->_tool->run($whiteList, $blackList, $extensions); } + + public function testGetReportFile() + { + $this->assertEquals(self::REPORT_FILE, $this->_tool->getReportFile()); + } } diff --git a/dev/tests/static/testsuite/Js/_files/blacklist/ee.txt b/dev/tests/static/testsuite/Js/_files/blacklist/ee.txt deleted file mode 100644 index 373ec3a9d98..00000000000 --- a/dev/tests/static/testsuite/Js/_files/blacklist/ee.txt +++ /dev/null @@ -1,2 +0,0 @@ -app/code/core/Enterprise/Cms/view/adminhtml/cms.js -app/code/core/Enterprise/Rma/view/adminhtml/rma.js diff --git a/dev/tests/static/testsuite/Legacy/ConfigTest.php b/dev/tests/static/testsuite/Legacy/ConfigTest.php index 7de62090a3c..9490ff3602d 100644 --- a/dev/tests/static/testsuite/Legacy/ConfigTest.php +++ b/dev/tests/static/testsuite/Legacy/ConfigTest.php @@ -51,6 +51,9 @@ class Legacy_ConfigTest extends PHPUnit_Framework_TestCase 'Event has been replaced with "core_layout_render_element"', '/config/*/events/catalog_controller_product_delete' => '', '/config//observers/*/args' => 'This was an undocumented and unused feature in event subscribers', + '/config/default/design/theme' => 'Relocated to /config/<area>/design/theme', + '/config/default/web/*/base_js_url' => 'See /config/default/web/*/base_lib_url', + '/config/default/web/*/base_skin_url' => '', ); $xml = simplexml_load_file($file); foreach ($obsoleteNodes as $xpath => $suggestion) { diff --git a/dev/tests/static/testsuite/Legacy/EmailTemplateTest.php b/dev/tests/static/testsuite/Legacy/EmailTemplateTest.php index 65bda42b5c9..de5241a5b86 100644 --- a/dev/tests/static/testsuite/Legacy/EmailTemplateTest.php +++ b/dev/tests/static/testsuite/Legacy/EmailTemplateTest.php @@ -36,11 +36,10 @@ class Legacy_EmailTemplateTest extends PHPUnit_Framework_TestCase */ public function testObsoleteDirectives($file) { - $suggestion = sprintf(Legacy_ObsoleteCodeTest::SUGGESTION_MESSAGE, '{{escapehtml}}'); $this->assertNotRegExp( '/\{\{htmlescape.*?\}\}/i', file_get_contents($file), - 'Directive {{htmlescape}} is obsolete. ' . $suggestion + 'Directive {{htmlescape}} is obsolete. Use {{escapehtml}} instead.' ); } diff --git a/dev/tests/static/testsuite/Legacy/LayoutTest.php b/dev/tests/static/testsuite/Legacy/LayoutTest.php index c1b3f980734..d469ed1197f 100644 --- a/dev/tests/static/testsuite/Legacy/LayoutTest.php +++ b/dev/tests/static/testsuite/Legacy/LayoutTest.php @@ -101,7 +101,6 @@ class Legacy_LayoutTest extends PHPUnit_Framework_TestCase */ public function testLayoutFile($layoutFile) { - $suggestion = sprintf(Legacy_ObsoleteCodeTest::SUGGESTION_MESSAGE, 'addCss/addJss'); $layoutXml = simplexml_load_file($layoutFile); $this->_testObsoleteReferences($layoutXml); @@ -113,7 +112,7 @@ class Legacy_LayoutTest extends PHPUnit_Framework_TestCase $layoutXml->xpath( '//*[' . $selectorHeadBlock . ']/action[@method="addItem"]' ), - "Mage_Page_Block_Html_Head::addItem is obsolete. $suggestion" + 'Mage_Page_Block_Html_Head::addItem is obsolete. Use addCss()/addJs() instead.' ); $this->assertSame(array(), $layoutXml->xpath( diff --git a/dev/tests/static/testsuite/Legacy/ObsoleteCodeTest.php b/dev/tests/static/testsuite/Legacy/ObsoleteCodeTest.php index b602d5168d7..1a6fd978b7c 100644 --- a/dev/tests/static/testsuite/Legacy/ObsoleteCodeTest.php +++ b/dev/tests/static/testsuite/Legacy/ObsoleteCodeTest.php @@ -36,12 +36,92 @@ class Legacy_ObsoleteCodeTest extends PHPUnit_Framework_TestCase */ const SUGGESTION_MESSAGE = 'Use "%s" instead.'; - /** - * In-memory cache for the configuration files + /**@#+ + * Lists of obsolete entities from fixtures * * @var array */ - protected static $_configFilesCache = array(); + protected static $_classes = array(); + protected static $_constants = array(); + protected static $_methods = array(); + protected static $_attributes = array(); + /**#@-*/ + + /** + * Read fixtures into memory as arrays + */ + public static function setUpBeforeClass() + { + $errors = array(); + self::_populateList(self::$_classes, $errors, 'obsolete_classes*.php', false); + self::_populateList(self::$_constants, $errors, 'obsolete_constants*.php'); + self::_populateList(self::$_methods, $errors, 'obsolete_methods*.php'); + self::_populateList(self::$_attributes, $errors, 'obsolete_properties*.php'); + if ($errors) { + $message = 'Duplicate patterns identified in list declarations:' . PHP_EOL . PHP_EOL; + foreach ($errors as $file => $list) { + $message .= $file . PHP_EOL; + foreach ($list as $key) { + $message .= " {$key}" . PHP_EOL; + } + $message .= PHP_EOL; + } + throw new Exception($message); + } + } + + /** + * Read the specified file pattern and merge it with the list + * + * Duplicate entries will be recorded into errors array. + * + * @param array $list + * @param array $errors + * @param string $filePattern + * @param bool $hasScope + */ + protected static function _populateList(array &$list, array &$errors, $filePattern, $hasScope = true) + { + + foreach (glob(__DIR__ . '/_files/' . $filePattern) as $file) { + foreach (self::_readList($file) as $row) { + list($item, $scope, $replacement) = self::_padRow($row, $hasScope); + $key = "{$item}|{$scope}"; + if (isset($list[$key])) { + $errors[$file][] = $key; + } else { + $list[$key] = array($item, $scope, $replacement); + } + } + } + } + + /** + * Populate insufficient row elements regarding to whether the row supposed to have scope value + * + * @param array $row + * @param bool $hasScope + * @return array + */ + protected static function _padRow($row, $hasScope) + { + if ($hasScope) { + return array_pad($row, 3, ''); + } + list($item, $replacement) = array_pad($row, 2, ''); + return array($item, '', $replacement); + } + + /** + * Isolate including a file into a method to reduce scope + * + * @param $file + * @return array + */ + protected static function _readList($file) + { + return include($file); + } /** * @param string $file @@ -50,12 +130,14 @@ class Legacy_ObsoleteCodeTest extends PHPUnit_Framework_TestCase public function testPhpFile($file) { $content = file_get_contents($file); - $this->_testObsoleteClasses($content, $file); - $this->_testObsoleteMethods($content, $file); + $this->_testObsoleteClasses($content); + $this->_testObsoleteMethods($content); + $this->_testGetChildSpecialCase($content, $file); + $this->_testGetOptionsSpecialCase($content); $this->_testObsoleteMethodArguments($content); - $this->_testObsoleteProperties($content, $file); - $this->_testObsoleteActions($content, $file); - $this->_testObsoleteConstants($content, $file); + $this->_testObsoleteProperties($content); + $this->_testObsoleteActions($content); + $this->_testObsoleteConstants($content); $this->_testObsoletePropertySkipCalculate($content); } @@ -105,34 +187,82 @@ class Legacy_ObsoleteCodeTest extends PHPUnit_Framework_TestCase /** * @param string $content - * @param string $file */ - protected function _testObsoleteClasses($content, $file) + protected function _testObsoleteClasses($content) { - $declarations = $this->_getRelevantConfigEntities('obsolete_classes*.php', $content, $file); - foreach ($declarations as $declaration) { - list($entity, $suggestion) = $declaration; + foreach (self::$_classes as $row) { + list($entity, , $suggestion) = $row; $this->_assertNotRegExp('/[^a-z\d_]' . preg_quote($entity, '/') . '[^a-z\d_]/iS', $content, - "Class '$entity' is obsolete. $suggestion" + sprintf("Class '%s' is obsolete. Replacement suggestion: %s", $entity, $suggestion) ); } } /** + * Determine if content should be skipped based on specified class scope + * + * @param string $content + * @param string $class + * @return bool + */ + protected function _isClassSkipped($content, $class) + { + $regexp = '/(class|extends)\s+' . preg_quote($class, '/') . '(\s|;)/S'; + /* Note: strpos is used just to prevent excessive preg_match calls */ + if ($class && (!strpos($content, $class) || !preg_match($regexp, $content))) { + return true; + } + return false; + } + + /** + * @param string $content + */ + protected function _testObsoleteMethods($content) + { + foreach (self::$_methods as $row) { + list($method, $class, $suggestion) = $row; + if (!$this->_isClassSkipped($content, $class)) { + $this->_assertNotRegExp('/[^a-z\d_]' . preg_quote($method, '/') . '\s*\(/iS', $content, + sprintf("Method '%s' is obsolete. Replacement suggestion: %s", $method, $suggestion) + ); + } + } + } + + /** + * Special case: don't allow usage of getChild() method anywhere within app directory + * + * In Magento 1.x it used to belong only to abstract block (therefore all blocks) + * At the same time, the name is pretty generic and can be encountered in other directories, such as lib + * * @param string $content * @param string $file */ - protected function _testObsoleteMethods($content, $file) + protected function _testGetChildSpecialCase($content, $file) { - $declarations = $this->_getRelevantConfigEntities('obsolete_methods*.php', $content, $file); - foreach ($declarations as $declaration) { - list($method, $suggestion) = $declaration; - $this->_assertNotRegExp('/[^a-z\d_]' . preg_quote($method, '/') . '\s*\(/iS', $content, - "Method '$method' is obsolete. $suggestion" + if (0 === strpos($file, Utility_Files::init()->getPathToSource() . '/app/')) { + $this->_assertNotRegexp('/[^a-z\d_]getChild\s*\(/iS', $content, + 'Block method getChild() is obsolete. Replacement suggestion: Mage_Core_Block_Abstract::getChildBlock()' ); } } + /** + * Special case for ->getConfig()->getOptions()-> + * + * @param string $content + */ + protected function _testGetOptionsSpecialCase($content) + { + $this->_assertNotRegexp( + '/getOptions\(\)\s*->get(Base|App|Code|Design|Etc|Lib|Locale|Js|Media' + .'|Var|Tmp|Cache|Log|Session|Upload|Export)?Dir\(/S', + $content, + 'The class Mage_Core_Model_Config_Options is obsolete. Replacement suggestion: Mage_Core_Model_Dir' + ); + } + /** * @param string $content */ @@ -168,16 +298,16 @@ class Legacy_ObsoleteCodeTest extends PHPUnit_Framework_TestCase /** * @param string $content - * @param string $file */ - protected function _testObsoleteProperties($content, $file) + protected function _testObsoleteProperties($content) { - $declarations = $this->_getRelevantConfigEntities('obsolete_properties*.php', $content, $file); - foreach ($declarations as $declaration) { - list($entity, $suggestion) = $declaration; - $this->_assertNotRegExp('/[^a-z\d_]' . preg_quote($entity, '/') . '[^a-z\d_]/iS', $content, - "Property '$entity' is obsolete. $suggestion" - ); + foreach (self::$_attributes as $row) { + list($attribute, $class, $suggestion) = $row; + if (!$this->_isClassSkipped($content, $class)) { + $this->_assertNotRegExp('/[^a-z\d_]' . preg_quote($attribute, '/') . '[^a-z\d_]/iS', $content, + sprintf("Class attribute '%s' is obsolete. Replacement suggestion: %s", $attribute, $suggestion) + ); + } } } @@ -194,16 +324,16 @@ class Legacy_ObsoleteCodeTest extends PHPUnit_Framework_TestCase /** * @param string $content - * @param string $file */ - protected function _testObsoleteConstants($content, $file) + protected function _testObsoleteConstants($content) { - $declarations = $this->_getRelevantConfigEntities('obsolete_constants*.php', $content, $file); - foreach ($declarations as $declaration) { - list($entity, $suggestion) = $declaration; - $this->_assertNotRegExp('/[^a-z\d_]' . preg_quote($entity, '/') . '[^a-z\d_]/iS', $content, - "Constant '$entity' is obsolete. $suggestion" - ); + foreach (self::$_constants as $row) { + list($constant, $class, $suggestion) = $row; + if (!$this->_isClassSkipped($content, $class)) { + $this->_assertNotRegExp('/[^a-z\d_]' . preg_quote($constant, '/') . '[^a-z\d_]/iS', $content, + sprintf("Constant '%s' is obsolete. Replacement suggestion: %s", $constant, $suggestion) + ); + } } } @@ -217,57 +347,6 @@ class Legacy_ObsoleteCodeTest extends PHPUnit_Framework_TestCase ); } - /** - * Retrieve configuration items, whose 'class_scope' match to the content, in the following format: - * array( - * array('<entity>', '<suggestion>'), - * ... - * ) - * - * @param string $fileNamePattern - * @param string $content - * @param string $file - * @return array - */ - protected function _getRelevantConfigEntities($fileNamePattern, $content, $file) - { - $result = array(); - foreach ($this->_loadConfigFiles($fileNamePattern) as $info) { - $class = $info['class_scope']; - $regexp = '/(class|extends)\s+' . preg_quote($class, '/') . '(\s|;)/S'; - /* Note: strpos is used just to prevent excessive preg_match calls */ - if ($class && (!strpos($content, $class) || !preg_match($regexp, $content))) { - continue; - } - if ($info['directory']) { - if (0 !== strpos(str_replace('\\', '/', $file), str_replace('\\', '/', $info['directory']))) { - continue; - } - } - $result[] = array($info['obsolete_entity'], $info['suggestion']); - } - return $result; - } - - /** - * Load configuration data from the files that match a glob-pattern - * - * @param string $fileNamePattern - * @return array - */ - protected function _loadConfigFiles($fileNamePattern) - { - if (isset(self::$_configFilesCache[$fileNamePattern])) { - return self::$_configFilesCache[$fileNamePattern]; - } - $config = array(); - foreach (glob(dirname(__FILE__) . '/_files/' . $fileNamePattern, GLOB_BRACE) as $configFile) { - $config = array_merge($config, include($configFile)); - } - self::$_configFilesCache[$fileNamePattern] = $config; - return $config; - } - /** * Custom replacement for assertNotRegexp() * @@ -282,36 +361,4 @@ class Legacy_ObsoleteCodeTest extends PHPUnit_Framework_TestCase { $this->assertSame(0, preg_match($regex, $content), $message); } - - /** - * Add class rule - * - * @param string $name - * @param null|string $suggestion - * @param null|string $directory - * @return array - */ - protected function _getClassRule($name, $suggestion = null, $directory = null) - { - return $this->_getRule($name, null, $suggestion, $directory); - } - - /** - * Get rule - * - * @param string $obsoleteEntity - * @param null|string $classScope - * @param null|string $suggestion - * @param null|string $directory - * @return array - */ - protected function _getRule($obsoleteEntity, $classScope = null, $suggestion = null, $directory = null) - { - return array( - 'obsolete_entity' => $obsoleteEntity, - 'class_scope' => $classScope, - 'suggestion' => $suggestion, - 'directory' => $directory - ); - } } diff --git a/dev/tests/static/testsuite/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Legacy/_files/obsolete_classes.php index b5116d51b44..b8d72cb763a 100644 --- a/dev/tests/static/testsuite/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Legacy/_files/obsolete_classes.php @@ -1,5 +1,9 @@ <?php /** + * Obsolete classes + * + * Format: array(<class_name>[, <replacement>]) + * * Magento * * NOTICE OF LICENSE @@ -18,696 +22,705 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category tests - * @package static - * @subpackage Legacy * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ return array( - $this->_getClassRule('Mage_Admin_Helper_Data', 'Mage_Backend_Helper_Data'), - $this->_getClassRule('Mage_Admin_Model_Acl', 'Magento_Acl'), - $this->_getClassRule('Mage_Admin_Model_Acl_Role'), - $this->_getClassRule('Mage_Admin_Model_Acl_Resource', 'Magento_Acl_Resource'), - $this->_getClassRule('Mage_Admin_Model_Acl_Role_Registry', 'Magento_Acl_Role_Registry'), - $this->_getClassRule('Mage_Admin_Model_Acl_Role_Generic', 'Mage_User_Model_Acl_Role_Generic'), - $this->_getClassRule('Mage_Admin_Model_Acl_Role_Group', 'Mage_User_Model_Acl_Role_Group'), - $this->_getClassRule('Mage_Admin_Model_Acl_Role_User', 'Mage_User_Model_Acl_Role_User'), - $this->_getClassRule('Mage_Admin_Model_Resource_Acl', 'Mage_User_Model_Resource_Acl'), - $this->_getClassRule('Mage_Admin_Model_Observer'), - $this->_getClassRule('Mage_Admin_Model_Session', 'Mage_Backend_Model_Auth_Session'), - $this->_getClassRule('Mage_Admin_Model_Resource_Acl_Role'), - $this->_getClassRule('Mage_Admin_Model_Resource_Acl_Role_Collection'), - $this->_getClassRule('Mage_Admin_Model_User', 'Mage_User_Model_User'), - $this->_getClassRule('Mage_Admin_Model_Config'), - $this->_getClassRule('Mage_Admin_Model_Resource_User', 'Mage_User_Model_Resource_User'), - $this->_getClassRule('Mage_Admin_Model_Resource_User_Collection', 'Mage_User_Model_Resource_User_Collection'), - $this->_getClassRule('Mage_Admin_Model_Role', 'Mage_User_Model_Role'), - $this->_getClassRule('Mage_Admin_Model_Roles', 'Mage_User_Model_Roles'), - $this->_getClassRule('Mage_Admin_Model_Rules', 'Mage_User_Model_Rules'), - $this->_getClassRule('Mage_Admin_Model_Resource_Role', 'Mage_User_Model_Resource_Role'), - $this->_getClassRule('Mage_Admin_Model_Resource_Roles', 'Mage_User_Model_Resource_Roles'), - $this->_getClassRule('Mage_Admin_Model_Resource_Rules', 'Mage_User_Model_Resource_Rules'), - $this->_getClassRule('Mage_Admin_Model_Resource_Role_Collection', 'Mage_User_Model_Resource_Role_Collection'), - $this->_getClassRule('Mage_Admin_Model_Resource_Roles_Collection', 'Mage_User_Model_Resource_Roles_Collection'), - $this->_getClassRule('Mage_Admin_Model_Resource_Roles_User_Collection', + array('Mage_Admin_Helper_Data', 'Mage_Backend_Helper_Data'), + array('Mage_Admin_Model_Acl', 'Magento_Acl'), + array('Mage_Admin_Model_Acl_Role'), + array('Mage_Admin_Model_Acl_Resource', 'Magento_Acl_Resource'), + array('Mage_Admin_Model_Acl_Role_Registry', 'Magento_Acl_Role_Registry'), + array('Mage_Admin_Model_Acl_Role_Generic', 'Mage_User_Model_Acl_Role_Generic'), + array('Mage_Admin_Model_Acl_Role_Group', 'Mage_User_Model_Acl_Role_Group'), + array('Mage_Admin_Model_Acl_Role_User', 'Mage_User_Model_Acl_Role_User'), + array('Mage_Admin_Model_Resource_Acl', 'Mage_User_Model_Resource_Acl'), + array('Mage_Admin_Model_Observer'), + array('Mage_Admin_Model_Session', 'Mage_Backend_Model_Auth_Session'), + array('Mage_Admin_Model_Resource_Acl_Role'), + array('Mage_Admin_Model_Resource_Acl_Role_Collection'), + array('Mage_Admin_Model_User', 'Mage_User_Model_User'), + array('Mage_Admin_Model_Config'), + array('Mage_Admin_Model_Resource_User', 'Mage_User_Model_Resource_User'), + array('Mage_Admin_Model_Resource_User_Collection', 'Mage_User_Model_Resource_User_Collection'), + array('Mage_Admin_Model_Role', 'Mage_User_Model_Role'), + array('Mage_Admin_Model_Roles', 'Mage_User_Model_Roles'), + array('Mage_Admin_Model_Rules', 'Mage_User_Model_Rules'), + array('Mage_Admin_Model_Resource_Role', 'Mage_User_Model_Resource_Role'), + array('Mage_Admin_Model_Resource_Roles', 'Mage_User_Model_Resource_Roles'), + array('Mage_Admin_Model_Resource_Rules', 'Mage_User_Model_Resource_Rules'), + array('Mage_Admin_Model_Resource_Role_Collection', 'Mage_User_Model_Resource_Role_Collection'), + array('Mage_Admin_Model_Resource_Roles_Collection', 'Mage_User_Model_Resource_Roles_Collection'), + array('Mage_Admin_Model_Resource_Roles_User_Collection', 'Mage_User_Model_Resource_Roles_User_Collection'), - $this->_getClassRule('Mage_Admin_Model_Resource_Rules_Collection', 'Mage_User_Model_Resource_Rules_Collection'), - $this->_getClassRule('Mage_Admin_Model_Resource_Permissions_Collection', + array('Mage_Admin_Model_Resource_Rules_Collection', 'Mage_User_Model_Resource_Rules_Collection'), + array('Mage_Admin_Model_Resource_Permissions_Collection', 'Mage_User_Model_Resource_Permissions_Collection'), - $this->_getClassRule('Mage_Adminhtml_Block_Api_Edituser'), - $this->_getClassRule('Mage_Adminhtml_Block_Api_Tab_Userroles'), - $this->_getClassRule('Mage_Adminhtml_Block_Backup_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Catalog'), - $this->_getClassRule('Mage_Adminhtml_Block_Catalog_Product_Attribute_Set_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Catalog_Search_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Newsletter_Problem_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Newsletter_Queue_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Newsletter_Queue'), - $this->_getClassRule('Mage_Adminhtml_Block_Page_Menu', 'Mage_Backend_Block_Menu'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_User'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_User_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_User_Edit'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_User_Edit_Tabs'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_User_Edit_Tab_Main'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_User_Edit_Tab_Roles'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_User_Edit_Form'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Role'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Buttons'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Role_Grid_User'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Grid_Role'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Grid_User'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Tab_Roleinfo'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Tab_Rolesedit'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Tab_Rolesusers'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Tab_Useredit'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Editroles'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Roles'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Users'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Edituser'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Tab_Userroles'), - $this->_getClassRule('Mage_Adminhtml_Block_Permissions_Usernroles'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Store_Grid'), - $this->_getClassRule('Mage_Adminhtml_Permissions_UserController'), - $this->_getClassRule('Mage_Adminhtml_Permissions_RoleController'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Grid', 'Mage_Reports_Block_Adminhtml_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Customer_Accounts', + array('Mage_Adminhtml_Block_Abstract', 'Mage_Core_Block_Template'), + array('Mage_Adminhtml_Block_Api_Edituser'), + array('Mage_Adminhtml_Block_Api_Tab_Userroles'), + array('Mage_Adminhtml_Block_Backup_Grid'), + array('Mage_Adminhtml_Block_Catalog'), + array('Mage_Adminhtml_Block_Catalog_Product_Attribute_Set_Grid'), + array('Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config_Grid'), + array('Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Group_Grid'), + array('Mage_Adminhtml_Block_Catalog_Search_Grid'), + array('Mage_Adminhtml_Block_Html_Date', 'Mage_Core_Block_Html_Date'), + array('Mage_Adminhtml_Block_Html_Select', 'Mage_Core_Block_Html_Select'), + array('Mage_Adminhtml_Block_Messages', 'Mage_Core_Block_Messages'), + array('Mage_Adminhtml_Block_Newsletter_Problem_Grid'), + array('Mage_Adminhtml_Block_Newsletter_Queue'), + array('Mage_Adminhtml_Block_Newsletter_Queue_Grid'), + array('Mage_Adminhtml_Block_Page_Menu', 'Mage_Backend_Block_Menu'), + array('Mage_Adminhtml_Block_Permissions_User'), + array('Mage_Adminhtml_Block_Permissions_User_Grid'), + array('Mage_Adminhtml_Block_Permissions_User_Edit'), + array('Mage_Adminhtml_Block_Permissions_User_Edit_Tabs'), + array('Mage_Adminhtml_Block_Permissions_User_Edit_Tab_Main'), + array('Mage_Adminhtml_Block_Permissions_User_Edit_Tab_Roles'), + array('Mage_Adminhtml_Block_Permissions_User_Edit_Form'), + array('Mage_Adminhtml_Block_Permissions_Role'), + array('Mage_Adminhtml_Block_Permissions_Buttons'), + array('Mage_Adminhtml_Block_Permissions_Role_Grid_User'), + array('Mage_Adminhtml_Block_Permissions_Grid_Role'), + array('Mage_Adminhtml_Block_Permissions_Grid_User'), + array('Mage_Adminhtml_Block_Permissions_Tab_Roleinfo'), + array('Mage_Adminhtml_Block_Permissions_Tab_Rolesedit'), + array('Mage_Adminhtml_Block_Permissions_Tab_Rolesusers'), + array('Mage_Adminhtml_Block_Permissions_Tab_Useredit'), + array('Mage_Adminhtml_Block_Permissions_Editroles'), + array('Mage_Adminhtml_Block_Permissions_Roles'), + array('Mage_Adminhtml_Block_Permissions_Users'), + array('Mage_Adminhtml_Block_Permissions_Edituser'), + array('Mage_Adminhtml_Block_Permissions_Tab_Userroles'), + array('Mage_Adminhtml_Block_Permissions_Usernroles'), + array('Mage_Adminhtml_Permissions_UserController'), + array('Mage_Adminhtml_Permissions_RoleController'), + array('Mage_Adminhtml_Block_Report_Grid', 'Mage_Reports_Block_Adminhtml_Grid'), + array('Mage_Adminhtml_Block_Report_Customer_Accounts', 'Mage_Reports_Block_Adminhtml_Customer_Accounts'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Customer_Accounts_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Customer_Totals', 'Mage_Reports_Block_Adminhtml_Customer_Totals'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Customer_Totals_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Product_Sold', 'Mage_Reports_Block_Adminhtml_Product_Sold'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Product_Sold_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Review_Customer_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Review_Product_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Refresh_Statistics', - 'Mage_Reports_Block_Adminhtml_Refresh_Statistics'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Refresh_Statistics_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Customer_Orders', 'Mage_Reports_Block_Adminhtml_Customer_Orders'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Customer_Orders_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Product_Ordered'), - $this->_getClassRule('Mage_Adminhtml_Block_Report_Product_Ordered_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Sales'), - $this->_getClassRule('Mage_Adminhtml_Block_Sales_Order_Create_Search_Grid_Renderer_Giftmessage'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Edit', 'Mage_Backend_Block_System_Config_Edit'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form', 'Mage_Backend_Block_System_Config_Form'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Tabs', 'Mage_Backend_Block_System_Config_Tabs'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_System_Storage_Media_Synchronize', - 'Mage_Backend_Block_System_Config_System_Storage_Media_Synchronize'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Fieldset_Modules_DisableOutput', - 'Mage_Backend_Block_System_Config_Form_Fieldset_Modules_DisableOutput'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Regexceptions', - 'Mage_Backend_Block_System_Config_Form_Field_Regexceptions'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Notification', + array('Mage_Adminhtml_Block_Report_Customer_Accounts_Grid'), + array('Mage_Adminhtml_Block_Report_Customer_Totals', 'Mage_Reports_Block_Adminhtml_Customer_Totals'), + array('Mage_Adminhtml_Block_Report_Customer_Totals_Grid'), + array('Mage_Adminhtml_Block_Report_Product_Sold', 'Mage_Reports_Block_Adminhtml_Product_Sold'), + array('Mage_Adminhtml_Block_Report_Product_Sold_Grid'), + array('Mage_Adminhtml_Block_Report_Customer_Orders', 'Mage_Reports_Block_Adminhtml_Customer_Orders'), + array('Mage_Adminhtml_Block_Report_Customer_Orders_Grid'), + array('Mage_Adminhtml_Block_Report_Product_Ordered'), + array('Mage_Adminhtml_Block_Report_Product_Ordered_Grid'), + array('Mage_Adminhtml_Block_Report_Review_Product_Grid'), + array('Mage_Adminhtml_Block_Report_Refresh_Statistics', 'Mage_Reports_Block_Adminhtml_Refresh_Statistics'), + array('Mage_Adminhtml_Block_Report_Refresh_Statistics_Grid'), + array('Mage_Adminhtml_Block_Sales'), + array('Mage_Adminhtml_Block_Sales_Order_Create_Search_Grid_Renderer_Giftmessage'), + array('Mage_Adminhtml_Block_Sitemap_Grid'), + array('Mage_Adminhtml_Block_System_Config_Edit', 'Mage_Backend_Block_System_Config_Edit'), + array('Mage_Adminhtml_Block_System_Config_Form', 'Mage_Backend_Block_System_Config_Form'), + array('Mage_Adminhtml_Block_System_Config_Tabs', 'Mage_Backend_Block_System_Config_Tabs'), + array('Mage_Adminhtml_Block_System_Config_System_Storage_Media_Synchronize', + 'Mage_Backend_Block_System_Config_System_Storage_Media_Synchronize' + ), + array('Mage_Adminhtml_Block_System_Config_Form_Fieldset_Modules_DisableOutput', + 'Mage_Backend_Block_System_Config_Form_Fieldset_Modules_DisableOutput' + ), + array('Mage_Adminhtml_Block_System_Config_Form_Field_Regexceptions', + 'Mage_Backend_Block_System_Config_Form_Field_Regexceptions' + ), + array('Mage_Adminhtml_Block_System_Config_Form_Field_Notification', 'Mage_Backend_Block_System_Config_Form_Field_Notification' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Heading', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Heading', 'Mage_Backend_Block_System_Config_Form_Field_Heading' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Datetime', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Datetime', 'Mage_Backend_Block_System_Config_Form_Field_Datetime' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract', 'Mage_Backend_Block_System_Config_Form_Field_Array_Abstract' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Fieldset', + array('Mage_Adminhtml_Block_System_Config_Form_Fieldset', 'Mage_Backend_Block_System_Config_Form_Fieldset' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field', + array('Mage_Adminhtml_Block_System_Config_Form_Field', 'Mage_Backend_Block_System_Config_Form_Field' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Import', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Import', 'Mage_Backend_Block_System_Config_Form_Field_Import' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Image', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Image', 'Mage_Backend_Block_System_Config_Form_Field_Image' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Export', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Export', 'Mage_Backend_Block_System_Config_Form_Field_Export' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Select_Allowspecific', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Select_Allowspecific', 'Mage_Backend_Block_System_Config_Form_Field_Select_Allowspecific' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_File', + array('Mage_Adminhtml_Block_System_Config_Form_Field_File', 'Mage_Backend_Block_System_Config_Form_Field_File' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Select_Flatproduct', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Select_Flatproduct', 'Mage_Catalog_Block_Adminhtml_System_Config_Form_Field_Select_Flatproduct' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Field_Select_Flatcatalog', + array('Mage_Adminhtml_Block_System_Config_Form_Field_Select_Flatcatalog', 'Mage_Catalog_Block_Adminhtml_System_Config_Form_Field_Select_Flatcatalog' ), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Form_Fieldset_Order_Statuses', + array('Mage_Adminhtml_Block_System_Config_Form_Fieldset_Order_Statuses', 'Mage_Sales_Block_Adminhtml_System_Config_Form_Fieldset_Order_Statuses' - ), $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Dwstree', 'Mage_Backend_Block_System_Config_Dwstree'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Config_Switcher', 'Mage_Backend_Block_System_Config_Switcher'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Design_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Email_Template_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Store_Switcher', 'Mage_Backend_Block_Store_Switcher'), - $this->_getClassRule('Mage_Adminhtml_Block_Store_Switcher_Form_Renderer_Fieldset', + ), + array('Mage_Adminhtml_Block_System_Config_Dwstree', 'Mage_Backend_Block_System_Config_Dwstree'), + array('Mage_Adminhtml_Block_System_Config_Switcher', 'Mage_Backend_Block_System_Config_Switcher'), + array('Mage_Adminhtml_Block_System_Design_Grid'), + array('Mage_Adminhtml_Block_System_Email_Template_Grid'), + array('Mage_Adminhtml_Block_System_Variable_Grid'), + array('Mage_Adminhtml_Block_Store_Switcher', 'Mage_Backend_Block_Store_Switcher'), + array('Mage_Adminhtml_Block_Store_Switcher_Form_Renderer_Fieldset', 'Mage_Backend_Block_Store_Switcher_Form_Renderer_Fieldset' ), - $this->_getClassRule('Mage_Adminhtml_Block_Store_Switcher_Form_Renderer_Fieldset_Element', + array('Mage_Adminhtml_Block_Store_Switcher_Form_Renderer_Fieldset_Element', 'Mage_Backend_Block_Store_Switcher_Form_Renderer_Fieldset_Element' ), - $this->_getClassRule('Mage_Adminhtml_Block_Sitemap_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Tag_Tag_Edit'), - $this->_getClassRule('Mage_Adminhtml_Block_Tag_Tag_Edit_Form'), - $this->_getClassRule('Mage_Adminhtml_Block_Tax_Rate_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_Tree'), - $this->_getClassRule('Mage_Adminhtml_Block_Urlrewrite_Grid'), - $this->_getClassRule('Mage_Adminhtml_Block_System_Variable_Grid'), - $this->_getClassRule('Mage_Adminhtml_Helper_Rss'), - $this->_getClassRule('Mage_Adminhtml_Model_Config', 'Mage_Backend_Model_Config_Structure'), - $this->_getClassRule('Mage_Adminhtml_Model_Config_Data', 'Mage_Backend_Model_Config'), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Shipping_Allowedmethods'), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Password_Link_Expirationperiod', + array('Mage_Adminhtml_Block_Tag_Tag_Edit'), + array('Mage_Adminhtml_Block_Tag_Tag_Edit_Form'), + array('Mage_Adminhtml_Block_Tax_Rate_Grid'), + array('Mage_Adminhtml_Block_Tree'), + array('Mage_Adminhtml_Block_Urlrewrite_Grid'), + array('Mage_Adminhtml_Helper_Rss'), + array('Mage_Adminhtml_Model_Config', 'Mage_Backend_Model_Config_Structure'), + array('Mage_Adminhtml_Model_Config_Data', 'Mage_Backend_Model_Config'), + array('Mage_Adminhtml_Model_Extension'), + array('Mage_Adminhtml_Model_System_Config_Source_Shipping_Allowedmethods'), + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Password_Link_Expirationperiod', 'Mage_Backend_Model_Config_Backend_Admin_Password_Link_Expirationperiod' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Custom', + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Custom', 'Mage_Backend_Model_Config_Backend_Admin_Custom' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Custompath', + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Custompath', 'Mage_Backend_Model_Config_Backend_Admin_Custompath' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Observer', + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Observer', 'Mage_Backend_Model_Config_Backend_Admin_Observer' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Robots', + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Robots', 'Mage_Backend_Model_Config_Backend_Admin_Robots' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Usecustom', + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Usecustom', 'Mage_Backend_Model_Config_Backend_Admin_Usecustom' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Usecustompath', + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Usecustompath', 'Mage_Backend_Model_Config_Backend_Admin_Usecustompath' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Admin_Usesecretkey', + array('Mage_Adminhtml_Model_System_Config_Backend_Admin_Usesecretkey', 'Mage_Backend_Model_Config_Backend_Admin_Usesecretkey' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Catalog_Inventory_Managestock', + array('Mage_Adminhtml_Model_System_Config_Backend_Catalog_Inventory_Managestock', 'Mage_CatalogInventory_Model_Config_Backend_Managestock' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Catalog_Search_Type', + array('Mage_Adminhtml_Model_System_Config_Backend_Catalog_Search_Type', 'Mage_CatalogSearch_Model_Config_Backend_Search_Type' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Currency_Abstract', + array('Mage_Adminhtml_Model_System_Config_Backend_Currency_Abstract', 'Mage_Backend_Model_Config_Backend_Currency_Abstract' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Currency_Allow', + array('Mage_Adminhtml_Model_System_Config_Backend_Currency_Allow', 'Mage_Backend_Model_Config_Backend_Currency_Allow' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Currency_Base', + array('Mage_Adminhtml_Model_System_Config_Backend_Currency_Base', 'Mage_Backend_Model_Config_Backend_Currency_Base' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Currency_Cron', + array('Mage_Adminhtml_Model_System_Config_Backend_Currency_Cron', 'Mage_Backend_Model_Config_Backend_Currency_Cron' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Currency_Default', + array('Mage_Adminhtml_Model_System_Config_Backend_Currency_Default', 'Mage_Backend_Model_Config_Backend_Currency_Default' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Customer_Address_Street', + array('Mage_Adminhtml_Model_System_Config_Backend_Customer_Address_Street', 'Mage_Customer_Model_Config_Backend_Address_Street' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Customer_Password_Link_Expirationperiod', + array('Mage_Adminhtml_Model_System_Config_Backend_Customer_Password_Link_Expirationperiod', 'Mage_Customer_Model_Config_Backend_Password_Link_Expirationperiod' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Address', + array('Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Address', 'Mage_Customer_Model_Config_Backend_Show_Address' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Customer', + array('Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Customer', 'Mage_Customer_Model_Config_Backend_Show_Customer' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Design_Exception', + array('Mage_Adminhtml_Model_System_Config_Backend_Design_Exception', 'Mage_Backend_Model_Config_Backend_Design_Exception' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Email_Address', + array('Mage_Adminhtml_Model_System_Config_Backend_Email_Address', 'Mage_Backend_Model_Config_Backend_Email_Address' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Email_Logo', + array('Mage_Adminhtml_Model_System_Config_Backend_Email_Logo', 'Mage_Backend_Model_Config_Backend_Email_Logo' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Email_Sender', + array('Mage_Adminhtml_Model_System_Config_Backend_Email_Sender', 'Mage_Backend_Model_Config_Backend_Email_Sender' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Image_Adapter', + array('Mage_Adminhtml_Model_System_Config_Backend_Image_Adapter', 'Mage_Backend_Model_Config_Backend_Image_Adapter' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Image_Favicon', + array('Mage_Adminhtml_Model_System_Config_Backend_Image_Favicon', 'Mage_Backend_Model_Config_Backend_Image_Favicon' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Image_Pdf', + array('Mage_Adminhtml_Model_System_Config_Backend_Image_Pdf', 'Mage_Backend_Model_Config_Backend_Image_Pdf' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Locale_Timezone', + array('Mage_Adminhtml_Model_System_Config_Backend_Locale_Timezone', 'Mage_Backend_Model_Config_Backend_Locale_Timezone' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Log_Cron', + array('Mage_Adminhtml_Model_System_Config_Backend_Log_Cron', 'Mage_Backend_Model_Config_Backend_Log_Cron' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Price_Scope'), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Product_Alert_Cron', + array('Mage_Adminhtml_Model_System_Config_Backend_Price_Scope'), + array('Mage_Adminhtml_Model_System_Config_Backend_Product_Alert_Cron', 'Mage_Cron_Model_Config_Backend_Product_Alert' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Seo_Product', + array('Mage_Adminhtml_Model_System_Config_Backend_Seo_Product', 'Mage_Catalog_Model_Config_Backend_Seo_Product' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Serialized_Array', + array('Mage_Adminhtml_Model_System_Config_Backend_Serialized_Array', 'Mage_Backend_Model_Config_Backend_Serialized_Array' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Shipping_Tablerate', + array('Mage_Adminhtml_Model_System_Config_Backend_Shipping_Tablerate', 'Mage_Shipping_Model_Config_Backend_Tablerate' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Sitemap_Cron', + array('Mage_Adminhtml_Model_System_Config_Backend_Sitemap_Cron', 'Mage_Cron_Model_Config_Backend_Sitemap' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Storage_Media_Database', + array('Mage_Adminhtml_Model_System_Config_Backend_Storage_Media_Database', 'Mage_Backend_Model_Config_Backend_Storage_Media_Database' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Baseurl', + array('Mage_Adminhtml_Model_System_Config_Backend_Baseurl', 'Mage_Backend_Model_Config_Backend_Baseurl' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Cache', + array('Mage_Adminhtml_Model_System_Config_Backend_Cache', 'Mage_Backend_Model_Config_Backend_Cache' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Category', + array('Mage_Adminhtml_Model_System_Config_Backend_Category', 'Mage_Catalog_Model_Config_Backend_Category' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Cookie', + array('Mage_Adminhtml_Model_System_Config_Backend_Cookie', 'Mage_Backend_Model_Config_Backend_Cookie' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Datashare', + array('Mage_Adminhtml_Model_System_Config_Backend_Datashare', 'Mage_Backend_Model_Config_Backend_Datashare' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Encrypted', + array('Mage_Adminhtml_Model_System_Config_Backend_Encrypted', 'Mage_Backend_Model_Config_Backend_Encrypted' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_File', + array('Mage_Adminhtml_Model_System_Config_Backend_File', 'Mage_Backend_Model_Config_Backend_File' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Filename', + array('Mage_Adminhtml_Model_System_Config_Backend_Filename', 'Mage_Backend_Model_Config_Backend_Filename' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Image', + array('Mage_Adminhtml_Model_System_Config_Backend_Image', 'Mage_Backend_Model_Config_Backend_Image' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Locale', + array('Mage_Adminhtml_Model_System_Config_Backend_Locale', 'Mage_Backend_Model_Config_Backend_Locale' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Secure', + array('Mage_Adminhtml_Model_System_Config_Backend_Secure', 'Mage_Backend_Model_Config_Backend_Secure' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Serialized', + array('Mage_Adminhtml_Model_System_Config_Backend_Serialized', 'Mage_Backend_Model_Config_Backend_Serialized' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Sitemap', + array('Mage_Adminhtml_Model_System_Config_Backend_Sitemap', 'Mage_Sitemap_Model_Config_Backend_Priority' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Store', + array('Mage_Adminhtml_Model_System_Config_Backend_Store', 'Mage_Backend_Model_Config_Backend_Store' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Backend_Translate', + array('Mage_Adminhtml_Model_System_Config_Backend_Translate', 'Mage_Backend_Model_Config_Backend_Translate' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Clone_Media_Image', + array('Mage_Adminhtml_Model_System_Config_Clone_Media_Image', 'Mage_Catalog_Model_Config_Clone_Media_Image' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Admin_Page', + array('Mage_Adminhtml_Model_System_Config_Source_Admin_Page', 'Mage_Backend_Model_Config_Source_Admin_Page' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Catalog_Search_Type', + array('Mage_Adminhtml_Model_System_Config_Source_Catalog_Search_Type', 'Mage_CatalogSearch_Model_Config_Source_Search_Type' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Catalog_GridPerPage', + array('Mage_Adminhtml_Model_System_Config_Source_Catalog_GridPerPage', 'Mage_Catalog_Model_Config_Source_GridPerPage' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Catalog_ListMode', + array('Mage_Adminhtml_Model_System_Config_Source_Catalog_ListMode', 'Mage_Catalog_Model_Config_Source_ListMode' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Catalog_ListPerPage', + array('Mage_Adminhtml_Model_System_Config_Source_Catalog_ListPerPage', 'Mage_Catalog_Model_Config_Source_ListPerPage' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Catalog_ListSort', + array('Mage_Adminhtml_Model_System_Config_Source_Catalog_ListSort', 'Mage_Catalog_Model_Config_Source_ListSort' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Catalog_TimeFormat', + array('Mage_Adminhtml_Model_System_Config_Source_Catalog_TimeFormat', 'Mage_Catalog_Model_Config_Source_TimeFormat' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Cms_Wysiwyg_Enabled', + array('Mage_Adminhtml_Model_System_Config_Source_Cms_Wysiwyg_Enabled', 'Mage_Cms_Model_Config_Source_Wysiwyg_Enabled' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Cms_Page', + array('Mage_Adminhtml_Model_System_Config_Source_Cms_Page', 'Mage_Cms_Model_Config_Source_Page' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Country_Full', + array('Mage_Adminhtml_Model_System_Config_Source_Country_Full', 'Mage_Directory_Model_Config_Source_Country_Full' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency', + array('Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency', 'Mage_Cron_Model_Config_Source_Frequency' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Currency_Service', + array('Mage_Adminhtml_Model_System_Config_Source_Currency_Service', 'Mage_Backend_Model_Config_Source_Currency' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Customer_Address_Type', + array('Mage_Adminhtml_Model_System_Config_Source_Customer_Address_Type', 'Mage_Customer_Model_Config_Source_Address_Type' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Customer_Group_Multiselect', + array('Mage_Adminhtml_Model_System_Config_Source_Customer_Group_Multiselect', 'Mage_Customer_Model_Config_Source_Group_Multiselect' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Customer_Group', + array('Mage_Adminhtml_Model_System_Config_Source_Customer_Group', 'Mage_Customer_Model_Config_Source_Group' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Date_Short', + array('Mage_Adminhtml_Model_System_Config_Source_Date_Short', 'Mage_Backend_Model_Config_Source_Date_Short' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Design_Package'), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Design_Robots', + array('Mage_Adminhtml_Model_System_Config_Source_Design_Package'), + array('Mage_Adminhtml_Model_System_Config_Source_Design_Robots', 'Mage_Backend_Model_Config_Source_Design_Robots' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Dev_Dbautoup', + array('Mage_Adminhtml_Model_System_Config_Source_Dev_Dbautoup', 'Mage_Backend_Model_Config_Source_Dev_Dbautoup' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Email_Identity', + array('Mage_Adminhtml_Model_System_Config_Source_Email_Identity', 'Mage_Backend_Model_Config_Source_Email_Identity' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Email_Method', + array('Mage_Adminhtml_Model_System_Config_Source_Email_Method', 'Mage_Backend_Model_Config_Source_Email_Method' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Email_Smtpauth', + array('Mage_Adminhtml_Model_System_Config_Source_Email_Smtpauth', 'Mage_Backend_Model_Config_Source_Email_Smtpauth' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Email_Template', + array('Mage_Adminhtml_Model_System_Config_Source_Email_Template', 'Mage_Backend_Model_Config_Source_Email_Template' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Image_Adapter', + array('Mage_Adminhtml_Model_System_Config_Source_Image_Adapter', 'Mage_Backend_Model_Config_Source_Image_Adapter' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Locale_Country', + array('Mage_Adminhtml_Model_System_Config_Source_Locale_Country', 'Mage_Backend_Model_Config_Source_Locale_Country' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Locale_Currency_All', + array('Mage_Adminhtml_Model_System_Config_Source_Locale_Currency_All', 'Mage_Backend_Model_Config_Source_Locale_Currency_All' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Locale_Currency', + array('Mage_Adminhtml_Model_System_Config_Source_Locale_Currency', 'Mage_Backend_Model_Config_Source_Locale_Currency' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Locale_Timezone', + array('Mage_Adminhtml_Model_System_Config_Source_Locale_Timezone', 'Mage_Backend_Model_Config_Source_Locale_Timezone' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Locale_Weekdays', + array('Mage_Adminhtml_Model_System_Config_Source_Locale_Weekdays', 'Mage_Backend_Model_Config_Source_Locale_Weekdays' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Notification_Frequency', + array('Mage_Adminhtml_Model_System_Config_Source_Notification_Frequency', 'Mage_AdminNotification_Model_Config_Source_Frequency' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Order_Status_New', + array('Mage_Adminhtml_Model_System_Config_Source_Order_Status_New', 'Mage_Sales_Model_Config_Source_Order_Status_New' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Order_Status_Newprocessing', + array('Mage_Adminhtml_Model_System_Config_Source_Order_Status_Newprocessing', 'Mage_Sales_Model_Config_Source_Order_Status_Newprocessing' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Order_Status_Processing', + array('Mage_Adminhtml_Model_System_Config_Source_Order_Status_Processing', 'Mage_Sales_Model_Config_Source_Order_Status_Processing' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Order_Status', + array('Mage_Adminhtml_Model_System_Config_Source_Order_Status', 'Mage_Sales_Model_Config_Source_Order_Status' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Payment_Allmethods', + array('Mage_Adminhtml_Model_System_Config_Source_Payment_Allmethods', 'Mage_Payment_Model_Config_Source_Allmethods' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Payment_Allowedmethods', + array('Mage_Adminhtml_Model_System_Config_Source_Payment_Allowedmethods', 'Mage_Payment_Model_Config_Source_Allowedmethods' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Payment_Allspecificcountries', + array('Mage_Adminhtml_Model_System_Config_Source_Payment_Allspecificcountries', 'Mage_Payment_Model_Config_Source_Allspecificcountries' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Payment_Cctype', + array('Mage_Adminhtml_Model_System_Config_Source_Payment_Cctype', 'Mage_Payment_Model_Config_Source_Cctype' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Price_Scope', + array('Mage_Adminhtml_Model_System_Config_Source_Price_Scope', 'Mage_Catalog_Model_Config_Source_Price_Scope' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Price_Step', + array('Mage_Adminhtml_Model_System_Config_Source_Price_Step', 'Mage_Catalog_Model_Config_Source_Price_Step' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Product_Options_Price', + array('Mage_Adminhtml_Model_System_Config_Source_Product_Options_Price', 'Mage_Catalog_Model_Config_Source_Product_Options_Price' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Product_Options_Type', + array('Mage_Adminhtml_Model_System_Config_Source_Product_Options_Type', 'Mage_Catalog_Model_Config_Source_Product_Options_Type' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Product_Thumbnail', + array('Mage_Adminhtml_Model_System_Config_Source_Product_Thumbnail', 'Mage_Catalog_Model_Config_Source_Product_Thumbnail' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Reports_Scope', + array('Mage_Adminhtml_Model_System_Config_Source_Reports_Scope', 'Mage_Backend_Model_Config_Source_Reports_Scope' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Shipping_Allmethods', + array('Mage_Adminhtml_Model_System_Config_Source_Shipping_Allmethods', 'Mage_Shipping_Model_Config_Source_Allmethods' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Shipping_Allspecificcountries', + array('Mage_Adminhtml_Model_System_Config_Source_Shipping_Allspecificcountries', 'Mage_Shipping_Model_Config_Source_Allspecificcountries' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Shipping_Flatrate', + array('Mage_Adminhtml_Model_System_Config_Source_Shipping_Flatrate', 'Mage_Shipping_Model_Config_Source_Flatrate' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Shipping_Tablerate', + array('Mage_Adminhtml_Model_System_Config_Source_Shipping_Tablerate', 'Mage_Shipping_Model_Config_Source_Tablerate' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Shipping_Taxclass', + array('Mage_Adminhtml_Model_System_Config_Source_Shipping_Taxclass', 'Mage_Tax_Model_Config_Source_Class_Product' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Storage_Media_Database', + array('Mage_Adminhtml_Model_System_Config_Source_Storage_Media_Database', 'Mage_Backend_Model_Config_Source_Storage_Media_Database' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Storage_Media_Storage', + array('Mage_Adminhtml_Model_System_Config_Source_Storage_Media_Storage', 'Mage_Backend_Model_Config_Source_Storage_Media_Storage' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Tax_Apply_On', + array('Mage_Adminhtml_Model_System_Config_Source_Tax_Apply_On', 'Mage_Tax_Model_Config_Source_Apply_On' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Tax_Basedon', + array('Mage_Adminhtml_Model_System_Config_Source_Tax_Basedon', 'Mage_Tax_Model_Config_Source_Basedon' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Tax_Catalog', + array('Mage_Adminhtml_Model_System_Config_Source_Tax_Catalog', 'Mage_Tax_Model_Config_Source_Catalog' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Watermark_Position', + array('Mage_Adminhtml_Model_System_Config_Source_Watermark_Position', 'Mage_Catalog_Model_Config_Source_Watermark_Position' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Web_Protocol', + array('Mage_Adminhtml_Model_System_Config_Source_Web_Protocol', 'Mage_Backend_Model_Config_Source_Web_Protocol' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Web_Redirect', + array('Mage_Adminhtml_Model_System_Config_Source_Web_Redirect', 'Mage_Backend_Model_Config_Source_Web_Redirect' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Allregion', + array('Mage_Adminhtml_Model_System_Config_Source_Allregion', 'Mage_Directory_Model_Config_Source_Allregion' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Category', + array('Mage_Adminhtml_Model_System_Config_Source_Category', 'Mage_Catalog_Model_Config_Source_Category' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Checktype', + array('Mage_Adminhtml_Model_System_Config_Source_Checktype', 'Mage_Backend_Model_Config_Source_Checktype' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Country', + array('Mage_Adminhtml_Model_System_Config_Source_Country', 'Mage_Directory_Model_Config_Source_Country' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Currency', + array('Mage_Adminhtml_Model_System_Config_Source_Currency', 'Mage_Backend_Model_Config_Source_Currency' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Enabledisable', + array('Mage_Adminhtml_Model_System_Config_Source_Enabledisable', 'Mage_Backend_Model_Config_Source_Enabledisable' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Frequency', + array('Mage_Adminhtml_Model_System_Config_Source_Frequency', 'Mage_Sitemap_Model_Config_Source_Frequency' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Locale', + array('Mage_Adminhtml_Model_System_Config_Source_Locale', 'Mage_Backend_Model_Config_Source_Locale' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Nooptreq', + array('Mage_Adminhtml_Model_System_Config_Source_Nooptreq', 'Mage_Backend_Model_Config_Source_Nooptreq' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Store', + array('Mage_Adminhtml_Model_System_Config_Source_Store', 'Mage_Backend_Model_Config_Source_Store' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Website', + array('Mage_Adminhtml_Model_System_Config_Source_Website', 'Mage_Backend_Model_Config_Source_Website' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Yesno', 'Mage_Backend_Model_Config_Source_Yesno'), - $this->_getClassRule('Mage_Adminhtml_Model_System_Config_Source_Yesnocustom', + array('Mage_Adminhtml_Model_System_Config_Source_Yesno', 'Mage_Backend_Model_Config_Source_Yesno'), + array('Mage_Adminhtml_Model_System_Config_Source_Yesnocustom', 'Mage_Backend_Model_Config_Source_Yesnocustom' ), - $this->_getClassRule('Mage_Adminhtml_Model_System_Store', 'Mage_Core_Model_System_Store'), - $this->_getClassRule('Mage_Adminhtml_Model_Url', 'Mage_Backend_Model_Url'), - $this->_getClassRule('Mage_Adminhtml_Rss_CatalogController'), - $this->_getClassRule('Mage_Adminhtml_Rss_OrderController'), - $this->_getClassRule('Mage_Adminhtml_SystemController', 'Mage_Backend_Adminhtml_SystemController'), - $this->_getClassRule('Mage_Adminhtml_System_ConfigController', 'Mage_Backend_Adminhtml_System_ConfigController'), - $this->_getClassRule('Mage_Bundle_Product_EditController', 'Mage_Bundle_Adminhtml_Bundle_SelectionController'), - $this->_getClassRule('Mage_Bundle_SelectionController', 'Mage_Bundle_Adminhtml_Bundle_SelectionController'), - $this->_getClassRule('Mage_Catalog_Model_Convert'), - $this->_getClassRule('Mage_Catalog_Model_Convert_Adapter_Catalog'), - $this->_getClassRule('Mage_Catalog_Model_Convert_Adapter_Product'), - $this->_getClassRule('Mage_Catalog_Model_Convert_Parser_Product'), - $this->_getClassRule('Mage_Catalog_Model_Entity_Product_Attribute_Frontend_Image'), - $this->_getClassRule('Mage_Catalog_Model_Resource_Product_Attribute_Frontend_Image'), - $this->_getClassRule('Mage_Catalog_Model_Resource_Product_Attribute_Frontend_Tierprice'), - $this->_getClassRule('Mage_Core_Block_Flush'), - $this->_getClassRule('Mage_Core_Block_Template_Facade'), - $this->_getClassRule('Mage_Core_Controller_Varien_Router_Admin', 'Mage_Backend_Controller_Router_Default'), - $this->_getClassRule('Mage_Core_Model_Convert'), - $this->_getClassRule('Mage_Core_Model_Config_System'), - $this->_getClassRule('Mage_Core_Model_Design_Source_Apply'), - $this->_getClassRule('Mage_Core_Model_Language'), - $this->_getClassRule('Mage_Core_Model_Resource_Language'), - $this->_getClassRule('Mage_Core_Model_Resource_Language_Collection'), - $this->_getClassRule('Mage_Core_Model_Session_Abstract_Varien'), - $this->_getClassRule('Mage_Core_Model_Session_Abstract_Zend'), - $this->_getClassRule('Mage_Core_Model_Layout_Data', 'Mage_Core_Model_Layout_Update'), - $this->_getClassRule('Mage_Customer_Block_Account'), - $this->_getClassRule('Mage_Customer_Model_Convert_Adapter_Customer'), - $this->_getClassRule('Mage_Customer_Model_Convert_Parser_Customer'), - $this->_getClassRule('Mage_Directory_Model_Resource_Currency_Collection'), - $this->_getClassRule('Mage_Downloadable_FileController', 'Mage_Downloadable_Adminhtml_Downloadable_FileController'), - $this->_getClassRule('Mage_Downloadable_Product_EditController', 'Mage_Adminhtml_Catalog_ProductController'), - $this->_getClassRule('Mage_Eav_Model_Convert_Adapter_Entity'), - $this->_getClassRule('Mage_Eav_Model_Convert_Adapter_Grid'), - $this->_getClassRule('Mage_Eav_Model_Convert_Parser_Abstract'), - $this->_getClassRule('Mage_GiftMessage_Block_Message_Form'), - $this->_getClassRule('Mage_GiftMessage_Block_Message_Helper'), - $this->_getClassRule('Mage_GiftMessage_IndexController'), - $this->_getClassRule('Mage_GiftMessage_Model_Entity_Attribute_Backend_Boolean_Config'), - $this->_getClassRule('Mage_GiftMessage_Model_Entity_Attribute_Source_Boolean_Config'), - $this->_getClassRule('Mage_GoogleOptimizer_IndexController', + array('Mage_Adminhtml_Model_System_Store', 'Mage_Core_Model_System_Store'), + array('Mage_Adminhtml_Block_System_Store_Grid'), + array('Mage_Adminhtml_Model_Url', 'Mage_Backend_Model_Url'), + array('Mage_Adminhtml_Rss_CatalogController'), + array('Mage_Adminhtml_Rss_OrderController'), + array('Mage_Adminhtml_SystemController', 'Mage_Backend_Adminhtml_SystemController'), + array('Mage_Adminhtml_System_ConfigController', 'Mage_Backend_Adminhtml_System_ConfigController'), + array('Mage_Bundle_Product_EditController', 'Mage_Bundle_Adminhtml_Bundle_SelectionController'), + array('Mage_Bundle_SelectionController', 'Mage_Bundle_Adminhtml_Bundle_SelectionController'), + array('Mage_Catalog_Model_Convert'), + array('Mage_Catalog_Model_Convert_Adapter_Catalog'), + array('Mage_Catalog_Model_Convert_Adapter_Product'), + array('Mage_Catalog_Model_Convert_Parser_Product'), + array('Mage_Catalog_Model_Entity_Product_Attribute_Frontend_Image'), + array('Mage_Catalog_Model_Resource_Product_Attribute_Frontend_Image'), + array('Mage_Catalog_Model_Resource_Product_Attribute_Frontend_Tierprice'), + array('Mage_Core_Block_Flush'), + array('Mage_Core_Block_Template_Facade'), + array('Mage_Core_Block_Template_Smarty'), + array('Mage_Core_Block_Template_Zend'), + array('Mage_Core_Controller_Varien_Router_Admin', 'Mage_Backend_Controller_Router_Default'), + array('Mage_Core_Model_Convert'), + array('Mage_Core_Model_Config_Options', 'Mage_Core_Model_Dir'), + array('Mage_Core_Model_Config_System'), + array('Mage_Core_Model_Design_Source_Apply'), + array('Mage_Core_Model_Language'), + array('Mage_Core_Model_Resource_Language'), + array('Mage_Core_Model_Resource_Language_Collection'), + array('Mage_Core_Model_Session_Abstract_Varien'), + array('Mage_Core_Model_Session_Abstract_Zend'), + array('Mage_Core_Model_Layout_Data', 'Mage_Core_Model_Layout_Update'), + array('Mage_Customer_Block_Account'), + array('Mage_Customer_Model_Convert_Adapter_Customer'), + array('Mage_Customer_Model_Convert_Parser_Customer'), + array('Mage_Directory_Model_Resource_Currency_Collection'), + array('Mage_Downloadable_FileController', 'Mage_Downloadable_Adminhtml_Downloadable_FileController'), + array('Mage_Downloadable_Product_EditController', 'Mage_Adminhtml_Catalog_ProductController'), + array('Mage_Eav_Model_Convert_Adapter_Entity'), + array('Mage_Eav_Model_Convert_Adapter_Grid'), + array('Mage_Eav_Model_Convert_Parser_Abstract'), + array('Mage_GiftMessage_Block_Message_Form'), + array('Mage_GiftMessage_Block_Message_Helper'), + array('Mage_GiftMessage_IndexController'), + array('Mage_GiftMessage_Model_Entity_Attribute_Backend_Boolean_Config'), + array('Mage_GiftMessage_Model_Entity_Attribute_Source_Boolean_Config'), + array('Mage_GoogleOptimizer_IndexController', 'Mage_GoogleOptimizer_Adminhtml_Googleoptimizer_IndexController'), - $this->_getClassRule('Mage_ImportExport_Model_Import_Adapter_Abstract', + array('Mage_ImportExport_Model_Import_Adapter_Abstract', 'Mage_ImportExport_Model_Import_SourceAbstract'), - $this->_getClassRule('Mage_ImportExport_Model_Import_Adapter_Csv', 'Mage_ImportExport_Model_Import_Source_Csv'), - $this->_getClassRule('Mage_Ogone_Model_Api_Debug'), - $this->_getClassRule('Mage_Ogone_Model_Resource_Api_Debug'), - $this->_getClassRule('Mage_Page_Block_Html_Toplinks'), - $this->_getClassRule('Mage_Page_Block_Html_Wrapper'), - $this->_getClassRule('Mage_Poll_Block_Poll'), - $this->_getClassRule('Mage_ProductAlert_Block_Price'), - $this->_getClassRule('Mage_ProductAlert_Block_Stock'), - $this->_getClassRule('Mage_Reports_Model_Resource_Coupons_Collection'), - $this->_getClassRule('Mage_Reports_Model_Resource_Invoiced_Collection'), - $this->_getClassRule('Mage_Reports_Model_Resource_Product_Ordered_Collection'), - $this->_getClassRule('Mage_Reports_Model_Resource_Product_Viewed_Collection', + array('Mage_ImportExport_Model_Import_Adapter_Csv', + 'Mage_ImportExport_Model_Import_Source_Csv'), + array('Mage_Ogone_Model_Api_Debug'), + array('Mage_Ogone_Model_Resource_Api_Debug'), + array('Mage_Page_Block_Html_Toplinks'), + array('Mage_Page_Block_Html_Wrapper'), + array('Mage_Poll_Block_Poll'), + array('Mage_ProductAlert_Block_Price'), + array('Mage_ProductAlert_Block_Stock'), + array('Mage_Reports_Model_Resource_Coupons_Collection'), + array('Mage_Reports_Model_Resource_Invoiced_Collection'), + array('Mage_Reports_Model_Resource_Product_Ordered_Collection'), + array('Mage_Reports_Model_Resource_Product_Viewed_Collection', 'Mage_Reports_Model_Resource_Report_Product_Viewed_Collection'), - $this->_getClassRule('Mage_Reports_Model_Resource_Refunded_Collection'), - $this->_getClassRule('Mage_Reports_Model_Resource_Shipping_Collection'), - $this->_getClassRule('Mage_Rss_Model_Observer'), - $this->_getClassRule('Mage_Rss_Model_Session', 'Mage_Backend_Model_Auth and Mage_Backend_Model_Auth_Session'), - $this->_getClassRule('Mage_Sales_Block_Order_Details'), - $this->_getClassRule('Mage_Sales_Block_Order_Tax'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Address'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Address_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Attribute_Backend_Billing'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Attribute_Backend_Child'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Attribute_Backend_Parent'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Attribute_Backend_Shipping'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo_Attribute_Backend_Child'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo_Attribute_Backend_Parent'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo_Comment'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo_Comment_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo_Item'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Creditmemo_Item_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Child'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Item'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Order'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Parent'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Comment'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Comment_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Item'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Invoice_Item_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Item'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Item_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Payment'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Payment_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Attribute_Backend_Child'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Attribute_Backend_Parent'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Comment'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Comment_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Item'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Item_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Track'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Shipment_Track_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Status_History'), - $this->_getClassRule('Mage_Sales_Model_Entity_Order_Status_History_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend_Child'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend_Parent'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend_Region'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Custbalance'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Discount'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Grand'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Shipping'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Subtotal'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Tax'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Item'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Item_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Rate'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Address_Rate_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Item'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Item_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Payment'), - $this->_getClassRule('Mage_Sales_Model_Entity_Quote_Payment_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Sale_Collection'), - $this->_getClassRule('Mage_Sales_Model_Entity_Setup'), - $this->_getClassRule('Mage_Shipping_ShippingController'), - $this->_getClassRule('Mage_Tag_Block_Customer_Edit'), - $this->_getClassRule('Mage_User_Block_Role_Grid'), - $this->_getClassRule('Mage_User_Block_User_Grid'), - $this->_getClassRule('Mage_User_Model_Roles'), - $this->_getClassRule('Mage_User_Model_Resource_Roles'), - $this->_getClassRule('Mage_User_Model_Resource_Roles_Collection'), - $this->_getClassRule('Mage_User_Model_Resource_Roles_User_Collection'), - $this->_getClassRule('Mage_Wishlist_Model_Resource_Product_Collection'), - $this->_getClassRule('Varien_Convert_Action'), - $this->_getClassRule('Varien_Convert_Action_Abstract'), - $this->_getClassRule('Varien_Convert_Action_Interface'), - $this->_getClassRule('Varien_Convert_Adapter_Abstract'), - $this->_getClassRule('Varien_Convert_Adapter_Db_Table'), - $this->_getClassRule('Varien_Convert_Adapter_Http'), - $this->_getClassRule('Varien_Convert_Adapter_Http_Curl'), - $this->_getClassRule('Varien_Convert_Adapter_Interface'), - $this->_getClassRule('Varien_Convert_Adapter_Io'), - $this->_getClassRule('Varien_Convert_Adapter_Soap'), - $this->_getClassRule('Varien_Convert_Adapter_Std'), - $this->_getClassRule('Varien_Convert_Adapter_Zend_Cache'), - $this->_getClassRule('Varien_Convert_Adapter_Zend_Db'), - $this->_getClassRule('Varien_Convert_Container_Collection'), - $this->_getClassRule('Varien_Convert_Container_Generic'), - $this->_getClassRule('Varien_Convert_Container_Interface'), - $this->_getClassRule('Varien_Convert_Mapper_Abstract'), - $this->_getClassRule('Varien_Convert_Parser_Abstract'), - $this->_getClassRule('Varien_Convert_Parser_Csv'), - $this->_getClassRule('Varien_Convert_Parser_Interface'), - $this->_getClassRule('Varien_Convert_Parser_Serialize'), - $this->_getClassRule('Varien_Convert_Parser_Xml_Excel'), - $this->_getClassRule('Varien_Convert_Profile'), - $this->_getClassRule('Varien_Convert_Profile_Abstract'), - $this->_getClassRule('Varien_Convert_Profile_Collection'), - $this->_getClassRule('Varien_Convert_Validator_Abstract'), - $this->_getClassRule('Varien_Convert_Validator_Column'), - $this->_getClassRule('Varien_Convert_Validator_Dryrun'), - $this->_getClassRule('Varien_Convert_Validator_Interface'), - $this->_getClassRule('Varien_File_Uploader_Image'), - $this->_getClassRule('Varien_Profiler', 'Magento_Profiler'), + array('Mage_Reports_Model_Resource_Refunded_Collection'), + array('Mage_Reports_Model_Resource_Shipping_Collection'), + array('Mage_Rss_Model_Observer'), + array('Mage_Rss_Model_Session', 'Mage_Backend_Model_Auth and Mage_Backend_Model_Auth_Session'), + array('Mage_Sales_Block_Order_Details'), + array('Mage_Sales_Block_Order_Tax'), + array('Mage_Sales_Model_Entity_Order'), + array('Mage_Sales_Model_Entity_Order_Address'), + array('Mage_Sales_Model_Entity_Order_Address_Collection'), + array('Mage_Sales_Model_Entity_Order_Attribute_Backend_Billing'), + array('Mage_Sales_Model_Entity_Order_Attribute_Backend_Child'), + array('Mage_Sales_Model_Entity_Order_Attribute_Backend_Parent'), + array('Mage_Sales_Model_Entity_Order_Attribute_Backend_Shipping'), + array('Mage_Sales_Model_Entity_Order_Collection'), + array('Mage_Sales_Model_Entity_Order_Creditmemo'), + array('Mage_Sales_Model_Entity_Order_Creditmemo_Attribute_Backend_Child'), + array('Mage_Sales_Model_Entity_Order_Creditmemo_Attribute_Backend_Parent'), + array('Mage_Sales_Model_Entity_Order_Creditmemo_Collection'), + array('Mage_Sales_Model_Entity_Order_Creditmemo_Comment'), + array('Mage_Sales_Model_Entity_Order_Creditmemo_Comment_Collection'), + array('Mage_Sales_Model_Entity_Order_Creditmemo_Item'), + array('Mage_Sales_Model_Entity_Order_Creditmemo_Item_Collection'), + array('Mage_Sales_Model_Entity_Order_Invoice'), + array('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Child'), + array('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Item'), + array('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Order'), + array('Mage_Sales_Model_Entity_Order_Invoice_Attribute_Backend_Parent'), + array('Mage_Sales_Model_Entity_Order_Invoice_Collection'), + array('Mage_Sales_Model_Entity_Order_Invoice_Comment'), + array('Mage_Sales_Model_Entity_Order_Invoice_Comment_Collection'), + array('Mage_Sales_Model_Entity_Order_Invoice_Item'), + array('Mage_Sales_Model_Entity_Order_Invoice_Item_Collection'), + array('Mage_Sales_Model_Entity_Order_Item'), + array('Mage_Sales_Model_Entity_Order_Item_Collection'), + array('Mage_Sales_Model_Entity_Order_Payment'), + array('Mage_Sales_Model_Entity_Order_Payment_Collection'), + array('Mage_Sales_Model_Entity_Order_Shipment'), + array('Mage_Sales_Model_Entity_Order_Shipment_Attribute_Backend_Child'), + array('Mage_Sales_Model_Entity_Order_Shipment_Attribute_Backend_Parent'), + array('Mage_Sales_Model_Entity_Order_Shipment_Collection'), + array('Mage_Sales_Model_Entity_Order_Shipment_Comment'), + array('Mage_Sales_Model_Entity_Order_Shipment_Comment_Collection'), + array('Mage_Sales_Model_Entity_Order_Shipment_Item'), + array('Mage_Sales_Model_Entity_Order_Shipment_Item_Collection'), + array('Mage_Sales_Model_Entity_Order_Shipment_Track'), + array('Mage_Sales_Model_Entity_Order_Shipment_Track_Collection'), + array('Mage_Sales_Model_Entity_Order_Status_History'), + array('Mage_Sales_Model_Entity_Order_Status_History_Collection'), + array('Mage_Sales_Model_Entity_Quote'), + array('Mage_Sales_Model_Entity_Quote_Address'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend_Child'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend_Parent'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Backend_Region'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Custbalance'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Discount'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Grand'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Shipping'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Subtotal'), + array('Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Tax'), + array('Mage_Sales_Model_Entity_Quote_Address_Collection'), + array('Mage_Sales_Model_Entity_Quote_Address_Item'), + array('Mage_Sales_Model_Entity_Quote_Address_Item_Collection'), + array('Mage_Sales_Model_Entity_Quote_Address_Rate'), + array('Mage_Sales_Model_Entity_Quote_Address_Rate_Collection'), + array('Mage_Sales_Model_Entity_Quote_Collection'), + array('Mage_Sales_Model_Entity_Quote_Item'), + array('Mage_Sales_Model_Entity_Quote_Item_Collection'), + array('Mage_Sales_Model_Entity_Quote_Payment'), + array('Mage_Sales_Model_Entity_Quote_Payment_Collection'), + array('Mage_Sales_Model_Entity_Sale_Collection'), + array('Mage_Sales_Model_Entity_Setup'), + array('Mage_Shipping_ShippingController'), + array('Mage_Tag_Block_Customer_Edit'), + array('Mage_User_Block_Role_Grid'), + array('Mage_User_Block_User_Grid'), + array('Mage_User_Model_Roles'), + array('Mage_User_Model_Resource_Roles'), + array('Mage_User_Model_Resource_Roles_Collection'), + array('Mage_User_Model_Resource_Roles_User_Collection'), + array('Mage_Wishlist_Model_Resource_Product_Collection'), + array('Varien_Convert_Action'), + array('Varien_Convert_Action_Abstract'), + array('Varien_Convert_Action_Interface'), + array('Varien_Convert_Adapter_Abstract'), + array('Varien_Convert_Adapter_Db_Table'), + array('Varien_Convert_Adapter_Http'), + array('Varien_Convert_Adapter_Http_Curl'), + array('Varien_Convert_Adapter_Interface'), + array('Varien_Convert_Adapter_Io'), + array('Varien_Convert_Adapter_Soap'), + array('Varien_Convert_Adapter_Std'), + array('Varien_Convert_Adapter_Zend_Cache'), + array('Varien_Convert_Adapter_Zend_Db'), + array('Varien_Convert_Container_Collection'), + array('Varien_Convert_Container_Generic'), + array('Varien_Convert_Container_Interface'), + array('Varien_Convert_Mapper_Abstract'), + array('Varien_Convert_Parser_Abstract'), + array('Varien_Convert_Parser_Csv'), + array('Varien_Convert_Parser_Interface'), + array('Varien_Convert_Parser_Serialize'), + array('Varien_Convert_Parser_Xml_Excel'), + array('Varien_Convert_Profile'), + array('Varien_Convert_Profile_Abstract'), + array('Varien_Convert_Profile_Collection'), + array('Varien_Convert_Validator_Abstract'), + array('Varien_Convert_Validator_Column'), + array('Varien_Convert_Validator_Dryrun'), + array('Varien_Convert_Validator_Interface'), + array('Varien_File_Uploader_Image'), + array('Varien_Profiler', 'Magento_Profiler'), ); diff --git a/dev/tests/static/testsuite/Legacy/_files/obsolete_constants.php b/dev/tests/static/testsuite/Legacy/_files/obsolete_constants.php index 1d241ab1d25..be48adab35a 100644 --- a/dev/tests/static/testsuite/Legacy/_files/obsolete_constants.php +++ b/dev/tests/static/testsuite/Legacy/_files/obsolete_constants.php @@ -1,5 +1,9 @@ <?php /** + * Obsolete constants + * + * Format: array(<constant_name>[, <class_scope> = ''[, <replacement>]]) + * * Magento * * NOTICE OF LICENSE @@ -18,50 +22,48 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category tests - * @package static - * @subpackage Legacy * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ return array( - $this->_getRule('GALLERY_IMAGE_TABLE', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Media'), - $this->_getRule('DEFAULT_VALUE_TABLE_PREFIX'), - $this->_getRule('CATEGORY_APPLY_CATEGORY_AND_PRODUCT_RECURSIVE'), - $this->_getRule('CATEGORY_APPLY_CATEGORY_ONLY'), - $this->_getRule('CATEGORY_APPLY_CATEGORY_AND_PRODUCT_ONLY'), - $this->_getRule('CATEGORY_APPLY_CATEGORY_RECURSIVE'), - $this->_getRule('BACKORDERS_BELOW'), - $this->_getRule('BACKORDERS_YES'), - $this->_getRule('XML_PATH_DEFAULT_COUNTRY', 'Mage_Core_Model_Locale'), - $this->_getRule('XML_PATH_SENDING_SET_RETURN_PATH', 'Mage_Newsletter_Model_Subscriber'), - $this->_getRule('CHECKSUM_KEY_NAME'), - $this->_getRule('XML_PATH_COUNTRY_DEFAULT', 'Mage_Paypal_Model_System_Config_Backend_MerchantCountry'), - $this->_getRule('ENTITY_PRODUCT', 'Mage_Review_Model_Review'), - $this->_getRule('CHECKOUT_METHOD_REGISTER'), - $this->_getRule('CHECKOUT_METHOD_GUEST'), - $this->_getRule('CONFIG_XML_PATH_SHOW_IN_CATALOG'), - $this->_getRule('CONFIG_XML_PATH_DEFAULT_PRODUCT_TAX_GROUP'), - $this->_getRule('CONFIG_XML_PATH_DISPLAY_TAX_COLUMN'), - $this->_getRule('CONFIG_XML_PATH_DISPLAY_FULL_SUMMARY'), - $this->_getRule('CONFIG_XML_PATH_DISPLAY_ZERO_TAX'), - $this->_getRule('EXCEPTION_CODE_IS_GROUPED_PRODUCT'), - $this->_getRule('Mage_Rss_Block_Catalog_NotifyStock::CACHE_TAG'), - $this->_getRule('Mage_Rss_Block_Catalog_Review::CACHE_TAG'), - $this->_getRule('Mage_Rss_Block_Order_New::CACHE_TAG'), - $this->_getRule('REGISTRY_FORM_PARAMS_KEY', null, 'direct value'), - $this->_getRule('TYPE_TINYINT', null, 'Varien_Db_Ddl_Table::TYPE_SMALLINT'), - $this->_getRule('TYPE_CHAR', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), - $this->_getRule('TYPE_VARCHAR', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), - $this->_getRule('TYPE_LONGVARCHAR', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), - $this->_getRule('TYPE_CLOB', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), - $this->_getRule('TYPE_DOUBLE', null, 'Varien_Db_Ddl_Table::TYPE_FLOAT'), - $this->_getRule('TYPE_REAL', null, 'Varien_Db_Ddl_Table::TYPE_FLOAT'), - $this->_getRule('TYPE_TIME', null, 'Varien_Db_Ddl_Table::TYPE_TIMESTAMP'), - $this->_getRule('TYPE_BINARY', null, 'Varien_Db_Ddl_Table::TYPE_BLOB'), - $this->_getRule('TYPE_LONGVARBINARY', null, 'Varien_Db_Ddl_Table::TYPE_BLOB'), - $this->_getRule('HASH_ALGO'), - $this->_getRule('SEESION_MAX_COOKIE_LIFETIME'), - $this->_getRule('URL_TYPE_SKIN'), - $this->_getRule('DEFAULT_THEME_NAME', 'Mage_Core_Model_Design_Package'), + array('GALLERY_IMAGE_TABLE', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Media'), + array('DEFAULT_VALUE_TABLE_PREFIX'), + array('CATEGORY_APPLY_CATEGORY_AND_PRODUCT_RECURSIVE'), + array('CATEGORY_APPLY_CATEGORY_ONLY'), + array('CATEGORY_APPLY_CATEGORY_AND_PRODUCT_ONLY'), + array('CATEGORY_APPLY_CATEGORY_RECURSIVE'), + array('BACKORDERS_BELOW'), + array('BACKORDERS_YES'), + array('XML_PATH_DEFAULT_COUNTRY', 'Mage_Core_Model_Locale'), + array('XML_PATH_SENDING_SET_RETURN_PATH', 'Mage_Newsletter_Model_Subscriber'), + array('CHECKSUM_KEY_NAME'), + array('XML_PATH_COUNTRY_DEFAULT', 'Mage_Paypal_Model_System_Config_Backend_MerchantCountry'), + array('ENTITY_PRODUCT', 'Mage_Review_Model_Review'), + array('CHECKOUT_METHOD_REGISTER'), + array('CHECKOUT_METHOD_GUEST'), + array('CONFIG_XML_PATH_SHOW_IN_CATALOG'), + array('CONFIG_XML_PATH_DEFAULT_PRODUCT_TAX_GROUP'), + array('CONFIG_XML_PATH_DISPLAY_TAX_COLUMN'), + array('CONFIG_XML_PATH_DISPLAY_FULL_SUMMARY'), + array('CONFIG_XML_PATH_DISPLAY_ZERO_TAX'), + array('EXCEPTION_CODE_IS_GROUPED_PRODUCT'), + array('Mage_Rss_Block_Catalog_NotifyStock::CACHE_TAG'), + array('Mage_Rss_Block_Catalog_Review::CACHE_TAG'), + array('Mage_Rss_Block_Order_New::CACHE_TAG'), + array('REGISTRY_FORM_PARAMS_KEY', null, 'direct value'), + array('TYPE_TINYINT', null, 'Varien_Db_Ddl_Table::TYPE_SMALLINT'), + array('TYPE_CHAR', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), + array('TYPE_VARCHAR', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), + array('TYPE_LONGVARCHAR', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), + array('TYPE_CLOB', null, 'Varien_Db_Ddl_Table::TYPE_TEXT'), + array('TYPE_DOUBLE', null, 'Varien_Db_Ddl_Table::TYPE_FLOAT'), + array('TYPE_REAL', null, 'Varien_Db_Ddl_Table::TYPE_FLOAT'), + array('TYPE_TIME', null, 'Varien_Db_Ddl_Table::TYPE_TIMESTAMP'), + array('TYPE_BINARY', null, 'Varien_Db_Ddl_Table::TYPE_BLOB'), + array('TYPE_LONGVARBINARY', null, 'Varien_Db_Ddl_Table::TYPE_BLOB'), + array('HASH_ALGO'), + array('SEESION_MAX_COOKIE_LIFETIME'), + array('URL_TYPE_SKIN'), + array('INSTALLER_HOST_RESPONSE', 'Mage_Install_Model_Installer'), + array('DEFAULT_THEME_NAME', 'Mage_Core_Model_Design_Package'), ); diff --git a/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php b/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php index 82e82106bcf..7112523adc1 100644 --- a/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php +++ b/dev/tests/static/testsuite/Legacy/_files/obsolete_methods.php @@ -1,5 +1,9 @@ <?php /** + * Obsolete methods + * + * Format: array(<method_name = ''>[, <class_scope> = ''[, <replacement>]]) + * * Magento * * NOTICE OF LICENSE @@ -18,413 +22,417 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category tests - * @package static - * @subpackage Legacy * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - -/** @var $this Legacy_ObsoleteCodeTest */ return array( - $this->_getRule('__get', 'Varien_Object'), - $this->_getRule('__set', 'Varien_Object'), - $this->_getRule('_addMinimalPrice', 'Mage_Catalog_Model_Resource_Product_Collection'), - $this->_getRule('_addTaxPercents', 'Mage_Catalog_Model_Resource_Product_Collection'), - $this->_getRule('_afterSaveCommit', 'Mage_Core_Model_Abstract'), - $this->_getRule('_afterSetConfig', 'Mage_Eav_Model_Entity_Abstract'), - $this->_getRule('_aggregateByOrderCreatedAt', 'Mage_SalesRule_Model_Resource_Report_Rule'), - $this->_getRule('_amountByCookies', 'Mage_Sendfriend_Model_Sendfriend'), - $this->_getRule('_amountByIp', 'Mage_Sendfriend_Model_Sendfriend'), - $this->_getRule('_applyCustomDesignSettings'), - $this->_getRule('_applyDesign', 'Mage_Catalog_Model_Design'), - $this->_getRule('_applyDesignRecursively', 'Mage_Catalog_Model_Design'), - $this->_getRule('_avoidDoubleTransactionProcessing'), - $this->_getRule('_beforeChildToHtml'), - $this->_getRule('_calculatePrice', 'Mage_Sales_Model_Quote_Item_Abstract'), - $this->_getRule('_canShowField', 'Mage_Backend_Block_System_Config_Form'), - $this->_getRule('_canUseLocalModules'), - $this->_getRule('_checkUrlSettings', 'Mage_Adminhtml_Controller_Action'), - $this->_getRule('_collectOrigData', 'Mage_Catalog_Model_Resource_Abstract'), - $this->_getRule('_decodeInput', 'Mage_Adminhtml_Catalog_ProductController'), - $this->_getRule('_emailOrderConfirmation', 'Mage_Checkout_Model_Type_Abstract'), - $this->_getRule('_escapeValue', 'Mage_Adminhtml_Block_Widget_Grid_Column_Filter_Abstract'), - $this->_getRule('_getAddressTaxRequest', 'Mage_Tax_Model_Sales_Total_Quote_Shipping'), - $this->_getRule('_getAggregationPerStoreView'), - $this->_getRule('_getAttributeFilterBlockName', 'Mage_Catalog_Block_Layer_View'), - $this->_getRule('_getAttributeFilterBlockName', 'Mage_CatalogSearch_Block_Layer'), - $this->_getRule('_getAttributeFilterBlockName'), - $this->_getRule('_getAvailable', 'Mage_GiftMessage_Model_Observer'), - $this->_getRule('_getCacheId', 'Mage_Core_Model_App'), - $this->_getRule('_getCacheKey', 'Mage_Catalog_Model_Layer_Filter_Price'), - $this->_getRule('_getCacheTags', 'Mage_Core_Model_App'), - $this->_getRule('_getChildHtml'), - $this->_getRule('_getCollapseState', 'Mage_Backend_Block_System_Config_Form_Fieldset', '_isCollapseState'), - $this->_getRule('_getCollectionNames', 'Mage_Adminhtml_Report_SalesController'), - $this->_getRule('_getConnenctionType', 'Mage_Install_Model_Installer_Db'), - $this->_getRule('_getDateFromToHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), - $this->_getRule('_getExistingBasePopularity'), - $this->_getRule('_getFieldTableAlias', 'Mage_Newsletter_Model_Resource_Subscriber_Collection'), - $this->_getRule('_getForeignKeyName', 'Varien_Db_Adapter_Pdo_Mysql'), - $this->_getRule('_getGiftmessageSaveModel', 'Mage_Adminhtml_Block_Sales_Order_Create_Search_Grid'), - $this->_getRule('_getGlobalAggregation'), - $this->_getRule('_getGroupByDateFormat', 'Mage_Log_Model_Resource_Visitor_Collection'), - $this->_getRule('_getInputHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), - $this->_getRule('_getLabelForStore', 'Mage_Catalog_Model_Resource_Eav_Attribute'), - $this->_getRule('_getMultiSelectHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), - $this->_getRule('_getNumberFromToHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), - $this->_getRule('_getPriceFilter', 'Mage_Catalog_Block_Layer_View'), - $this->_getRule('_getProductQtyForCheck', 'Mage_CatalogInventory_Model_Observer'), - $this->_getRule('_getRangeByType', 'Mage_Log_Model_Resource_Visitor_Collection'), - $this->_getRule('_getRecentProductsCollection'), - $this->_getRule('_getSelectHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), - $this->_getRule('_getSetData', 'Mage_Adminhtml_Block_Catalog_Product_Attribute_Set_Main'), - $this->_getRule('_getSHAInSet', null, 'Mage_Ogone_Model_Api::getHash'), - $this->_getRule('_getStoreTaxRequest', 'Mage_Tax_Model_Sales_Total_Quote_Shipping'), - $this->_getRule('_importAddress', 'Mage_Paypal_Model_Api_Nvp'), - $this->_getRule('_inheritDesign', 'Mage_Catalog_Model_Design'), - $this->_getRule('_initOrder', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('_initShipment', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('_inludeControllerClass', null, '_includeControllerClass'), - $this->_getRule('_isApplyDesign', 'Mage_Catalog_Model_Design'), - $this->_getRule('_isApplyFor', 'Mage_Catalog_Model_Design'), - $this->_getRule('_isPositiveDecimalNumber', 'Mage_Shipping_Model_Resource_Carrier_Tablerate'), - $this->_getRule('_loadOldRates', 'Mage_Tax_Model_Resource_Setup'), - $this->_getRule('_needSubtractShippingTax'), - $this->_getRule('_needSubtractTax'), - $this->_getRule('_needToAddDummy'), - $this->_getRule('_needToAddDummyForShipment'), - $this->_getRule('_parseDescription', 'Mage_Sales_Model_Order_Pdf_Items_Abstract'), - $this->_getRule('_parseXmlTrackingResponse', 'Mage_Usa_Model_Shipping_Carrier_Fedex'), - $this->_getRule('_prepareCondition', 'Mage_CatalogSearch_Model_Advanced'), - $this->_getRule('_prepareConfigurableProductData', 'Mage_ImportExport_Model_Export_Entity_Product'), - $this->_getRule('_prepareConfigurableProductPrice', 'Mage_ImportExport_Model_Export_Entity_Product'), - $this->_getRule('_prepareOptionsForCart', 'Mage_Catalog_Model_Product_Type_Abstract'), - $this->_getRule('_preparePackageTheme', 'Mage_Widget_Model_Widget_Instance'), - $this->_getRule('_processItem', 'Mage_Weee_Model_Total_Quote_Weee'), - $this->_getRule('_processShippingAmount'), - $this->_getRule('_processValidateCustomer', 'Mage_Checkout_Model_Type_Onepage'), - $this->_getRule('_putCustomerIntoQuote', 'Mage_Adminhtml_Model_Sales_Order_Create'), - $this->_getRule('_quoteRow', 'Mage_Backup_Model_Resource_Db'), - $this->_getRule('_recollectItem', 'Mage_Tax_Model_Sales_Total_Quote_Subtotal'), - $this->_getRule('_resetItemPriceInclTax'), - $this->_getRule('_saveCustomerAfterOrder', 'Mage_Adminhtml_Model_Sales_Order_Create'), - $this->_getRule('_saveCustomers', 'Mage_Adminhtml_Model_Sales_Order_Create'), - $this->_getRule('_sendUploadResponse', 'Mage_Adminhtml_CustomerController'), - $this->_getRule('_sendUploadResponse', 'Mage_Adminhtml_Newsletter_SubscriberController'), - $this->_getRule('_setAttribteValue'), - $this->_getRule('_sort', 'Mage_Backend_Model_Config_Structure_Converter'), - $this->_getRule('_usePriceIncludeTax'), - $this->_getRule('addBackupedFilter'), - $this->_getRule('addConfigField', 'Mage_Core_Model_Resource_Setup'), - $this->_getRule('addConstraint', 'Varien_Db_Adapter_Pdo_Mysql'), - $this->_getRule('addCustomersToAlertQueueAction'), - $this->_getRule('addCustomerToSegments'), - $this->_getRule('addGroupByTag', 'Mage_Tag_Model_Resource_Reports_Collection'), - $this->_getRule('addKey', 'Varien_Db_Adapter_Pdo_Mysql'), - $this->_getRule('addSaleableFilterToCollection'), - $this->_getRule('addSearchQfFilter'), - $this->_getRule('addStoresFilter', 'Mage_Poll_Model_Resource_Poll_Collection'), - $this->_getRule('addSummary', 'Mage_Tag_Model_Resource_Tag'), - $this->_getRule('addSummary', 'Mage_Tag_Model_Tag'), - $this->_getRule('addTemplateData', 'Mage_Newsletter_Model_Queue'), - $this->_getRule('addToAlersAction'), - $this->_getRule('addToChildGroup'), - $this->_getRule('addVisibleFilterToCollection', 'Mage_Catalog_Model_Product_Status'), - $this->_getRule('addVisibleInCatalogFilterToCollection', null, + array('__get', 'Varien_Object'), + array('__set', 'Varien_Object'), + array('_addMinimalPrice', 'Mage_Catalog_Model_Resource_Product_Collection'), + array('_addTaxPercents', 'Mage_Catalog_Model_Resource_Product_Collection'), + array('_afterSaveCommit', 'Mage_Core_Model_Abstract'), + array('_afterSetConfig', 'Mage_Eav_Model_Entity_Abstract'), + array('_aggregateByOrderCreatedAt', 'Mage_SalesRule_Model_Resource_Report_Rule'), + array('_amountByCookies', 'Mage_Sendfriend_Model_Sendfriend'), + array('_amountByIp', 'Mage_Sendfriend_Model_Sendfriend'), + array('_applyCustomDesignSettings'), + array('_applyDesign', 'Mage_Catalog_Model_Design'), + array('_applyDesignRecursively', 'Mage_Catalog_Model_Design'), + array('_avoidDoubleTransactionProcessing'), + array('_beforeChildToHtml'), + array('_calculatePrice', 'Mage_Sales_Model_Quote_Item_Abstract'), + array('_canShowField', 'Mage_Backend_Block_System_Config_Form'), + array('_canUseLocalModules'), + array('_checkUrlSettings', 'Mage_Adminhtml_Controller_Action'), + array('_collectOrigData', 'Mage_Catalog_Model_Resource_Abstract'), + array('_decodeInput', 'Mage_Adminhtml_Catalog_ProductController'), + array('_emailOrderConfirmation', 'Mage_Checkout_Model_Type_Abstract'), + array('_escapeValue', 'Mage_Adminhtml_Block_Widget_Grid_Column_Filter_Abstract'), + array('_getAddressTaxRequest', 'Mage_Tax_Model_Sales_Total_Quote_Shipping'), + array('_getAggregationPerStoreView'), + array('_getAttributeFilterBlockName', 'Mage_Catalog_Block_Layer_View'), + array('_getAttributeFilterBlockName', 'Mage_CatalogSearch_Block_Layer'), + array('_getAttributeFilterBlockName'), + array('_getAvailable', 'Mage_GiftMessage_Model_Observer'), + array('_getCacheId', 'Mage_Core_Model_App'), + array('_getCacheKey', 'Mage_Catalog_Model_Layer_Filter_Price'), + array('_getCacheTags', 'Mage_Core_Model_App'), + array('_getChildHtml'), + array('_getCollapseState', 'Mage_Backend_Block_System_Config_Form_Fieldset', '_isCollapseState'), + array('_getCollectionNames', 'Mage_Adminhtml_Report_SalesController'), + array('_getConnenctionType', 'Mage_Install_Model_Installer_Db'), + array('_getDateFromToHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), + array('_getExistingBasePopularity'), + array('_getFieldTableAlias', 'Mage_Newsletter_Model_Resource_Subscriber_Collection'), + array('_getForeignKeyName', 'Varien_Db_Adapter_Pdo_Mysql'), + array('_getGiftmessageSaveModel', 'Mage_Adminhtml_Block_Sales_Order_Create_Search_Grid'), + array('_getGlobalAggregation'), + array('_getGroupByDateFormat', 'Mage_Log_Model_Resource_Visitor_Collection'), + array('_getInputHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), + array('_getLabelForStore', 'Mage_Catalog_Model_Resource_Eav_Attribute'), + array('_getMultiSelectHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), + array('_getNumberFromToHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), + array('_getPriceFilter', 'Mage_Catalog_Block_Layer_View'), + array('_getProductQtyForCheck', 'Mage_CatalogInventory_Model_Observer'), + array('_getRangeByType', 'Mage_Log_Model_Resource_Visitor_Collection'), + array('_getRecentProductsCollection'), + array('_getSelectHtml', 'Mage_ImportExport_Block_Adminhtml_Export_Filter'), + array('_getSetData', 'Mage_Adminhtml_Block_Catalog_Product_Attribute_Set_Main'), + array('_getSHAInSet', null, 'Mage_Ogone_Model_Api::getHash'), + array('_getStoreTaxRequest', 'Mage_Tax_Model_Sales_Total_Quote_Shipping'), + array('_importAddress', 'Mage_Paypal_Model_Api_Nvp'), + array('_inheritDesign', 'Mage_Catalog_Model_Design'), + array('_initOrder', 'Mage_Shipping_Block_Tracking_Popup'), + array('_initShipment', 'Mage_Shipping_Block_Tracking_Popup'), + array('_inludeControllerClass', null, '_includeControllerClass'), + array('_isApplyDesign', 'Mage_Catalog_Model_Design'), + array('_isApplyFor', 'Mage_Catalog_Model_Design'), + array('_isPositiveDecimalNumber', 'Mage_Shipping_Model_Resource_Carrier_Tablerate'), + array('_loadOldRates', 'Mage_Tax_Model_Resource_Setup'), + array('_needSubtractShippingTax'), + array('_needSubtractTax'), + array('_needToAddDummy'), + array('_needToAddDummyForShipment'), + array('_parseDescription', 'Mage_Sales_Model_Order_Pdf_Items_Abstract'), + array('_parseXmlTrackingResponse', 'Mage_Usa_Model_Shipping_Carrier_Fedex'), + array('_prepareCondition', 'Mage_CatalogSearch_Model_Advanced'), + array('_prepareConfigurableProductData', 'Mage_ImportExport_Model_Export_Entity_Product'), + array('_prepareConfigurableProductPrice', 'Mage_ImportExport_Model_Export_Entity_Product'), + array('_prepareOptionsForCart', 'Mage_Catalog_Model_Product_Type_Abstract'), + array('_preparePackageTheme', 'Mage_Widget_Model_Widget_Instance'), + array('_processItem', 'Mage_Weee_Model_Total_Quote_Weee'), + array('_processShippingAmount'), + array('_processValidateCustomer', 'Mage_Checkout_Model_Type_Onepage'), + array('_putCustomerIntoQuote', 'Mage_Adminhtml_Model_Sales_Order_Create'), + array('_quoteRow', 'Mage_Backup_Model_Resource_Db'), + array('_recollectItem', 'Mage_Tax_Model_Sales_Total_Quote_Subtotal'), + array('_resetItemPriceInclTax'), + array('_saveCustomerAfterOrder', 'Mage_Adminhtml_Model_Sales_Order_Create'), + array('_saveCustomers', 'Mage_Adminhtml_Model_Sales_Order_Create'), + array('_sendUploadResponse', 'Mage_Adminhtml_CustomerController'), + array('_sendUploadResponse', 'Mage_Adminhtml_Newsletter_SubscriberController'), + array('_setAttribteValue'), + array('_sort', 'Mage_Backend_Model_Config_Structure_Converter'), + array('_updateMediaPathUseRewrites', 'Mage_Core_Model_Store', '_getMediaScriptUrl'), + array('_usePriceIncludeTax'), + array('addBackupedFilter'), + array('addConfigField', 'Mage_Core_Model_Resource_Setup'), + array('addConstraint', 'Varien_Db_Adapter_Pdo_Mysql'), + array('addCustomersToAlertQueueAction'), + array('addCustomerToSegments'), + array('addGroupByTag', 'Mage_Tag_Model_Resource_Reports_Collection'), + array('addKey', 'Varien_Db_Adapter_Pdo_Mysql'), + array('addSaleableFilterToCollection'), + array('addSearchQfFilter'), + array('addStoresFilter', 'Mage_Poll_Model_Resource_Poll_Collection'), + array('addSummary', 'Mage_Tag_Model_Resource_Tag'), + array('addSummary', 'Mage_Tag_Model_Tag'), + array('addTemplateData', 'Mage_Newsletter_Model_Queue'), + array('addToAlersAction'), + array('addToChildGroup'), + array('addVisibleFilterToCollection', 'Mage_Catalog_Model_Product_Status'), + array('addVisibleInCatalogFilterToCollection', null, '$collection->setVisibility(Mage_Catalog_Model_Product_Visibility->getVisibleInCatalogIds());'), - $this->_getRule('addVisibleInSearchFilterToCollection', null, + array('addVisibleInSearchFilterToCollection', null, '$collection->setVisibility(Mage_Catalog_Model_Product_Visibility->getVisibleInSearchIds());'), - $this->_getRule('addVisibleInSiteFilterToCollection', null, + array('addVisibleInSiteFilterToCollection', null, '$collection->setVisibility(Mage_Catalog_Model_Product_Visibility->getVisibleInSiteIds());'), - $this->_getRule('addWishlistLink', 'Mage_Wishlist_Block_Links'), - $this->_getRule('addWishListSortOrder', 'Mage_Wishlist_Model_Resource_Item_Collection'), - $this->_getRule('aggregate', 'Mage_Tag_Model_Resource_Tag'), - $this->_getRule('aggregate', 'Mage_Tag_Model_Tag'), - $this->_getRule('applyDesign', 'Mage_Catalog_Model_Design'), - $this->_getRule('authAdmin'), - $this->_getRule('authFailed', null, 'Mage_Core_Helper_Http::failHttpAuthentication()'), - $this->_getRule('authFrontend'), - $this->_getRule('authValidate', null, 'Mage_Core_Helper_Http::getHttpAuthCredentials()'), - $this->_getRule('bundlesAction', 'Mage_Adminhtml_Catalog_ProductController'), - $this->_getRule('calcTaxAmount', 'Mage_Sales_Model_Quote_Item_Abstract'), - $this->_getRule('canPrint', 'Mage_Checkout_Block_Onepage_Success'), - $this->_getRule('catalogCategoryChangeProducts', 'Mage_Catalog_Model_Product_Flat_Observer'), - $this->_getRule('catalogEventProductCollectionAfterLoad', 'Mage_GiftMessage_Model_Observer'), - $this->_getRule('catalogProductLoadAfter', 'Mage_Bundle_Model_Observer'), - $this->_getRule('chechAllowedExtension'), - $this->_getRule('checkConfigurableProducts', 'Mage_Eav_Model_Resource_Entity_Attribute_Collection'), - $this->_getRule('checkDatabase', 'Mage_Install_Model_Installer_Db'), - $this->_getRule('checkDateTime', 'Mage_Core_Model_Date'), - $this->_getRule('cleanDbRow', 'Mage_Core_Model_Resource'), - $this->_getRule('cloneIndexTable', 'Mage_Index_Model_Resource_Abstract'), - $this->_getRule('convertOldTaxData', 'Mage_Tax_Model_Resource_Setup'), - $this->_getRule('convertOldTreeToNew', 'Mage_Catalog_Model_Resource_Setup'), - $this->_getRule('countChildren', 'Mage_Core_Block_Abstract'), - $this->_getRule('crear'), - $this->_getRule('createOrderItem', 'Mage_CatalogInventory_Model_Observer'), - $this->_getRule('debugRequest', 'Mage_Paypal_Model_Api_Standard'), - $this->_getRule('deleteProductPrices', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Tierprice'), - $this->_getRule('display', 'Varien_Image_Adapter_Abstract', 'getImage()'), - $this->_getRule('displayFullSummary', 'Mage_Tax_Model_Config'), - $this->_getRule('displayTaxColumn', 'Mage_Tax_Model_Config'), - $this->_getRule('displayZeroTax', 'Mage_Tax_Model_Config'), - $this->_getRule('drawItem', 'Mage_Catalog_Block_Navigation'), - $this->_getRule('dropKey', 'Varien_Db_Adapter_Pdo_Mysql'), - $this->_getRule('editAction', 'Mage_Tag_CustomerController'), - $this->_getRule('escapeJs', 'Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config'), - $this->_getRule('exportOrderedCsvAction'), - $this->_getRule('exportOrderedExcelAction'), - $this->_getRule('fetchItemsCount', 'Mage_Wishlist_Model_Resource_Wishlist'), - $this->_getRule('fetchRuleRatesForCustomerTaxClass'), - $this->_getRule('forsedSave'), - $this->_getRule('generateBlocks', null, 'generateElements()'), - $this->_getRule('getAccount', 'Mage_GoogleAnalytics_Block_Ga'), - $this->_getRule('getAclAssert', 'Mage_Admin_Model_Config'), - $this->_getRule('getAclPrivilegeSet', 'Mage_Admin_Model_Config'), - $this->_getRule('getAclResourceList', 'Mage_Admin_Model_Config'), - $this->_getRule('getAclResourceTree', 'Mage_Admin_Model_Config'), - $this->_getRule('getAddNewButtonHtml', 'Mage_Adminhtml_Block_Catalog_Product'), - $this->_getRule('getAddToCartItemUrl', 'Mage_Wishlist_Block_Customer_Sidebar'), - $this->_getRule('getAddToCartUrlBase64', null, '_getAddToCartUrl'), - $this->_getRule('getAllEntityIds', 'Mage_Rss_Model_Resource_Order'), - $this->_getRule('getAllEntityTypeCommentIds', 'Mage_Rss_Model_Resource_Order'), - $this->_getRule('getAllOrderEntityIds', 'Mage_Rss_Model_Resource_Order'), - $this->_getRule('getAllOrderEntityTypeIds', 'Mage_Rss_Model_Resource_Order'), - $this->_getRule('getAnonSuffix'), - $this->_getRule('getAttributesJson', 'Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config', 'getAttributes'), - $this->_getRule('getBaseTaxAmount', 'Mage_Sales_Model_Quote_Item_Abstract'), - $this->_getRule('getCheckoutMehod', 'Mage_Checkout_Model_Type_Onepage'), - $this->_getRule('getChild', null, 'Mage_Core_Block_Abstract::getChildBlock()', 'app'), - $this->_getRule('getChildGroup', null, 'Mage_Core_Block_Abstract::getGroupChildNames()'), - $this->_getRule('getConfig', 'Mage_Eav_Model_Entity_Attribute_Abstract'), - $this->_getRule('getCustomerData', 'Mage_Adminhtml_Block_Sales_Order_Create_Form_Account'), - $this->_getRule('getDataForSave', 'Mage_Wishlist_Model_Item'), - $this->_getRule('getDebug', 'Mage_Ogone_Model_Api'), - $this->_getRule('getDebug', 'Mage_Paypal_Model_Api_Abstract'), - $this->_getRule('getDirectOutput', 'Mage_Core_Model_Layout'), - $this->_getRule('getEntityIdsToIncrementIds', 'Mage_Rss_Model_Resource_Order'), - $this->_getRule('getEntityTypeIdsToTypes', 'Mage_Rss_Model_Resource_Order'), - $this->_getRule('getFacets'), - $this->_getRule('getFallbackTheme'), - $this->_getRule('getFormated', null, 'getFormated(true) -> format(\'html\'), getFormated() -> format(\'text\')'), - $this->_getRule('getFormObject', 'Mage_Adminhtml_Block_Widget_Form'), - $this->_getRule('getGiftmessageHtml', 'Mage_Adminhtml_Block_Sales_Order_View_Tab_Info'), - $this->_getRule('getHtmlFormat', 'Mage_Customer_Model_Address_Abstract'), - $this->_getRule('getIsActiveAanalytics', null, 'getOnsubmitJs'), - $this->_getRule('getIsAjaxRequest', 'Mage_Core_Model_Translate_Inline'), - $this->_getRule('getIsEngineAvailable'), - $this->_getRule('getIsGlobal', 'Mage_Eav_Model_Entity_Attribute_Abstract'), - $this->_getRule('getIsInStock', 'Mage_Checkout_Block_Cart_Item_Renderer'), - $this->_getRule('getItemRender', 'Mage_Checkout_Block_Cart_Abstract'), - $this->_getRule('getJoinFlag', 'Mage_Tag_Model_Resource_Customer_Collection'), - $this->_getRule('getJoinFlag', 'Mage_Tag_Model_Resource_Product_Collection'), - $this->_getRule('getJoinFlag', 'Mage_Tag_Model_Resource_Tag_Collection'), - $this->_getRule('getKeyList', 'Varien_Db_Adapter_Pdo_Mysql'), - $this->_getRule('getLanguages', 'Mage_Install_Block_Begin'), - $this->_getRule('getLayoutFilename', null, 'getFilename'), - $this->_getRule('getLifeTime', 'Mage_Core_Model_Resource_Session'), - $this->_getRule('getLocaleBaseDir', 'Mage_Core_Model_Design_Package'), - $this->_getRule('getMail', 'Mage_Newsletter_Model_Template'), - $this->_getRule('getMaxQueryLenght'), - $this->_getRule('getMenuItemLabel', 'Mage_Admin_Model_Config'), - $this->_getRule('getMergedCssUrl'), - $this->_getRule('getMergedJsUrl'), - $this->_getRule('getMinQueryLenght'), - $this->_getRule('getNeedUsePriceExcludeTax', null, 'Mage_Tax_Model_Config::priceIncludesTax()'), - $this->_getRule('getOneBalanceTotal'), - $this->_getRule('getOrderHtml', 'Mage_GoogleAnalytics_Block_Ga'), - $this->_getRule('getOrderId', 'Mage_Checkout_Block_Onepage_Success'), - $this->_getRule('getOrderId', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('getOriginalHeigh', null, 'getOriginalHeight'), - $this->_getRule('getParentProductIds', 'Mage_Catalog_Model_Resource_Product'), - $this->_getRule('getPriceFormatted', 'Mage_Adminhtml_Block_Customer_Edit_Tab_View_Sales'), - $this->_getRule('getPrices', 'Mage_Bundle_Model_Product_Price'), - $this->_getRule('getPricesDependingOnTax', 'Mage_Bundle_Model_Product_Price'), - $this->_getRule('getPrintUrl', 'Mage_Checkout_Block_Onepage_Success'), - $this->_getRule('getPrintUrl', 'Mage_Sales_Block_Order_Info'), - $this->_getRule('getProductCollection', 'Mage_Wishlist_Helper_Data'), - $this->_getRule('getProductCollection', 'Mage_Wishlist_Model_Wishlist'), - $this->_getRule('getProductsNotInStoreIds'), - $this->_getRule('getProfile', 'Varien_Convert_Container_Abstract'), - $this->_getRule('getQuoteItem', 'Mage_Catalog_Model_Product_Option_Type_Default'), - $this->_getRule('getQuoteItemOption', 'Mage_Catalog_Model_Product_Option_Type_Default'), - $this->_getRule('getQuoteOrdersHtml', 'Mage_GoogleAnalytics_Block_Ga'), - $this->_getRule('getRemoveItemUrl', 'Mage_Wishlist_Block_Customer_Sidebar'), - $this->_getRule('getReorderUrl', 'Mage_Sales_Block_Order_Info'), - $this->_getRule('getRowId', 'Mage_Adminhtml_Block_Sales_Order_Create_Customer_Grid'), - $this->_getRule('getRowId', 'Mage_Adminhtml_Block_Widget_Grid'), - $this->_getRule('getSaveTemplateFlag', 'Mage_Newsletter_Model_Queue'), - $this->_getRule('getSelectionFinalPrice', 'Mage_Bundle_Model_Product_Price'), - $this->_getRule('getSecure', 'Mage_Core_Model_Url', 'isSecure'), - $this->_getRule('getSecure', 'Mage_Backend_Model_Url', 'isSecure'), - $this->_getRule('getShipId', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('getSortedChildren', null, 'getChildNames'), - $this->_getRule('getSortedChildBlocks', null, 'getChildNames() + $this->getLayout()->getBlock($name)'), - $this->_getRule('getStatrupPageUrl'), - $this->_getRule('getStoreButtonsHtml', 'Mage_Backend_Block_System_Config_Tabs'), - $this->_getRule('getStoreCurrency', 'Mage_Sales_Model_Order'), - $this->_getRule('getStoreSelectOptions', 'Mage_Backend_Block_System_Config_Tabs'), - $this->_getRule('getSuggestedZeroDate'), - $this->_getRule('getSuggestionsByQuery'), - $this->_getRule('getSysTmpDir'), - $this->_getRule('getTaxAmount', 'Mage_Sales_Model_Quote_Item_Abstract'), - $this->_getRule('getTaxRatesByProductClass', null, '_getAllRatesByProductClass'), - $this->_getRule('getTemplateFilename', null, 'getFilename'), - $this->_getRule('getTotalModels', 'Mage_Sales_Model_Quote_Address'), - $this->_getRule('getTrackId', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('getTrackingInfoByOrder', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('getTrackingInfoByShip', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('getTrackingInfoByTrackId', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('getTrackingPopUpUrlByOrderId', null, 'getTrackingPopupUrlBySalesModel'), - $this->_getRule('getTrackingPopUpUrlByShipId', null, 'getTrackingPopupUrlBySalesModel'), - $this->_getRule('getTrackingPopUpUrlByTrackId', null, 'getTrackingPopupUrlBySalesModel'), - $this->_getRule('getUseCacheFilename', 'Mage_Core_Model_App'), - $this->_getRule('getValidator', 'Mage_SalesRule_Model_Observer'), - $this->_getRule('getValidatorData', 'Mage_Core_Model_Session_Abstract', 'use _getSessionEnvironment method'), - $this->_getRule('getValueTable'), - $this->_getRule('getViewOrderUrl', 'Mage_Checkout_Block_Onepage_Success'), - $this->_getRule('getWidgetSupportedBlocks', 'Mage_Widget_Model_Widget_Instance'), - $this->_getRule('getWidgetSupportedTemplatesByBlock', 'Mage_Widget_Model_Widget_Instance'), - $this->_getRule('hasItems', 'Mage_Wishlist_Helper_Data'), - $this->_getRule('htmlEscape', null, 'escapeHtml'), - $this->_getRule('imageAction', 'Mage_Catalog_ProductController'), - $this->_getRule('importFromTextArray'), - $this->_getRule('initLabels', 'Mage_Catalog_Model_Resource_Eav_Attribute'), - $this->_getRule('insertProductPrice', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Tierprice'), - $this->_getRule('isAllowedGuestCheckout', 'Mage_Sales_Model_Quote'), - $this->_getRule('isAutomaticCleaningAvailable', 'Varien_Cache_Backend_Eaccelerator'), - $this->_getRule('isCheckoutAvailable', 'Mage_Checkout_Model_Type_Multishipping'), - $this->_getRule('isFulAmountCovered'), - $this->_getRule('isLeyeredNavigationAllowed'), - $this->_getRule('isReadablePopupObject'), - $this->_getRule('isTemplateAllowedForApplication'), - $this->_getRule('loadLabel', 'Mage_Catalog_Model_Resource_Product_Type_Configurable_Attribute'), - $this->_getRule('loadParentProductIds', 'Mage_Catalog_Model_Product'), - $this->_getRule('loadPrices', 'Mage_Catalog_Model_Resource_Product_Type_Configurable_Attribute'), - $this->_getRule('loadProductPrices', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Tierprice'), - $this->_getRule('lockOrderInventoryData', 'Mage_CatalogInventory_Model_Observer'), - $this->_getRule('logEncryptionKeySave'), - $this->_getRule('logInvitationSave'), - $this->_getRule('mergeFiles', 'Mage_Core_Helper_Data'), - $this->_getRule('order_success_page_view', 'Mage_GoogleAnalytics_Model_Observer'), - $this->_getRule('orderedAction', 'Mage_Adminhtml_Report_ProductController'), - $this->_getRule('parseDateTime', 'Mage_Core_Model_Date'), - $this->_getRule('postDispatchMyAccountSave'), - $this->_getRule('postDispatchSystemImportExportRun'), - $this->_getRule('prepareCacheId', 'Mage_Core_Model_App'), - $this->_getRule('prepareGoogleOptimizerScripts'), - $this->_getRule('preprocess', 'Mage_Newsletter_Model_Template'), - $this->_getRule('processBeacon'), - $this->_getRule('processBeforeVoid', 'Mage_Payment_Model_Method_Abstract'), - $this->_getRule('processSubst', 'Mage_Core_Model_Store'), - $this->_getRule('productEventAggregate'), - $this->_getRule('push', 'Mage_Catalog_Model_Product_Image'), - $this->_getRule('rebuildCategoryLevels', 'Mage_Catalog_Model_Resource_Setup'), - $this->_getRule('regenerateSessionId', 'Mage_Core_Model_Session_Abstract'), - $this->_getRule('refundOrderItem', 'Mage_CatalogInventory_Model_Observer'), - $this->_getRule('removeCustomerFromSegments'), - $this->_getRule('revalidateCookie', 'Mage_Core_Model_Session_Abstract_Varien'), - $this->_getRule('sales_order_afterPlace'), - $this->_getRule('sales_quote_address_discount_item'), - $this->_getRule('salesOrderPaymentPlaceEnd'), - $this->_getRule('saveRow__OLD'), - $this->_getRule('saveAction', 'Mage_Tag_CustomerController'), - $this->_getRule('saveSegmentCustomersFromSelect'), - $this->_getRule('send', 'Mage_Newsletter_Model_Template'), - $this->_getRule('sendNewPasswordEmail'), - $this->_getRule('setAnonSuffix'), - $this->_getRule('setAttributeSetExcludeFilter', 'Mage_Eav_Model_Resource_Entity_Attribute_Collection'), - $this->_getRule('setBlockAlias'), - $this->_getRule('setCustomerId', 'Mage_Customer_Model_Resource_Address'), - $this->_getRule('setIsAjaxRequest', 'Mage_Core_Model_Translate_Inline'), - $this->_getRule('setJoinFlag', 'Mage_Tag_Model_Resource_Customer_Collection'), - $this->_getRule('setJoinFlag', 'Mage_Tag_Model_Resource_Product_Collection'), - $this->_getRule('setJoinFlag', 'Mage_Tag_Model_Resource_Tag_Collection'), - $this->_getRule('setOrderId', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('setNeedUsePriceExcludeTax', null, 'Mage_Tax_Model_Config::setPriceIncludesTax()'), - $this->_getRule('setWatermarkHeigth', null, 'setWatermarkHeight'), - $this->_getRule('getWatermarkHeigth', null, 'getWatermarkHeight'), - $this->_getRule('setParentBlock'), - $this->_getRule('setProfile', 'Varien_Convert_Container_Abstract'), - $this->_getRule('setSaveTemplateFlag', 'Mage_Newsletter_Model_Queue'), - $this->_getRule('setShipId', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('setTaxGroupFilter'), - $this->_getRule('setTrackId', 'Mage_Shipping_Block_Tracking_Popup'), - $this->_getRule('shaCrypt', null, 'Mage_Ogone_Model_Api::getHash'), - $this->_getRule('shaCryptValidation', null, 'Mage_Ogone_Model_Api::getHash'), - $this->_getRule('shouldCustomerHaveOneBalance'), - $this->_getRule('shouldShowOneBalance'), - $this->_getRule('sortChildren'), - $this->_getRule('toOptionArray', 'Mage_Cms_Model_Resource_Page_Collection'), - $this->_getRule('toOptionArray', 'Mage_Sendfriend_Model_Sendfriend'), - $this->_getRule('truncate', 'Varien_Db_Adapter_Pdo_Mysql'), - $this->_getRule('unsetBlock'), - $this->_getRule('unsetJoinFlag', 'Mage_Tag_Model_Resource_Customer_Collection'), - $this->_getRule('unsetJoinFlag', 'Mage_Tag_Model_Resource_Product_Collection'), - $this->_getRule('unsetJoinFlag', 'Mage_Tag_Model_Resource_Tag_Collection'), - $this->_getRule('useValidateRemoteAddr', 'Mage_Core_Model_Session_Abstract'), - $this->_getRule('useValidateHttpVia', 'Mage_Core_Model_Session_Abstract'), - $this->_getRule('useValidateHttpXForwardedFor', 'Mage_Core_Model_Session_Abstract'), - $this->_getRule('useValidateHttpUserAgent', 'Mage_Core_Model_Session_Abstract'), - $this->_getRule('updateCofigurableProductOptions', 'Mage_Weee_Model_Observer', 'updateConfigurableProductOptions'), - $this->_getRule('updateTable', 'Mage_Core_Model_Resource_Setup'), - $this->_getRule('urlEscape', null, 'escapeUrl'), - $this->_getRule('validateDataArray', 'Varien_Convert_Container_Abstract'), - $this->_getRule('validateFile', 'Mage_Core_Model_Design_Package'), - $this->_getRule('validateOrder', 'Mage_Checkout_Model_Type_Onepage'), - $this->_getRule('prepareAttributesForSave', 'Mage_ImportExport_Model_Import_Entity_Product'), - $this->_getRule('fetchUpdatesByHandle', 'Mage_Core_Model_Resource_Layout', + array('addWishlistLink', 'Mage_Wishlist_Block_Links'), + array('addWishListSortOrder', 'Mage_Wishlist_Model_Resource_Item_Collection'), + array('aggregate', 'Mage_Tag_Model_Resource_Tag'), + array('aggregate', 'Mage_Tag_Model_Tag'), + array('applyDesign', 'Mage_Catalog_Model_Design'), + array('authAdmin'), + array('authFailed', null, 'Mage_Core_Helper_Http::failHttpAuthentication()'), + array('authFrontend'), + array('authValidate', null, 'Mage_Core_Helper_Http::getHttpAuthCredentials()'), + array('bundlesAction', 'Mage_Adminhtml_Catalog_ProductController'), + array('calcTaxAmount', 'Mage_Sales_Model_Quote_Item_Abstract'), + array('canPrint', 'Mage_Checkout_Block_Onepage_Success'), + array('catalogCategoryChangeProducts', 'Mage_Catalog_Model_Product_Flat_Observer'), + array('catalogEventProductCollectionAfterLoad', 'Mage_GiftMessage_Model_Observer'), + array('catalogProductLoadAfter', 'Mage_Bundle_Model_Observer'), + array('chechAllowedExtension'), + array('checkConfigurableProducts', 'Mage_Eav_Model_Resource_Entity_Attribute_Collection'), + array('checkDatabase', 'Mage_Install_Model_Installer_Db'), + array('checkDateTime', 'Mage_Core_Model_Date'), + array('cleanDbRow', 'Mage_Core_Model_Resource'), + array('cleanVarFolder', null, 'Varien_Io_File::rmdirRecursive()'), + array('cleanVarSubFolders', null, 'glob() on Mage::getBaseDir(Mage_Core_Model_App_Dir::VAR_DIR)'), + array('cloneIndexTable', 'Mage_Index_Model_Resource_Abstract'), + array('convertOldTaxData', 'Mage_Tax_Model_Resource_Setup'), + array('convertOldTreeToNew', 'Mage_Catalog_Model_Resource_Setup'), + array('countChildren', 'Mage_Core_Block_Abstract'), + array('crear'), + array('createDirIfNotExists', null, 'mkdir()'), + array('createOrderItem', 'Mage_CatalogInventory_Model_Observer'), + array('debugRequest', 'Mage_Paypal_Model_Api_Standard'), + array('deleteProductPrices', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Tierprice'), + array('display', 'Varien_Image_Adapter_Abstract', 'getImage()'), + array('displayFullSummary', 'Mage_Tax_Model_Config'), + array('displayTaxColumn', 'Mage_Tax_Model_Config'), + array('displayZeroTax', 'Mage_Tax_Model_Config'), + array('drawItem', 'Mage_Catalog_Block_Navigation'), + array('dropKey', 'Varien_Db_Adapter_Pdo_Mysql'), + array('editAction', 'Mage_Tag_CustomerController'), + array('escapeJs', 'Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config'), + array('exportOrderedCsvAction'), + array('exportOrderedExcelAction'), + array('fetchItemsCount', 'Mage_Wishlist_Model_Resource_Wishlist'), + array('fetchRuleRatesForCustomerTaxClass'), + array('forsedSave'), + array('generateBlocks', null, 'generateElements()'), + array('getAccount', 'Mage_GoogleAnalytics_Block_Ga'), + array('getAclAssert', 'Mage_Admin_Model_Config'), + array('getAclPrivilegeSet', 'Mage_Admin_Model_Config'), + array('getAclResourceList', 'Mage_Admin_Model_Config'), + array('getAclResourceTree', 'Mage_Admin_Model_Config'), + array('getAddNewButtonHtml', 'Mage_Adminhtml_Block_Catalog_Product'), + array('getAddToCartItemUrl', 'Mage_Wishlist_Block_Customer_Sidebar'), + array('getAddToCartUrlBase64', null, '_getAddToCartUrl'), + array('getAllEntityIds', 'Mage_Rss_Model_Resource_Order'), + array('getAllEntityTypeCommentIds', 'Mage_Rss_Model_Resource_Order'), + array('getAllOrderEntityIds', 'Mage_Rss_Model_Resource_Order'), + array('getAllOrderEntityTypeIds', 'Mage_Rss_Model_Resource_Order'), + array('getAnonSuffix'), + array('getAttributesJson', 'Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config', 'getAttributes'), + array('getBaseTaxAmount', 'Mage_Sales_Model_Quote_Item_Abstract'), + array('getCheckoutMehod', 'Mage_Checkout_Model_Type_Onepage'), + array('getChildGroup', null, 'Mage_Core_Block_Abstract::getGroupChildNames()'), + array('getConfig', 'Mage_Eav_Model_Entity_Attribute_Abstract'), + array('getCustomerData', 'Mage_Adminhtml_Block_Sales_Order_Create_Form_Account'), + array('getDataForSave', 'Mage_Wishlist_Model_Item'), + array('getDebug', 'Mage_Ogone_Model_Api'), + array('getDebug', 'Mage_Paypal_Model_Api_Abstract'), + array('getDefaultBasePath', 'Mage_Core_Model_Store'), + array('getDirectOutput', 'Mage_Core_Model_Layout'), + array('getDistroServerVars', 'Mage_Core_Model_Config', 'getDistroBaseUrl'), + array('getEntityIdsToIncrementIds', 'Mage_Rss_Model_Resource_Order'), + array('getEntityTypeIdsToTypes', 'Mage_Rss_Model_Resource_Order'), + array('getFacets'), + array('getFallbackTheme'), + array('getFormated', null, 'getFormated(true) -> format(\'html\'), getFormated() -> format(\'text\')'), + array('getFormObject', 'Mage_Adminhtml_Block_Widget_Form'), + array('getGiftmessageHtml', 'Mage_Adminhtml_Block_Sales_Order_View_Tab_Info'), + array('getHtmlFormat', 'Mage_Customer_Model_Address_Abstract'), + array('getIsActiveAanalytics', null, 'getOnsubmitJs'), + array('getIsAjaxRequest', 'Mage_Core_Model_Translate_Inline'), + array('getIsEngineAvailable'), + array('getIsGlobal', 'Mage_Eav_Model_Entity_Attribute_Abstract'), + array('getIsInStock', 'Mage_Checkout_Block_Cart_Item_Renderer'), + array('getItemRender', 'Mage_Checkout_Block_Cart_Abstract'), + array('getJoinFlag', 'Mage_Tag_Model_Resource_Customer_Collection'), + array('getJoinFlag', 'Mage_Tag_Model_Resource_Product_Collection'), + array('getJoinFlag', 'Mage_Tag_Model_Resource_Tag_Collection'), + array('getKeyList', 'Varien_Db_Adapter_Pdo_Mysql'), + array('getLanguages', 'Mage_Install_Block_Begin'), + array('getLayoutFilename', null, 'getFilename'), + array('getLifeTime', 'Mage_Core_Model_Resource_Session'), + array('getLocaleBaseDir', 'Mage_Core_Model_Design_Package'), + array('getMail', 'Mage_Newsletter_Model_Template'), + array('getMaxQueryLenght'), + array('getMenuItemLabel', 'Mage_Admin_Model_Config'), + array('getMergedCssUrl'), + array('getMergedJsUrl'), + array('getMinQueryLenght'), + array('getNeedUsePriceExcludeTax', null, 'Mage_Tax_Model_Config::priceIncludesTax()'), + array('getOneBalanceTotal'), + array('getOption', 'Mage_Captcha_Helper_Data', 'Mage_Core_Model_Dir::getDir()'), + array('getOptions', 'Mage_Core_Model_Config'), + array('getOrderHtml', 'Mage_GoogleAnalytics_Block_Ga'), + array('getOrderId', 'Mage_Checkout_Block_Onepage_Success'), + array('getOrderId', 'Mage_Shipping_Block_Tracking_Popup'), + array('getOriginalHeigh', null, 'getOriginalHeight'), + array('getParentProductIds', 'Mage_Catalog_Model_Resource_Product'), + array('getPriceFormatted', 'Mage_Adminhtml_Block_Customer_Edit_Tab_View_Sales'), + array('getPrices', 'Mage_Bundle_Model_Product_Price'), + array('getPricesDependingOnTax', 'Mage_Bundle_Model_Product_Price'), + array('getPrintUrl', 'Mage_Checkout_Block_Onepage_Success'), + array('getPrintUrl', 'Mage_Sales_Block_Order_Info'), + array('getProductCollection', 'Mage_Wishlist_Helper_Data'), + array('getProductCollection', 'Mage_Wishlist_Model_Wishlist'), + array('getProductsNotInStoreIds'), + array('getProfile', 'Varien_Convert_Container_Abstract'), + array('getQuoteItem', 'Mage_Catalog_Model_Product_Option_Type_Default'), + array('getQuoteItemOption', 'Mage_Catalog_Model_Product_Option_Type_Default'), + array('getQuoteOrdersHtml', 'Mage_GoogleAnalytics_Block_Ga'), + array('getRemoveItemUrl', 'Mage_Wishlist_Block_Customer_Sidebar'), + array('getReorderUrl', 'Mage_Sales_Block_Order_Info'), + array('getRowId', 'Mage_Adminhtml_Block_Sales_Order_Create_Customer_Grid'), + array('getRowId', 'Mage_Adminhtml_Block_Widget_Grid'), + array('getSaveTemplateFlag', 'Mage_Newsletter_Model_Queue'), + array('getSelectionFinalPrice', 'Mage_Bundle_Model_Product_Price'), + array('getSecure', 'Mage_Core_Model_Url', 'isSecure'), + array('getSecure', 'Mage_Backend_Model_Url', 'isSecure'), + array('getShipId', 'Mage_Shipping_Block_Tracking_Popup'), + array('getSortedChildren', null, 'getChildNames'), + array('getSortedChildBlocks', null, 'getChildNames() + $this->getLayout()->getBlock($name)'), + array('getStatrupPageUrl'), + array('getStoreButtonsHtml', 'Mage_Backend_Block_System_Config_Tabs'), + array('getStoreCurrency', 'Mage_Sales_Model_Order'), + array('getStoreSelectOptions', 'Mage_Backend_Block_System_Config_Tabs'), + array('getSuggestedZeroDate'), + array('getSuggestionsByQuery'), + array('getSysTmpDir'), + array('getTaxAmount', 'Mage_Sales_Model_Quote_Item_Abstract'), + array('getTaxRatesByProductClass', null, '_getAllRatesByProductClass'), + array('getTemplateFilename', null, 'getFilename'), + array('getTempVarDir', 'Mage_Core_Model_Config', 'Mage_Core_Model_Dir::getDir()'), + array('getTotalModels', 'Mage_Sales_Model_Quote_Address'), + array('getTrackId', 'Mage_Shipping_Block_Tracking_Popup'), + array('getTrackingInfoByOrder', 'Mage_Shipping_Block_Tracking_Popup'), + array('getTrackingInfoByShip', 'Mage_Shipping_Block_Tracking_Popup'), + array('getTrackingInfoByTrackId', 'Mage_Shipping_Block_Tracking_Popup'), + array('getTrackingPopUpUrlByOrderId', null, 'getTrackingPopupUrlBySalesModel'), + array('getTrackingPopUpUrlByShipId', null, 'getTrackingPopupUrlBySalesModel'), + array('getTrackingPopUpUrlByTrackId', null, 'getTrackingPopupUrlBySalesModel'), + array('getUseCacheFilename', 'Mage_Core_Model_App'), + array('getValidator', 'Mage_SalesRule_Model_Observer'), + array('getValidatorData', 'Mage_Core_Model_Session_Abstract', 'use _getSessionEnvironment method'), + array('getValueTable'), + array('getVarDir', 'Mage_Core_Model_Config', 'Mage_Core_Model_Dir::getDir()'), + array('getViewOrderUrl', 'Mage_Checkout_Block_Onepage_Success'), + array('getWidgetSupportedBlocks', 'Mage_Widget_Model_Widget_Instance'), + array('getWidgetSupportedTemplatesByBlock', 'Mage_Widget_Model_Widget_Instance'), + array('hasItems', 'Mage_Wishlist_Helper_Data'), + array('htmlEscape', null, 'escapeHtml'), + array('imageAction', 'Mage_Catalog_ProductController'), + array('importFromTextArray'), + array('initLabels', 'Mage_Catalog_Model_Resource_Eav_Attribute'), + array('insertProductPrice', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Tierprice'), + array('isAllowedGuestCheckout', 'Mage_Sales_Model_Quote'), + array('isAutomaticCleaningAvailable', 'Varien_Cache_Backend_Eaccelerator'), + array('isCheckoutAvailable', 'Mage_Checkout_Model_Type_Multishipping'), + array('isFulAmountCovered'), + array('isLeyeredNavigationAllowed'), + array('isReadablePopupObject'), + array('isTemplateAllowedForApplication'), + array('loadLabel', 'Mage_Catalog_Model_Resource_Product_Type_Configurable_Attribute'), + array('loadParentProductIds', 'Mage_Catalog_Model_Product'), + array('loadPrices', 'Mage_Catalog_Model_Resource_Product_Type_Configurable_Attribute'), + array('loadProductPrices', 'Mage_Catalog_Model_Resource_Product_Attribute_Backend_Tierprice'), + array('lockOrderInventoryData', 'Mage_CatalogInventory_Model_Observer'), + array('logEncryptionKeySave'), + array('logInvitationSave'), + array('mergeFiles', 'Mage_Core_Helper_Data'), + array('order_success_page_view', 'Mage_GoogleAnalytics_Model_Observer'), + array('orderedAction', 'Mage_Adminhtml_Report_ProductController'), + array('parseDateTime', 'Mage_Core_Model_Date'), + array('postDispatchMyAccountSave'), + array('postDispatchSystemImportExportRun'), + array('prepareCacheId', 'Mage_Core_Model_App'), + array('prepareGoogleOptimizerScripts'), + array('preprocess', 'Mage_Newsletter_Model_Template'), + array('processBeacon'), + array('processBeforeVoid', 'Mage_Payment_Model_Method_Abstract'), + array('processSubst', 'Mage_Core_Model_Store'), + array('productEventAggregate'), + array('push', 'Mage_Catalog_Model_Product_Image'), + array('rebuildCategoryLevels', 'Mage_Catalog_Model_Resource_Setup'), + array('regenerateSessionId', 'Mage_Core_Model_Session_Abstract'), + array('refundOrderItem', 'Mage_CatalogInventory_Model_Observer'), + array('renderView', null, 'Mage_Core_Block_Template::_toHtml()'), + array('removeCustomerFromSegments'), + array('revalidateCookie', 'Mage_Core_Model_Session_Abstract_Varien'), + array('sales_order_afterPlace'), + array('sales_quote_address_discount_item'), + array('salesOrderPaymentPlaceEnd'), + array('saveRow__OLD'), + array('saveAction', 'Mage_Tag_CustomerController'), + array('saveSegmentCustomersFromSelect'), + array('send', 'Mage_Newsletter_Model_Template'), + array('sendNewPasswordEmail'), + array('setAnonSuffix'), + array('setAttributeSetExcludeFilter', 'Mage_Eav_Model_Resource_Entity_Attribute_Collection'), + array('setBlockAlias'), + array('setCustomerId', 'Mage_Customer_Model_Resource_Address'), + array('setIsAjaxRequest', 'Mage_Core_Model_Translate_Inline'), + array('setJoinFlag', 'Mage_Tag_Model_Resource_Customer_Collection'), + array('setJoinFlag', 'Mage_Tag_Model_Resource_Product_Collection'), + array('setJoinFlag', 'Mage_Tag_Model_Resource_Tag_Collection'), + array('setOption', 'Mage_Captcha_Helper_Data'), + array('setOrderId', 'Mage_Shipping_Block_Tracking_Popup'), + array('setNeedUsePriceExcludeTax', null, 'Mage_Tax_Model_Config::setPriceIncludesTax()'), + array('setScriptPath', 'Mage_Core_Block_Template'), + array('setVarSubFolders'), + array('setWatermarkHeigth', null, 'setWatermarkHeight'), + array('getWatermarkHeigth', null, 'getWatermarkHeight'), + array('setOptions', 'Mage_Core_Model_Config'), + array('setParentBlock'), + array('setProfile', 'Varien_Convert_Container_Abstract'), + array('setSaveTemplateFlag', 'Mage_Newsletter_Model_Queue'), + array('setScriptPath'), + array('setShipId', 'Mage_Shipping_Block_Tracking_Popup'), + array('setTaxGroupFilter'), + array('setTrackId', 'Mage_Shipping_Block_Tracking_Popup'), + array('shaCrypt', null, 'Mage_Ogone_Model_Api::getHash'), + array('shaCryptValidation', null, 'Mage_Ogone_Model_Api::getHash'), + array('shouldCustomerHaveOneBalance'), + array('shouldShowOneBalance'), + array('substDistroServerVars', 'Mage_Core_Model_Config'), + array('sortChildren'), + array('toOptionArray', 'Mage_Cms_Model_Resource_Page_Collection'), + array('toOptionArray', 'Mage_Sendfriend_Model_Sendfriend'), + array('truncate', 'Varien_Db_Adapter_Pdo_Mysql'), + array('unsetBlock'), + array('unsetJoinFlag', 'Mage_Tag_Model_Resource_Customer_Collection'), + array('unsetJoinFlag', 'Mage_Tag_Model_Resource_Product_Collection'), + array('unsetJoinFlag', 'Mage_Tag_Model_Resource_Tag_Collection'), + array('useValidateRemoteAddr', 'Mage_Core_Model_Session_Abstract'), + array('useValidateHttpVia', 'Mage_Core_Model_Session_Abstract'), + array('useValidateHttpXForwardedFor', 'Mage_Core_Model_Session_Abstract'), + array('useValidateHttpUserAgent', 'Mage_Core_Model_Session_Abstract'), + array('updateCofigurableProductOptions', 'Mage_Weee_Model_Observer', 'updateConfigurableProductOptions'), + array('updateTable', 'Mage_Core_Model_Resource_Setup'), + array('urlEscape', null, 'escapeUrl'), + array('validateDataArray', 'Varien_Convert_Container_Abstract'), + array('validateFile', 'Mage_Core_Model_Design_Package'), + array('validateOrder', 'Mage_Checkout_Model_Type_Onepage'), + array('prepareAttributesForSave', 'Mage_ImportExport_Model_Import_Entity_Product'), + array('fetchUpdatesByHandle', 'Mage_Core_Model_Resource_Layout', 'Mage_Core_Model_Resource_Layout_Update'), - $this->_getRule('getElementClass', 'Mage_Core_Model_Layout_Update'), - $this->_getRule('addUpdate', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('asArray', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('asString', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('addHandle', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('removeHandle', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getHandles', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('addPageHandles', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getPageHandleParents', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('pageHandleExists', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getPageHandles', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getPageHandlesHierarchy', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getPageHandleLabel', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getPageHandleType', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('load', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('asSimplexml', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getFileLayoutUpdatesXml', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getContainers', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), - $this->_getRule('getPostMaxSize', 'Mage_Adminhtml_Block_Media_Uploader', - 'Magento_File_Size::getPostMaxSize()'), - $this->_getRule('getUploadMaxSize', 'Mage_Adminhtml_Block_Media_Uploader', - 'Magento_File_Size::getUploadMaxSize()'), - $this->_getRule('getDataMaxSize'), - $this->_getRule('getDataMaxSizeInBytes', 'Mage_Adminhtml_Block_Media_Uploader', - 'Magento_File_Size::getMaxFileSize()'), - $this->_getRule('_getBytesIniValue', 'Mage_Catalog_Model_Product_Option_Type_File'), - $this->_getRule('_getUploadMaxFilesize', 'Mage_Catalog_Model_Product_Option_Type_File'), - $this->_getRule('_bytesToMbytes', 'Mage_Catalog_Model_Product_Option_Type_File'), - $this->_getRule('getMaxUploadSize', 'Mage_ImportExport_Helper_Data', 'getMaxUploadSizeMessage'), - $this->_getRule('prepareRedirect', 'Mage_Core_Controller_Varien_Exception'), - $this->_getRule('getPostMaxSize', 'Mage_Adminhtml_Block_Media_Uploader', - 'Magento_File_Size::getPostMaxSize()'), - $this->_getRule('getUploadMaxSize', 'Mage_Adminhtml_Block_Media_Uploader', - 'Magento_File_Size::getUploadMaxSize()'), - $this->_getRule('getDataMaxSize'), - $this->_getRule('getDataMaxSizeInBytes', 'Mage_Adminhtml_Block_Media_Uploader', - 'Magento_File_Size::getMaxFileSize()'), - $this->_getRule('_getBytesIniValue', 'Mage_Catalog_Model_Product_Option_Type_File'), - $this->_getRule('_getUploadMaxFilesize', 'Mage_Catalog_Model_Product_Option_Type_File'), - $this->_getRule('_bytesToMbytes', 'Mage_Catalog_Model_Product_Option_Type_File'), - $this->_getRule('getMaxUploadSize', 'Mage_ImportExport_Helper_Data', 'getMaxUploadSizeMessage'), - $this->_getRule('getOptions', 'Mage_Core_Model_Design_Source_Design', + array('getElementClass', 'Mage_Core_Model_Layout_Update'), + array('addUpdate', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('asArray', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('asString', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('addHandle', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('removeHandle', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getHandles', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('addPageHandles', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getPageHandleParents', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('pageHandleExists', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getPageHandles', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getPageHandlesHierarchy', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getPageHandleLabel', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getPageHandleType', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('load', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('asSimplexml', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getFileLayoutUpdatesXml', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getContainers', 'Mage_Core_Model_Layout_Update', 'Mage_Core_Model_Layout_Merge'), + array('getDataMaxSize'), + array('getDataMaxSizeInBytes', 'Mage_Adminhtml_Block_Media_Uploader', 'Magento_File_Size::getMaxFileSize()'), + array('getPostMaxSize', 'Mage_Adminhtml_Block_Media_Uploader', 'Magento_File_Size::getPostMaxSize()'), + array('getUploadMaxSize', 'Mage_Adminhtml_Block_Media_Uploader', 'Magento_File_Size::getUploadMaxSize()'), + array('_getBytesIniValue', 'Mage_Catalog_Model_Product_Option_Type_File'), + array('_getUploadMaxFilesize', 'Mage_Catalog_Model_Product_Option_Type_File'), + array('_bytesToMbytes', 'Mage_Catalog_Model_Product_Option_Type_File'), + array('getMaxUploadSize', 'Mage_ImportExport_Helper_Data', 'getMaxUploadSizeMessage'), + array('prepareRedirect', 'Mage_Core_Controller_Varien_Exception'), + array('getOptions', 'Mage_Core_Model_Design_Source_Design', 'Mage_Core_Model_Theme::getThemeCollectionOptionArray'), - $this->_getRule('getThemeOptions', 'Mage_Core_Model_Design_Source_Design', + array('getThemeOptions', 'Mage_Core_Model_Design_Source_Design', 'Mage_Core_Model_Theme::getThemeCollectionOptionArray'), - $this->_getRule('isThemeCompatible', 'Mage_Core_Model_Design_Package', 'Mage_Core_Model_Theme::isThemeCompatible'), - $this->_getRule('setPackageTheme', 'Mage_Widget_Model_Widget_Instance', 'setThemeId'), - $this->_getRule('getPackageTheme', 'Mage_Widget_Model_Widget_Instance', 'getThemeId'), - $this->_getRule('getPackage', 'Mage_Widget_Model_Widget_Instance'), - $this->_getRule('getTheme', 'Mage_Widget_Model_Widget_Instance'), - $this->_getRule('_parsePackageTheme', 'Mage_Widget_Model_Widget_Instance'), + array('isThemeCompatible', 'Mage_Core_Model_Design_Package', 'Mage_Core_Model_Theme::isThemeCompatible'), + array('setPackageTheme', 'Mage_Widget_Model_Widget_Instance', 'setThemeId'), + array('getPackageTheme', 'Mage_Widget_Model_Widget_Instance', 'getThemeId'), + array('getPackage', 'Mage_Widget_Model_Widget_Instance'), + array('getTheme', 'Mage_Widget_Model_Widget_Instance'), + array('_parsePackageTheme', 'Mage_Widget_Model_Widget_Instance'), + array('isVerbose', 'Magento_Shell'), + array('setVerbose', 'Magento_Shell'), + array('output', 'Magento_Shell'), + array('getHeaderText', 'Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search'), + array('getButtonsHtml', 'Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search'), + array('getHeaderCssClass', 'Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Search'), + array('superGroupGridOnlyAction', 'Mage_Adminhtml_Catalog_ProductController'), ); diff --git a/dev/tests/static/testsuite/Legacy/_files/obsolete_properties.php b/dev/tests/static/testsuite/Legacy/_files/obsolete_properties.php index fae1c41ad0d..d914ac1a508 100644 --- a/dev/tests/static/testsuite/Legacy/_files/obsolete_properties.php +++ b/dev/tests/static/testsuite/Legacy/_files/obsolete_properties.php @@ -1,5 +1,9 @@ <?php /** + * Obsolete class attributes + * + * Format: array(<attribute_name>[, <class_scope> = ''[, <replacement>]]) + * * Magento * * NOTICE OF LICENSE @@ -18,54 +22,60 @@ * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magentocommerce.com for more information. * - * @category tests - * @package static - * @subpackage Legacy * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ return array( - $this->_getRule('_anonSuffix'), - $this->_getRule('_isAnonymous'), - $this->_getRule('decoratedIsFirst', null, 'getDecoratedIsFirst'), - $this->_getRule('decoratedIsEven', null, 'getDecoratedIsEven'), - $this->_getRule('decoratedIsOdd', null, 'getDecoratedIsOdd'), - $this->_getRule('decoratedIsLast', null, 'getDecoratedIsLast'), - $this->_getRule('_alias', 'Mage_Core_Block_Abstract'), - $this->_getRule('_children', 'Mage_Core_Block_Abstract'), - $this->_getRule('_childrenHtmlCache', 'Mage_Core_Block_Abstract'), - $this->_getRule('_childGroups', 'Mage_Core_Block_Abstract'), - $this->_getRule('_canUseLocalModules'), - $this->_getRule('_currencyNameTable'), - $this->_getRule('_combineHistory'), - $this->_getRule('_searchTextFields'), - $this->_getRule('_skipFieldsByModel'), - $this->_getRule('_parent', 'Mage_Core_Block_Abstract'), - $this->_getRule('_parentBlock', 'Mage_Core_Block_Abstract'), - $this->_getRule('_setAttributes', 'Mage_Catalog_Model_Product_Type_Abstract'), - $this->_getRule('_storeFilter', 'Mage_Catalog_Model_Product_Type_Abstract'), - $this->_getRule('_addMinimalPrice', 'Mage_Catalog_Model_Resource_Product_Collection'), - $this->_getRule('_checkedProductsQty', 'Mage_CatalogInventory_Model_Observer'), - $this->_getRule('_baseDirCache', 'Mage_Core_Model_Config'), - $this->_getRule('_customEtcDir', 'Mage_Core_Model_Config'), - $this->_getRule('static', 'Mage_Core_Model_Email_Template_Filter'), - $this->_getRule('_loadDefault', 'Mage_Core_Model_Resource_Store_Collection'), - $this->_getRule('_loadDefault', 'Mage_Core_Model_Resource_Store_Group_Collection'), - $this->_getRule('_loadDefault', 'Mage_Core_Model_Resource_Website_Collection'), - $this->_getRule('_addresses', 'Mage_Customer_Model_Customer'), - $this->_getRule('_currency', 'Mage_GoogleCheckout_Model_Api_Xml_Checkout'), - $this->_getRule('_saveTemplateFlag', 'Mage_Newsletter_Model_Queue'), - $this->_getRule('_ratingOptionTable', 'Mage_Rating_Model_Resource_Rating_Option_Collection'), - $this->_getRule('_entityTypeIdsToTypes'), - $this->_getRule('_entityIdsToIncrementIds'), - $this->_getRule('_isFirstTimeProcessRun', 'Mage_SalesRule_Model_Validator'), - $this->_getRule('_shipTable', 'Mage_Shipping_Model_Resource_Carrier_Tablerate_Collection'), - $this->_getRule('_designProductSettingsApplied'), - $this->_getRule('_order', 'Mage_Checkout_Block_Onepage_Success'), - $this->_getRule('_track_id'), - $this->_getRule('_order_id'), - $this->_getRule('_ship_id'), - $this->_getRule('_sortedChildren'), - $this->_getRule('_sortInstructions'), - $this->_getRule('_config', 'Mage_Core_Model_Design_Package'), + array('_alias', 'Mage_Core_Block_Abstract'), + array('_anonSuffix'), + array('_isAnonymous'), + array('_children', 'Mage_Core_Block_Abstract'), + array('_childrenHtmlCache', 'Mage_Core_Block_Abstract'), + array('_childGroups', 'Mage_Core_Block_Abstract'), + array('_canUseLocalModules'), + array('_config', 'Mage_Core_Model_Design_Package'), + array('_config', 'Mage_Core_Model_Logger', '_dirs'), + array('_configuration', 'Mage_Index_Model_Lock_Storage', '_dirs'), + array('_combineHistory'), + array('_currencyNameTable'), + array('decoratedIsFirst', null, 'getDecoratedIsFirst'), + array('decoratedIsEven', null, 'getDecoratedIsEven'), + array('decoratedIsOdd', null, 'getDecoratedIsOdd'), + array('decoratedIsLast', null, 'getDecoratedIsLast'), + array('_distroServerVars'), + array('_searchTextFields'), + array('_skipFieldsByModel'), + array('_parent', 'Mage_Core_Block_Abstract'), + array('_parentBlock', 'Mage_Core_Block_Abstract'), + array('_setAttributes', 'Mage_Catalog_Model_Product_Type_Abstract'), + array('_storeFilter', 'Mage_Catalog_Model_Product_Type_Abstract'), + array('_addMinimalPrice', 'Mage_Catalog_Model_Resource_Product_Collection'), + array('_checkedProductsQty', 'Mage_CatalogInventory_Model_Observer'), + array('_baseDirCache', 'Mage_Core_Model_Config'), + array('_customEtcDir', 'Mage_Core_Model_Config'), + array('static', 'Mage_Core_Model_Email_Template_Filter'), + array('_loadDefault', 'Mage_Core_Model_Resource_Store_Collection'), + array('_loadDefault', 'Mage_Core_Model_Resource_Store_Group_Collection'), + array('_loadDefault', 'Mage_Core_Model_Resource_Website_Collection'), + array('_addresses', 'Mage_Customer_Model_Customer'), + array('_currency', 'Mage_GoogleCheckout_Model_Api_Xml_Checkout'), + array('_saveTemplateFlag', 'Mage_Newsletter_Model_Queue'), + array('_ratingOptionTable', 'Mage_Rating_Model_Resource_Rating_Option_Collection'), + array('_entityTypeIdsToTypes'), + array('_entityIdsToIncrementIds'), + array('_isFirstTimeProcessRun', 'Mage_SalesRule_Model_Validator'), + array('_shipTable', 'Mage_Shipping_Model_Resource_Carrier_Tablerate_Collection'), + array('_designProductSettingsApplied'), + array('_option', 'Mage_Captcha_Helper_Data', '_dirs'), + array('_options', 'Mage_Core_Model_Config', 'Mage_Core_Model_Dir'), + array('_optionsMapping', null, 'Mage::getBaseDir($nodeKey)'), + array('_order', 'Mage_Checkout_Block_Onepage_Success'), + array('_order_id'), + array('_ship_id'), + array('_sortedChildren'), + array('_sortInstructions'), + array('_substServerVars'), + array('_track_id'), + array('_varSubFolders', null, 'Mage_Core_Model_Dir'), + array('_viewDir', 'Mage_Core_Block_Template', '_dirs'), ); diff --git a/dev/tests/static/testsuite/Legacy/_files/words_core.xml b/dev/tests/static/testsuite/Legacy/_files/words_core.xml index 1042f311ed2..22e6bd4d100 100644 --- a/dev/tests/static/testsuite/Legacy/_files/words_core.xml +++ b/dev/tests/static/testsuite/Legacy/_files/words_core.xml @@ -40,6 +40,9 @@ <word>system/convert/profiles</word> <word>Mage_Adminhtml::gui</word> <word>Mage_Adminhtml::profiles</word> + <word>secure_base_url}}js/</word> + <word>secure_base_url}}skin/</word> + <word>secure_base_url}}media/</word> </words> <whitelist> <item> diff --git a/dev/tests/static/testsuite/Php/Exemplar/CodeStyleTest.php b/dev/tests/static/testsuite/Php/Exemplar/CodeStyleTest.php index d868f37e8e7..32b11a7aa5b 100644 --- a/dev/tests/static/testsuite/Php/Exemplar/CodeStyleTest.php +++ b/dev/tests/static/testsuite/Php/Exemplar/CodeStyleTest.php @@ -35,7 +35,7 @@ class Php_Exemplar_CodeStyleTest extends PHPUnit_Framework_TestCase { /** - * @var Inspection_CodeSniffer_Command + * @var CodingStandard_Tool_CodeSniffer */ protected static $_cmd = null; diff --git a/dev/tests/static/testsuite/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Php/LiveCodeTest.php index 5176569fb7f..02b867447c3 100644 --- a/dev/tests/static/testsuite/Php/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Php/LiveCodeTest.php @@ -100,7 +100,7 @@ class Php_LiveCodeTest extends PHPUnit_Framework_TestCase } $this->assertTrue($copyPasteDetector->run(array(), $blackList), - "PHP Code Mess has found error(s): See detailed report in $reportFile" + "PHP Copy/Paste Detector has found error(s): See detailed report in $reportFile" ); } diff --git a/dev/tests/static/testsuite/Php/_files/blacklist/common.txt b/dev/tests/static/testsuite/Php/_files/blacklist/common.txt index 0002d2b805f..fd9c398bc5a 100644 --- a/dev/tests/static/testsuite/Php/_files/blacklist/common.txt +++ b/dev/tests/static/testsuite/Php/_files/blacklist/common.txt @@ -6,22 +6,13 @@ app/code/core/Mage/Backend/Model/Config.php app/code/core/Mage/Backend/Model/Config/Structure/Converter.php app/code/core/Mage/Backend/Model/Menu/Config.php app/code/core/Mage/Backend/Block/Widget/Grid +app/code/core/Mage/Backend/view app/code/core/Mage/DesignEditor/view app/code/core/Mage/Webapi/view -app/code/core/Mage/Core/data/core_setup/data-upgrade-1.6.0.4-1.6.0.5.php -app/code/core/Mage/Theme/Helper/Data.php -app/code/core/Mage/Theme/Block/Adminhtml/System/Design/Theme/Edit/Tab/General.php app/code/core/Mage/User/view -lib/Magento/Config/Dom.php -lib/Magento/Config/Theme.php -lib/Magento/Data -lib/Magento/Shell.php -lib/Magento/Validator.php dev/tests/integration/testsuite/integrity/modular/TemplateFilesTest.php dev/tests/integration/testsuite/integrity/theme/TemplateFilesTest.php dev/tests/integration/testsuite/Mage/Backend/Block/System/Config/FormStub.php -dev/tests/integration/testsuite/Mage/Core/Block/_files dev/tests/integration/tmp dev/tests/static/testsuite/Php/Exemplar/_files/phpcs/input dev/tests/static/testsuite/Php/Exemplar/_files/phpmd/input -app/code/core/Mage/Backend/view \ No newline at end of file diff --git a/dev/tests/static/testsuite/Php/_files/whitelist/common.txt b/dev/tests/static/testsuite/Php/_files/whitelist/common.txt index 124d474a7c2..339d7620651 100644 --- a/dev/tests/static/testsuite/Php/_files/whitelist/common.txt +++ b/dev/tests/static/testsuite/Php/_files/whitelist/common.txt @@ -19,34 +19,40 @@ app/code/core/Mage/Adminhtml/controllers/Report/ProductController.php app/code/core/Mage/Adminhtml/controllers/UrlrewriteController.php app/code/core/Mage/Backend app/code/core/Mage/Catalog/Block/Product/Configurable +app/code/core/Mage/Catalog/Block/Product/Grouped app/code/core/Mage/Catalog/Model/Resource/Product/Collection app/code/core/Mage/CatalogInventory/Block/Adminhtml/Form/Field/Stock.php -app/code/core/Mage/Core/Block/Abstract.php -app/code/core/Mage/Core/data -app/code/core/Mage/Core/Model/Config.php app/code/core/Mage/Centinel/Model/State/Jcb.php +app/code/core/Mage/Cms/Controller/Router.php +app/code/core/Mage/Core/Block/Abstract.php app/code/core/Mage/Core/Controller/Varien/ActionAbstract.php app/code/core/Mage/Core/Controller/Varien/Action/Factory.php app/code/core/Mage/Core/Controller/Varien/Router/Factory.php +app/code/core/Mage/Core/Controller/Varien/Action/Forward.php +app/code/core/Mage/Core/Controller/Varien/DispatchableInterface.php +app/code/core/Mage/Core/Controller/Varien/Router/Abstract.php +app/code/core/Mage/Core/data +app/code/core/Mage/Core/Model/Config.php app/code/core/Mage/Core/Model/Config/Module.php app/code/core/Mage/Core/Model/Design.php +app/code/core/Mage/Core/Model/Design/Fallback +app/code/core/Mage/Core/Model/Design/Fallback.php +app/code/core/Mage/Core/Model/Design/FallbackInterface.php app/code/core/Mage/Core/Model/Design/Source/Design.php -app/code/core/Mage/Core/Model/ShellAbstract.php +app/code/core/Mage/Core/Model/Dir.php app/code/core/Mage/Core/Model/Layout.php app/code/core/Mage/Core/Model/Layout/Factory.php app/code/core/Mage/Core/Model/Layout/Update.php -app/code/core/Mage/Core/Model/Design/Fallback -app/code/core/Mage/Core/Model/Design/Fallback.php -app/code/core/Mage/Core/Model/Design/FallbackInterface.php +app/code/core/Mage/Core/Model/Layout/Argument app/code/core/Mage/Core/Model/Resource/Setup/Migration.php app/code/core/Mage/Core/Model/Resource/Theme/Collection.php app/code/core/Mage/Core/Model/Resource/Theme.php +app/code/core/Mage/Core/Model/ShellAbstract.php app/code/core/Mage/Core/Model/Theme/Validator.php app/code/core/Mage/Core/Model/Theme.php app/code/core/Mage/Core/sql/core_setup/upgrade-1.6.0.3-1.6.0.4.php app/code/core/Mage/Directory/Model/Currency/DefaultLocator.php app/code/core/Mage/DesignEditor -app/code/core/Mage/Core/Model/Layout/Argument app/code/core/Mage/ImportExport/Model/Import/Entity/CustomerComposite.php app/code/core/Mage/ImportExport/Model/Import/Entity/Product/Option.php app/code/core/Mage/ImportExport/Model/Resource/Customer/Storage.php @@ -56,6 +62,7 @@ app/code/core/Mage/Index/Model/Shell.php app/code/core/Mage/Log/Model/Resource/Helper app/code/core/Mage/Log/Model/Resource/Shell.php app/code/core/Mage/Log/Model/Shell.php +app/code/core/Mage/Page/Helper/Robots.php app/code/core/Mage/Reports/Block/Adminhtml/Customer app/code/core/Mage/Reports/Block/Adminhtml/Product app/code/core/Mage/Reports/Model/Resource/Accounts @@ -65,13 +72,6 @@ app/code/core/Mage/Tag/Block/Adminhtml/Customer/Edit/Tab/Tag.php app/code/core/Mage/Tag/Block/Catalog/Product/Rss/Link.php app/code/core/Mage/Theme app/code/core/Mage/User -app/code/core/Mage/Core/Controller/Varien/Action/Forward.php -app/code/core/Mage/Core/Controller/Varien/DispatchableInterface.php -app/code/core/Mage/Core/Controller/Varien/Router/Abstract.php -app/code/core/Mage/Cms/Controller/Router.php -app/code/core/Mage/DesignEditor/Controller/Varien/Router/Standard.php -app/code/core/Mage/DesignEditor/Helper/Data.php -app/code/core/Mage/Page/Helper/Robots.php app/code/core/Mage/Webapi dev/shell dev/tests/integration diff --git a/dev/tests/unit/framework/Magento/Test/Helper/ObjectManager.php b/dev/tests/unit/framework/Magento/Test/Helper/ObjectManager.php index c6f027fc61c..74b11836bc6 100644 --- a/dev/tests/unit/framework/Magento/Test/Helper/ObjectManager.php +++ b/dev/tests/unit/framework/Magento/Test/Helper/ObjectManager.php @@ -60,6 +60,8 @@ class Magento_Test_Helper_ObjectManager 'storeConfig' => 'Mage_Core_Model_Store_Config', 'frontController' => 'Mage_Core_Controller_Varien_Front', 'helperFactory' => 'Mage_Core_Model_Factory_Helper', + 'dirs' => 'Mage_Core_Model_Dir', + 'logger' => 'Mage_Core_Model_Logger', 'filesystem' => 'Magento_Filesystem', ), self::MODEL_ENTITY => array( diff --git a/dev/tests/unit/testsuite/Mage/Captcha/Helper/DataTest.php b/dev/tests/unit/testsuite/Mage/Captcha/Helper/DataTest.php index 2342464b754..bce1e24d08f 100644 --- a/dev/tests/unit/testsuite/Mage/Captcha/Helper/DataTest.php +++ b/dev/tests/unit/testsuite/Mage/Captcha/Helper/DataTest.php @@ -28,8 +28,39 @@ class Mage_Captcha_Helper_DataTest extends PHPUnit_Framework_TestCase { /** - * Sets up the fixture, for example, opens a network connection. - * This method is called before a test is executed. + * Fixture for testing getFonts() + */ + const FONT_FIXTURE = '<fonts><font_code><label>Label</label><path>path/to/fixture.ttf</path></font_code></fonts>'; + + /** + * Temp dir to act as media dir for the test + * + * @var string + */ + protected $_mediaDir; + + protected function setUp() + { + $this->_mediaDir = TESTS_TEMP_DIR . DIRECTORY_SEPARATOR . 'media'; + if (!is_dir($this->_mediaDir)) { + mkdir($this->_mediaDir, 0777); + } + } + + protected function tearDown() + { + if (is_dir($this->_mediaDir)) { + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + $filesystem->delete($this->_mediaDir); + } + } + + /** + * Return helper to be tested + * + * @param Mage_Core_Model_Store $store + * @param Mage_Core_Model_Config $config + * @return Mage_Captcha_Helper_Data */ protected function _getHelper($store, $config) { @@ -42,13 +73,19 @@ class Mage_Captcha_Helper_DataTest extends PHPUnit_Framework_TestCase $app->expects($this->any()) ->method('getStore') ->will($this->returnValue($store)); + $adapterMock = $this->getMockBuilder('Magento_Filesystem_Adapter_Local') ->getMock(); $adapterMock->expects($this->any()) ->method('isDirectory') ->will($this->returnValue(true)); - $filesystem = new Magento_Filesystem($adapterMock); - return new Mage_Captcha_Helper_Data($app, $config, $filesystem); + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + + $customPaths = array( + Mage_Core_Model_Dir::MEDIA => $this->_mediaDir + ); + $dirs = new Mage_Core_Model_Dir(TESTS_TEMP_DIR, array(), $customPaths); + return new Mage_Captcha_Helper_Data($dirs, $app, $config, $filesystem); } /** @@ -66,11 +103,12 @@ class Mage_Captcha_Helper_DataTest extends PHPUnit_Framework_TestCase ->with('customer/captcha/type') ->will($this->returnValue('zend')); + $objectManager = $this->getMock('Magento_ObjectManager_Zend', array(), array(), '', false); $config = $this->_getConfigStub(); $config->expects($this->once()) ->method('getModelInstance') ->with('Mage_Captcha_Model_Zend') - ->will($this->returnValue(new Mage_Captcha_Model_Zend(array('formId' => 'user_create')))); + ->will($this->returnValue(new Mage_Captcha_Model_Zend($objectManager, array('formId' => 'user_create')))); $helper = $this->_getHelper($store, $config); $this->assertInstanceOf('Mage_Captcha_Model_Zend', $helper->getCaptcha('user_create')); @@ -94,28 +132,16 @@ class Mage_Captcha_Helper_DataTest extends PHPUnit_Framework_TestCase $object->getConfigNode('enable'); } - /** - * @covers Mage_Captcha_Helper_Data::getFonts - */ public function testGetFonts() { - $option = $this->_getOptionStub(); - $option->expects($this->any()) - ->method('getDir') - ->will($this->returnValue(TESTS_TEMP_DIR)); - $config = $this->_getConfigStub(); - $config->expects($this->any()) - ->method('getOptions') - ->will($this->returnValue($option)); - - $object = $this->_getHelper($this->_getStoreStub(), $config); + $object = $this->_getHelper($this->_getStoreStub(), $this->_getConfigStub()); $fonts = $object->getFonts(); - - $this->assertEquals($fonts['linlibertine']['label'], 'LinLibertine'); - $this->assertEquals( - $fonts['linlibertine']['path'], - TESTS_TEMP_DIR . DIRECTORY_SEPARATOR . 'lib/LinLibertineFont/LinLibertine_Bd-2.8.1.ttf' - ); + $this->assertArrayHasKey('font_code', $fonts); // fixture + $this->assertArrayHasKey('label', $fonts['font_code']); + $this->assertArrayHasKey('path', $fonts['font_code']); + $this->assertEquals('Label', $fonts['font_code']['label']); + $this->assertStringStartsWith(TESTS_TEMP_DIR, $fonts['font_code']['path']); + $this->assertStringEndsWith('path/to/fixture.ttf', $fonts['font_code']['path']); } /** @@ -124,22 +150,13 @@ class Mage_Captcha_Helper_DataTest extends PHPUnit_Framework_TestCase */ public function testGetImgDir() { - $captchaTmpDir = TESTS_TEMP_DIR . DIRECTORY_SEPARATOR . 'captcha'; - $option = $this->_getOptionStub(); - $option->expects($this->once()) - ->method('getDir') - ->will($this->returnValue($captchaTmpDir)); - $config = $this->_getConfigStub(); - $config->expects($this->any()) - ->method('getOptions') - ->will($this->returnValue($option)); - - $object = $this->_getHelper($this->_getStoreStub(), $config); - $this->assertEquals( - $object->getImgDir(), - Magento_Filesystem::getPathFromArray(array($captchaTmpDir, 'captcha', 'base')) - . Magento_Filesystem::DIRECTORY_SEPARATOR - ); + $object = $this->_getHelper($this->_getStoreStub(), $this->_getConfigStub()); + $this->assertFileNotExists(TESTS_TEMP_DIR . '/captcha'); + $result = $object->getImgDir(); + $result = str_replace('/', DIRECTORY_SEPARATOR, $result); + $this->assertFileExists($result); + $this->assertStringStartsWith(TESTS_TEMP_DIR, $result); + $this->assertStringEndsWith('captcha' . DIRECTORY_SEPARATOR . 'base' . DIRECTORY_SEPARATOR, $result); } /** @@ -161,33 +178,16 @@ class Mage_Captcha_Helper_DataTest extends PHPUnit_Framework_TestCase { $config = $this->getMock( 'Mage_Core_Model_Config', - array('getNode', 'getModelInstance', 'getOptions'), + array('getNode', 'getModelInstance'), array(), '', false ); $config->expects($this->any()) ->method('getNode') - ->will($this->returnValue( - new SimpleXMLElement('<fonts><linlibertine><label>LinLibertine</label>' - . '<path>lib/LinLibertineFont/LinLibertine_Bd-2.8.1.ttf</path></linlibertine></fonts>'))); + ->will($this->returnValue(new SimpleXMLElement(self::FONT_FIXTURE))); return $config; } - /** - * Create option stub - * - * @return Mage_Core_Model_Config_Options - */ - protected function _getOptionStub() - { - $option = $this->getMock( - 'Mage_Core_Model_Config_Options', - array('getDir'), - array(), '', false - ); - return $option; - } - /** * Create Website Stub * diff --git a/dev/tests/unit/testsuite/Mage/Captcha/Model/ZendTest.php b/dev/tests/unit/testsuite/Mage/Captcha/Model/ZendTest.php index 009d906738b..7bf7e81c9de 100644 --- a/dev/tests/unit/testsuite/Mage/Captcha/Model/ZendTest.php +++ b/dev/tests/unit/testsuite/Mage/Captcha/Model/ZendTest.php @@ -67,16 +67,27 @@ class Mage_Captcha_Model_ZendTest extends PHPUnit_Framework_TestCase */ protected $_object; + /** + * @var Magento_ObjectManager_Zend + */ + protected $_objectManager; + /** * Sets up the fixture, for example, opens a network connection. * This method is called before a test is executed. */ protected function setUp() { + $this->_objectManager = $this->getMock('Magento_ObjectManager_Zend', array('get'), array(), '', false); + $this->_objectManager->expects($this->any()) + ->method('get') + ->with('Mage_Captcha_Helper_Data') + ->will($this->returnValue($this->_getHelperStub())); + $this->_object = new Mage_Captcha_Model_Zend( + $this->_objectManager, array( 'formId' => 'user_create', - 'helper' => $this->_getHelperStub(), 'session' => $this->_getSessionStub() ) ); @@ -169,9 +180,9 @@ class Mage_Captcha_Model_ZendTest extends PHPUnit_Framework_TestCase $resourceModel = $this->_getResourceModelStub(); $captcha = new Mage_Captcha_Model_Zend( + $this->_objectManager, array( 'formId' => 'user_create', - 'helper' => $this->_getHelperStub(), 'session' => $this->_getSessionStub(), 'resourceModel' => $resourceModel, ) diff --git a/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php b/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php index fef92dcda2d..1b926a9463b 100644 --- a/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php +++ b/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Attribute/Backend/MediaTest.php @@ -39,8 +39,12 @@ class Mage_Catalog_Model_Product_Attribute_Backend_MediaTest extends PHPUnit_Fra ->method('getMainTable') ->will($this->returnValue('table')); + $mediaConfig = $this->getMock('Mage_Catalog_Model_Product_Media_Config', array(), array(), '', false); + $dirs = $this->getMock('Mage_Core_Model_Dir', array(), array(), '', false); $filesystem = $this->getMockBuilder('Magento_Filesystem')->disableOriginalConstructor()->getMock(); $this->_model = new Mage_Catalog_Model_Product_Attribute_Backend_Media( + $mediaConfig, + $dirs, $filesystem, array('resourceModel' => $resource) ); diff --git a/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Type/ConfigurableTest.php b/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Type/ConfigurableTest.php index 6bbe7a3a2c5..32c82982cb9 100644 --- a/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Type/ConfigurableTest.php +++ b/dev/tests/unit/testsuite/Mage/Catalog/Model/Product/Type/ConfigurableTest.php @@ -38,8 +38,8 @@ class Mage_Catalog_Model_Product_Type_ConfigurableTest extends PHPUnit_Framework $this->_model = new Mage_Catalog_Model_Product_Type_Configurable($filesystem); } - public function testHasWeightFalse() + public function testHasWeightTrue() { - $this->assertFalse($this->_model->hasWeight(), 'This product has weight, but it should not'); + $this->assertTrue($this->_model->hasWeight(), 'This product has not weight, but it should'); } } diff --git a/dev/tests/unit/testsuite/Mage/Core/Block/AbstractTest.php b/dev/tests/unit/testsuite/Mage/Core/Block/AbstractTest.php index 015ca69670b..dd938996bf0 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Block/AbstractTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Block/AbstractTest.php @@ -31,13 +31,12 @@ class Mage_Core_Block_AbstractTest extends PHPUnit_Framework_TestCase * @param string $expectedResult * @param string $nameInLayout * @param array $methodArguments - * @dataProvider dataGetUiId + * @dataProvider getUiIdDataProvider */ public function testGetUiId($expectedResult, $nameInLayout, $methodArguments) { - /** @var $block Mage_Core_Block_Abstract */ - $block = $this->getMockForAbstractClass('Mage_Core_Block_Abstract', - array(), '', false); + /** @var $block Mage_Core_Block_Abstract|PHPUnit_Framework_MockObject_MockObject */ + $block = $this->getMockForAbstractClass('Mage_Core_Block_Abstract', array(), '', false); $block->setNameInLayout($nameInLayout); $this->assertEquals( @@ -46,7 +45,10 @@ class Mage_Core_Block_AbstractTest extends PHPUnit_Framework_TestCase ); } - public static function dataGetUiId() + /** + * @return array + */ + public function getUiIdDataProvider() { return array( array(' data-ui-id="" ', null, array()), @@ -67,4 +69,32 @@ class Mage_Core_Block_AbstractTest extends PHPUnit_Framework_TestCase ), ); } + + public function testGetVar() + { + $filesystemMock = $this->getMock('Magento_Filesystem', array(), array(), '', false); + $design = $this->getMock('Mage_Core_Model_Design_Package', array('getViewConfig'), array($filesystemMock)); + /** @var $block Mage_Core_Block_Abstract|PHPUnit_Framework_MockObject_MockObject */ + $block = $this->getMockForAbstractClass('Mage_Core_Block_Abstract', array( + $this->getMock('Mage_Core_Controller_Request_Http'), + $this->getMock('Mage_Core_Model_Layout', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Event_Manager'), + $this->getMock('Mage_Core_Model_Url'), + $this->getMock('Mage_Core_Model_Translate', array(), array($design)), + $this->getMock('Mage_Core_Model_Cache', array(), array(), '', false), + $design, + $this->getMock('Mage_Core_Model_Session'), + $this->getMock('Mage_Core_Model_Store_Config'), + $this->getMock('Mage_Core_Controller_Varien_Front', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Factory_Helper'), + ), uniqid('Mage_Core_Block_Abstract_')); + $config = $this->getMock('Magento_Config_View', array('getVarValue'), array(), '', false); + $design->expects($this->exactly(2))->method('getViewConfig')->will($this->returnValue($config)); + $module = uniqid(); + $config->expects($this->at(0))->method('getVarValue')->with('Mage_Core', 'v1')->will($this->returnValue('one')); + $config->expects($this->at(1))->method('getVarValue')->with($module, 'v2')->will($this->returnValue('two')); + + $this->assertEquals('one', $block->getVar('v1')); + $this->assertEquals('two', $block->getVar('v2', $module)); + } } diff --git a/dev/tests/unit/testsuite/Mage/Core/Block/TemplateTest.php b/dev/tests/unit/testsuite/Mage/Core/Block/TemplateTest.php new file mode 100644 index 00000000000..c247e195aa1 --- /dev/null +++ b/dev/tests/unit/testsuite/Mage/Core/Block/TemplateTest.php @@ -0,0 +1,104 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category Magento + * @package Mage_Core + * @subpackage unit_tests + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Core_Block_TemplateTest extends PHPUnit_Framework_TestCase +{ + public function testGetTemplateFile() + { + $design = $this->getMock('Mage_Core_Model_Design_Package', array('getFilename'), array(), '', false); + $template = 'fixture'; + $area = 'areaFixture'; + $block = new Mage_Core_Block_Template( + $this->getMock('Mage_Core_Controller_Request_Http'), + $this->getMock('Mage_Core_Model_Layout', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Event_Manager'), + $this->getMock('Mage_Core_Model_Url'), + $this->getMock('Mage_Core_Model_Translate', array(), array($design)), + $this->getMock('Mage_Core_Model_Cache', array(), array(), '', false), + $design, + $this->getMock('Mage_Core_Model_Session'), + $this->getMock('Mage_Core_Model_Store_Config'), + $this->getMock('Mage_Core_Controller_Varien_Front', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Factory_Helper'), + $this->getMock('Mage_Core_Model_Dir', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Logger', array(), array(), '', false), + $this->getMock('Magento_Filesystem', array(), array(), '', false), + array('template' => $template, 'area' => $area) + ); + + $params = array('module' => 'Mage_Core', 'area' => $area); + $design->expects($this->once())->method('getFilename')->with($template, $params); + $block->getTemplateFile(); + } + + /** + * @param string $filename + * @param string $expectedOutput + * @dataProvider fetchViewDataProvider + */ + public function testFetchView($filename, $expectedOutput) + { + $layout = $this->getMock('Mage_Core_Model_Layout', array('isDirectOutput'), array(), '', false); + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); + $design = $this->getMock('Mage_Core_Model_Design_Package', array(), array($filesystem)); + $block = $this->getMock('Mage_Core_Block_Template', array('getShowTemplateHints'), array( + $this->getMock('Mage_Core_Controller_Request_Http'), + $layout, + $this->getMock('Mage_Core_Model_Event_Manager'), + $this->getMock('Mage_Core_Model_Url'), + $this->getMock('Mage_Core_Model_Translate', array(), array($design)), + $this->getMock('Mage_Core_Model_Cache', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Design_Package', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Session'), + $this->getMock('Mage_Core_Model_Store_Config'), + $this->getMock('Mage_Core_Controller_Varien_Front', array(), array(), '', false), + $this->getMock('Mage_Core_Model_Factory_Helper'), + new Mage_Core_Model_Dir( + __DIR__ . '/_files', + array(Mage_Core_Model_Dir::APP => ''), + array(Mage_Core_Model_Dir::APP => __DIR__) + ), + $this->getMock('Mage_Core_Model_Logger', array('log'), array(), '', false), + $filesystem + )); + $layout->expects($this->once())->method('isDirectOutput')->will($this->returnValue(false)); + + $this->assertSame($block, $block->assign(array('varOne' => 'value1', 'varTwo' => 'value2'))); + $this->assertEquals($expectedOutput, $block->fetchView(__DIR__ . "/_files/{$filename}")); + } + + /** + * @return array + */ + public function fetchViewDataProvider() + { + return array( + array('template_test_assign.phtml', 'value1, value2'), + array('invalid_file', ''), + ); + } +} diff --git a/dev/tests/integration/testsuite/Mage/Core/Block/_files/template_test_assign.phtml b/dev/tests/unit/testsuite/Mage/Core/Block/_files/template_test_assign.phtml similarity index 96% rename from dev/tests/integration/testsuite/Mage/Core/Block/_files/template_test_assign.phtml rename to dev/tests/unit/testsuite/Mage/Core/Block/_files/template_test_assign.phtml index c64f82e2a48..456da5eede2 100644 --- a/dev/tests/integration/testsuite/Mage/Core/Block/_files/template_test_assign.phtml +++ b/dev/tests/unit/testsuite/Mage/Core/Block/_files/template_test_assign.phtml @@ -25,4 +25,5 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -<?php echo $varOne . ', ' . $varTwo ?> +<?php +echo $varOne . ', ' . $varTwo; diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/App/OptionsTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/App/OptionsTest.php deleted file mode 100644 index 5a04e56fa3c..00000000000 --- a/dev/tests/unit/testsuite/Mage/Core/Model/App/OptionsTest.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Mage_Core - * @subpackage unit_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -class Mage_Core_Model_App_OptionsTest extends PHPUnit_Framework_TestCase -{ - public function testGetRunCode() - { - $model = new Mage_Core_Model_App_Options(array()); - $this->assertEmpty($model->getRunCode()); - - $model = new Mage_Core_Model_App_Options(array(Mage_Core_Model_App_Options::OPTION_APP_RUN_CODE => 'test')); - $this->assertEquals('test', $model->getRunCode()); - } - - public function testGetRunType() - { - $model = new Mage_Core_Model_App_Options(array()); - $this->assertEquals(Mage_Core_Model_App_Options::APP_RUN_TYPE_STORE, $model->getRunType()); - - $runType = Mage_Core_Model_App_Options::APP_RUN_TYPE_WEBSITE; - $model = new Mage_Core_Model_App_Options(array(Mage_Core_Model_App_Options::OPTION_APP_RUN_TYPE => $runType)); - $this->assertEquals($runType, $model->getRunType()); - } - - /** - * @expectedException InvalidArgumentException - * @expectedExceptionMessage run type "invalid" is not recognized, supported values: "store", "group", "website" - */ - public function testGetRunTypeException() - { - new Mage_Core_Model_App_Options(array(Mage_Core_Model_App_Options::OPTION_APP_RUN_TYPE => 'invalid')); - } - - public function testGetRunOptions() - { - $model = new Mage_Core_Model_App_Options(array('ignored_option' => 'ignored value')); - $this->assertEmpty($model->getRunOptions()); - - $extraLocalConfigFile = 'test/local.xml'; - $inputOptions = array(Mage_Core_Model_App_Options::OPTION_LOCAL_CONFIG_EXTRA_FILE => $extraLocalConfigFile); - $expectedRunOptions = array(Mage_Core_Model_Config::OPTION_LOCAL_CONFIG_EXTRA_FILE => $extraLocalConfigFile); - $model = new Mage_Core_Model_App_Options($inputOptions); - $this->assertEquals($expectedRunOptions, $model->getRunOptions()); - } -} diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/AppTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/AppTest.php index 02eeca38643..6119e5324ad 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Model/AppTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Model/AppTest.php @@ -30,13 +30,8 @@ */ class Mage_Core_Model_AppTest extends PHPUnit_Framework_TestCase { - /* - * Test layout class instance - */ - const LAYOUT_INSTANCE = 'TestLayoutInstance'; - /** - * @var Mage_Core_Model_App + * @var Mage_Core_Model_App|PHPUnit_Framework_MockObject_MockObject */ protected $_model; @@ -45,20 +40,64 @@ class Mage_Core_Model_AppTest extends PHPUnit_Framework_TestCase */ protected $_objectManager; - public function setUp() + protected function setUp() { $frontController = $this->getMock('Mage_Core_Controller_Varien_Front', array(), array(), '', false); - $this->_objectManager = $this->getMock('Magento_ObjectManager_Zend', array('get'), array(), '', false); - $this->_model = new Mage_Core_Model_App($frontController, $this->_objectManager); + + $this->_objectManager = new Magento_ObjectManager_Zend(); + $dirs = new Mage_Core_Model_Dir(__DIR__, array(), array(Mage_Core_Model_Dir::CONFIG => __DIR__)); + $this->_objectManager->addSharedInstance($dirs, 'Mage_Core_Model_Dir'); + + $this->_model = $this->getMock( + 'Mage_Core_Model_App', + array('_initEnvironment', '_initFilesystem', '_initLogger', '_initCache'), + array($frontController, $this->_objectManager) + ); + $this->_objectManager->addSharedInstance($this->_model, 'Mage_Core_Model_App'); + } + + protected function tearDown() + { + $this->_model = null; + $this->_objectManager = null; + } + + public function testIsInstalledFalse() + { + $this->_model->baseInit(array( + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA + => sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'invalid') + )); + $this->assertFalse($this->_model->isInstalled()); + } + + public function testIsInstalledTrue() + { + $this->_model->baseInit(array( + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA + => sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'Fri, 28 Dec 2012 11:29:51 -0800') + )); + $this->assertTrue($this->_model->isInstalled()); + } + + /** + * @expectedException Magento_Exception + * @expectedExceptionMessage Application is not installed yet, please complete the installation first. + */ + public function testRequireInstalledInstance() + { + $this->_model->baseInit(array( + Mage_Core_Model_Config::INIT_OPTION_EXTRA_DATA + => sprintf(Mage_Core_Model_Config::CONFIG_TEMPLATE_INSTALL_DATE, 'invalid') + )); + $this->_model->requireInstalledInstance(); } public function testGetLayout() { - $this->_objectManager->expects($this->once()) - ->method('get') - ->with('Mage_Core_Model_Layout') - ->will($this->returnValue(self::LAYOUT_INSTANCE)); + $layout = $this->getMock('Mage_Core_Model_Layout', array(), array(), '', false); + $this->_objectManager->addSharedInstance($layout, 'Mage_Core_Model_Layout'); - $this->assertEquals(self::LAYOUT_INSTANCE, $this->_model->getLayout()); + $this->assertEquals($layout, $this->_model->getLayout()); } } diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/CacheTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/CacheTest.php index 4f0bc940d7c..60b4a3afb3c 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Model/CacheTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Model/CacheTest.php @@ -27,15 +27,25 @@ class Mage_Core_Model_CacheTest extends PHPUnit_Framework_TestCase { + /** + * @var Mage_Core_Model_Dir + */ + protected static $_dirs; + /** * @var Mage_Core_Model_Cache */ protected $_model; /** - * @var Mage_Core_Model_Config + * @var Mage_Core_Model_App|PHPUnit_Framework_MockObject_MockObject + */ + protected $_app; + + /** + * @var Magento_ObjectManager_Zend|PHPUnit_Framework_MockObject_MockObject */ - protected $_config; + protected $_objectManager; /** * @var Mage_Core_Helper_Abstract @@ -52,64 +62,109 @@ class Mage_Core_Model_CacheTest extends PHPUnit_Framework_TestCase */ protected $_requestProcessor; - public function setUp() + public static function setUpBeforeClass() + { + self::$_dirs = new Mage_Core_Model_Dir(TESTS_TEMP_DIR); + mkdir(self::$_dirs->getDir(Mage_Core_Model_Dir::CACHE), 0777, true); + } + + public static function tearDownAfterClass() + { + self::$_dirs = null; + } + + protected function setUp() { - $objectManagerMock = $this->getMock('Magento_ObjectManager_Zend', array('create', 'get'), array(), '', false); - $objectManagerMock->expects($this->any()) + $this->_prepareApp('global_ban_use_cache', false); + $this->_objectManager = $this->getMock( + 'Magento_ObjectManager_Zend', array('create', 'get'), array(), '', false + ); + $this->_objectManager->expects($this->any()) ->method('create') ->will($this->returnCallback(array($this, 'getInstance'))); + $this->_objectManager->expects($this->any()) + ->method('get') + ->will($this->returnCallback(array($this, 'getObject'))); - $this->_config = new Mage_Core_Model_Config($objectManagerMock, <<<XML - <config> - <global> - <cache> - <types> - <single_tag> - <label>Tag One</label> - <description>This is Tag One</description> - <tags>tag_one</tags> - </single_tag> - <multiple_tags> - <label>Tags One and Two</label> - <description>These are Tags One and Two</description> - <tags>tag_one,tag_two</tags> - </multiple_tags> - </types> - </cache> - </global> - </config> -XML - ); $this->_helper = $this->getMock('Mage_Core_Helper_Data', array('__')); $this->_helper ->expects($this->any()) ->method('__') ->will($this->returnArgument(0)) ; - $this->_config->setOptions(array( - 'cache_dir' => __DIR__, - 'etc_dir' => __DIR__, - )); $this->_cacheFrontend = $this->getMock( 'Zend_Cache_Core', array('load', 'test', 'save', 'remove', 'clean', '_getHelper') ); $this->_requestProcessor = $this->getMock('stdClass', array('extractContent')); - $this->_model = new Mage_Core_Model_Cache(array( - 'config' => $this->_config, - 'helper' => $this->_helper, - 'frontend' => $this->_cacheFrontend, - 'backend' => 'BlackHole', - 'request_processors' => array($this->_requestProcessor), + $this->_model = new Mage_Core_Model_Cache( + $this->_objectManager, + array( + 'helper' => $this->_helper, + 'frontend' => $this->_cacheFrontend, + 'backend' => 'BlackHole', + 'request_processors' => array($this->_requestProcessor), )); } - public function tearDown() + protected function tearDown() { - $this->_config = null; + $this->_objectManager = null; $this->_cacheFrontend = null; $this->_model = null; } + /** + * Create application mock + * + * @param string $initParam + * @param mixed $initValue + */ + protected function _prepareApp($initParam, $initValue) + { + $this->_app = $this->getMock('Mage_Core_Model_App', array('getInitParam'), array(), '', false); + $this->_app->expects($this->any()) + ->method('getInitParam') + ->with($initParam) + ->will($this->returnValue($initValue)); + } + + /** + * Callback for getter of the object manager + * + * @param string $className + * @return object|null|PHPUnit_Framework_MockObject_MockObject + */ + public function getObject($className) + { + switch ($className) { + case 'Mage_Core_Model_Config': + return new Mage_Core_Model_Config($this->_objectManager, <<<XML + <config> + <global> + <cache> + <types> + <single_tag> + <label>Tag One</label> + <description>This is Tag One</description> + <tags>tag_one</tags> + </single_tag> + <multiple_tags> + <label>Tags One and Two</label> + <description>These are Tags One and Two</description> + <tags>tag_one,tag_two</tags> + </multiple_tags> + </types> + </cache> + </global> + </config> +XML + ); + case 'Mage_Core_Model_App': return $this->_app; + case 'Mage_Core_Model_Dir': return self::$_dirs; + default: return null; + } + } + /** * Force to load desired cache type options * @@ -132,8 +187,8 @@ XML */ public function testConstructor(array $options, $expectedBackendClass) { - $options += array('config' => $this->_config, 'helper' => $this->_helper); - $model = new Mage_Core_Model_Cache($options); + $options += array('helper' => $this->_helper); + $model = new Mage_Core_Model_Cache($this->_objectManager, $options); $backend = $model->getFrontend()->getBackend(); $this->assertInstanceOf($expectedBackendClass, $backend); @@ -209,8 +264,7 @@ XML public function testSaveDisallowed() { - $model = new Mage_Core_Model_Cache(array( - 'config' => $this->_config, + $model = new Mage_Core_Model_Cache($this->_objectManager, array( 'helper' => $this->_helper, 'frontend' => $this->_cacheFrontend, 'backend' => 'BlackHole', @@ -312,6 +366,15 @@ XML return $this->_model; } + public function testCanUseBanCache() + { + $this->_prepareApp('global_ban_use_cache', true); + $this->_emulateCacheTypeOptions(); + $this->assertEquals(array('config' => false), $this->_model->canUse('')); + $this->assertFalse($this->_model->canUse('config')); + return $this->_model; + } + /** * @depends testCanUse * @param Mage_Core_Model_Cache $model @@ -436,8 +499,7 @@ XML public function testProcessRequestFalse() { $response = new Zend_Controller_Response_Http(); - $this->_model = new Mage_Core_Model_Cache(array( - 'config' => $this->_config, + $this->_model = new Mage_Core_Model_Cache($this->_objectManager, array( 'helper' => $this->_helper, 'frontend' => $this->_cacheFrontend, 'backend' => 'BlackHole', diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/Config/OptionsTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/Config/OptionsTest.php deleted file mode 100644 index 62b07ed2f83..00000000000 --- a/dev/tests/unit/testsuite/Mage/Core/Model/Config/OptionsTest.php +++ /dev/null @@ -1,114 +0,0 @@ -<?php -/** - * Magento - * - * NOTICE OF LICENSE - * - * This source file is subject to the Open Software License (OSL 3.0) - * that is bundled with this package in the file LICENSE.txt. - * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/osl-3.0.php - * If you did not receive a copy of the license and are unable to - * obtain it through the world-wide-web, please send an email - * to license@magentocommerce.com so we can send you a copy immediately. - * - * DISCLAIMER - * - * Do not edit or add to this file if you wish to upgrade Magento to newer - * versions in the future. If you wish to customize Magento for your - * needs please refer to http://www.magentocommerce.com for more information. - * - * @category Magento - * @package Mage_Core - * @subpackage unit_tests - * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - */ - -class Mage_Core_Model_Config_OptionsTest extends PHPUnit_Framework_TestCase -{ - /** - * @var Mage_Core_Model_Config_Options - */ - protected $_model; - - /** - * @var array - */ - protected $_sourceData; - - /** - * @var array - */ - protected $_varDir; - - protected function setUp() - { - $ioModel = $this->getMock('Varien_Io_File', array('checkAndCreateFolder')); - $this->_sourceData = array( - 'app_dir' => __DIR__ . DIRECTORY_SEPARATOR . 'app', - 'io' => $ioModel, - ); - $this->_varDir = __DIR__ . DIRECTORY_SEPARATOR . 'var'; - } - - public function testGetVarDir() - { - $this->_sourceData['io']->expects($this->once()) - ->method('checkAndCreateFolder') - ->with($this->equalTo($this->_varDir)) - ->will($this->returnValue(true)); - - $this->_model = new Mage_Core_Model_Config_Options($this->_sourceData); - $result = $this->_model->getVarDir(); - $this->assertEquals($this->_varDir, $result); - } - - /** - * @expectedException Mage_Core_Exception - */ - public function testGetVarDirWithException() - { - $this->_sourceData['io']->expects($this->at(0)) - ->method('checkAndCreateFolder') - ->with($this->equalTo($this->_varDir)) - ->will($this->throwException(new Exception)); - $this->_model = new Mage_Core_Model_Config_Options($this->_sourceData); - } - - public function testCreateDirIfNotExists() - { - $checkDir = __DIR__ . DIRECTORY_SEPARATOR . 'test'; - $this->_sourceData['io']->expects($this->at(0)) - ->method('checkAndCreateFolder') - ->with($this->equalTo($this->_varDir)) - ->will($this->returnValue(true)); - - $this->_sourceData['io']->expects($this->at(1)) - ->method('checkAndCreateFolder') - ->with($this->equalTo($checkDir)) - ->will($this->returnValue(true)); - - $this->_model = new Mage_Core_Model_Config_Options($this->_sourceData); - - $result = $this->_model->createDirIfNotExists($checkDir); - $this->assertEquals(true, $result); - } - - public function testCreateDirIfNotExistsNegativeResult() - { - $checkDir = __DIR__ . DIRECTORY_SEPARATOR . 'dirNotExists'; - $this->_sourceData['io']->expects($this->at(0)) - ->method('checkAndCreateFolder') - ->with($this->equalTo($this->_varDir)) - ->will($this->returnValue(true)); - - $this->_sourceData['io']->expects($this->at(1)) - ->method('checkAndCreateFolder') - ->will($this->throwException(new Exception)); - - $this->_model = new Mage_Core_Model_Config_Options($this->_sourceData); - $result = $this->_model->createDirIfNotExists($checkDir); - $this->assertEquals(false, $result); - } -} \ No newline at end of file diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/ConfigTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/ConfigTest.php index 00b88f53a27..cd899c38aaf 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Model/ConfigTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Model/ConfigTest.php @@ -34,23 +34,27 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase /** * @param mixed $data - * @param array $map * @dataProvider constructorDataProvider */ - public function testConstructor($data, $map) + public function testConstructor($data) { //TODO: We should not use mocks in integration tests /** @var Magento_ObjectManager_Zend|PHPUnit_Framework_MockObject_MockObject $objectManagerMock */ $objectManagerMock = $this->getMock('Magento_ObjectManager_Zend', array('create', 'get'), array(), '', false); $objectManagerMock->expects($this->any()) ->method('create') - ->will($this->returnValueMap(array( - $map, - array('Mage_Core_Model_Config_Base', array(), true, new Mage_Core_Model_Config_Base()) - ))); + ->will($this->returnValueMap( + array( + array( + 'Mage_Core_Model_Config_Base', + array(), + true, + new Mage_Core_Model_Config_Base() + ) + ) + )); $this->_model = new Mage_Core_Model_Config($objectManagerMock, $data); - $this->assertInstanceOf('Mage_Core_Model_Config_Options', $this->_model->getOptions()); } /** @@ -61,18 +65,14 @@ class Mage_Core_Model_ConfigTest extends PHPUnit_Framework_TestCase $simpleXml = new Varien_Simplexml_Element('<body></body>'); return array( array( - 'data' => null, - 'map' => array('Mage_Core_Model_Config_Options', array('data' => array(null)), true, - new Mage_Core_Model_Config_Options()) + 'data' => null ), array( - 'data' => array(), - 'map' => array('Mage_Core_Model_Config_Options', array('data' => array()), true, - new Mage_Core_Model_Config_Options()) + 'data' => array() ), - array('data' => $simpleXml, - 'map' => array('Mage_Core_Model_Config_Options', array('data' => array($simpleXml)), true, - new Mage_Core_Model_Config_Options())), + array( + 'data' => $simpleXml + ) ); } } diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/Design/Fallback/CachingProxyTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/Design/Fallback/CachingProxyTest.php index ee88abafba3..2ca8873f2bd 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Model/Design/Fallback/CachingProxyTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Model/Design/Fallback/CachingProxyTest.php @@ -32,14 +32,7 @@ class Mage_Core_Model_Design_Fallback_CachingProxyTest extends PHPUnit_Framework * * @var string */ - protected static $_tmpDir; - - /** - * Base dir as passed to the model - * - * @var string - */ - protected $_baseDir; + protected $_tmpDir; /** * Mock of the model to be tested. Operates the mocked fallback object. @@ -55,170 +48,103 @@ class Mage_Core_Model_Design_Fallback_CachingProxyTest extends PHPUnit_Framework */ protected $_fallback; - /** - * Mocked theme object - * - * @var Mage_Core_Model_Theme - */ - protected $_theme; - - public static function setUpBeforeClass() - { - self::$_tmpDir = TESTS_TEMP_DIR . DIRECTORY_SEPARATOR . 'fallback'; - mkdir(self::$_tmpDir); - } - public function setUp() { - // TODO This test should be either refactored to use mock filesystem or moved to integration - $this->_baseDir = DIRECTORY_SEPARATOR . 'base' . DIRECTORY_SEPARATOR . 'dir'; - - $this->_theme = $this->getMock('Mage_Core_Model_Theme', array(), array(), '', false); - - $params = array( - 'area' => 'frontend', - 'themeModel' => $this->_theme, - 'locale' => 'en_US', - 'appConfig' => false, - 'canSaveMap' => false, - 'mapDir' => self::$_tmpDir, - 'baseDir' => $this->_baseDir - ); - + $this->_tmpDir = TESTS_TEMP_DIR . DIRECTORY_SEPARATOR . 'fallback'; + mkdir($this->_tmpDir); $this->_fallback = $this->getMock( 'Mage_Core_Model_Design_Fallback', - array('getFile', 'getLocaleFile', 'getViewFile'), - array($this->_createFilesystem(), $params) + array('getFile', 'getLocaleFile', 'getViewFile', 'getArea', 'getPackage', 'getTheme', 'getLocale'), + array(), + '', + false + ); + $this->_fallback->expects($this->any())->method('getArea')->will($this->returnValue('a')); + $this->_fallback->expects($this->any())->method('getPackage')->will($this->returnValue('p')); + $this->_fallback->expects($this->any())->method('getTheme')->will($this->returnValue('t')); + $this->_fallback->expects($this->any())->method('getLocale')->will($this->returnValue('l')); + $this->_model = new Mage_Core_Model_Design_Fallback_CachingProxy( + $this->_fallback, $this->_createFilesystem(), $this->_tmpDir, __DIR__, true ); - - $this->_model = $this->getMockBuilder('Mage_Core_Model_Design_Fallback_CachingProxy') - ->setMethods(array('_getFallback')) - ->setConstructorArgs(array($this->_createFilesystem(), $params)) - ->getMock(); - $this->_model->expects($this->any()) - ->method('_getFallback') - ->will($this->returnValue($this->_fallback)); } - /** - * Calls are repeated twice to verify, that fallback is used only once, and next time a proper value is returned - * via cached map. - */ - public function testGetFile() + protected function tearDown() { - $module = 'Some_Module'; - $expected = $this->_baseDir . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'theme_file.ext'; - $expected = str_replace('/', DIRECTORY_SEPARATOR, $expected); - $this->_fallback->expects($this->once()) - ->method('getFile') - ->with('file.ext', $module) - ->will($this->returnValue($expected)); - - $actual = $this->_model->getFile('file.ext', $module); - $this->assertEquals($expected, $actual); - $actual = $this->_model->getFile('file.ext', $module); - $this->assertEquals($expected, $actual); + Varien_Io_File::rmdirRecursive($this->_tmpDir); } /** - * Calls are repeated twice to verify, that fallback is used only once, and next time a proper value is returned - * via cached map. + * @expectedException InvalidArgumentException */ - public function testGetLocaleFile() + public function testConstructInvalidDir() { - $expected = $this->_baseDir . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'locale_file.ext'; - $this->_fallback->expects($this->once()) - ->method('getLocaleFile') - ->with('file.ext') - ->will($this->returnValue($expected)); - - $actual = $this->_model->getLocaleFile('file.ext'); - $this->assertEquals($expected, $actual); - $actual = $this->_model->getLocaleFile('file.ext'); - $this->assertEquals($expected, $actual); + new Mage_Core_Model_Design_Fallback_CachingProxy($this->_fallback, $this->_createFilesystem(), $this->_tmpDir, + __DIR__ . '/invalid_dir'); } - /** - * Calls are repeated twice to verify, that fallback is used only once, and next time a proper value is returned - * via cached map. - */ - public function testGetViewFile() + public function testDestruct() { - $module = 'Some_Module'; - $expected = $this->_baseDir . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'view_file.ext'; $this->_fallback->expects($this->once()) - ->method('getViewFile') - ->with('file.ext', $module) - ->will($this->returnValue($expected)); - - $actual = $this->_model->getViewFile('file.ext', $module); - $this->assertEquals($expected, $actual); - $actual = $this->_model->getViewFile('file.ext', $module); - $this->assertEquals($expected, $actual); + ->method('getFile') + ->will($this->returnValue(__DIR__ . DIRECTORY_SEPARATOR . 'test.txt')); + $suffix = uniqid(); + $model = new Mage_Core_Model_Design_Fallback_CachingProxy( + $this->_fallback, + $this->_createFilesystem(), + $this->_tmpDir . DIRECTORY_SEPARATOR . $suffix, + __DIR__, + true + ); + $expectedFile = $this->_tmpDir . DIRECTORY_SEPARATOR . $suffix . DIRECTORY_SEPARATOR . 'a_t_l.ser'; + $model->getFile('does not matter'); + $this->assertFileNotExists($expectedFile); + unset($model); + $this->assertFileExists($expectedFile); + $contents = unserialize(file_get_contents($expectedFile)); + $this->assertContains('test.txt', $contents); } /** - * Test that proxy caches published skin path, and further calls do not use fallback model + * @covers Mage_Core_Model_Design_Fallback_CachingProxy::getFile + * @covers Mage_Core_Model_Design_Fallback_CachingProxy::getLocaleFile + * @covers Mage_Core_Model_Design_Fallback_CachingProxy::getViewFile */ - public function testNotifySkinFilePublished() + public function testProxyMethods() { - $module = 'Some_Module'; - $file = $this->_baseDir . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'file.ext'; - + $fileArg = 'file.txt'; + $moduleArg = 'module'; + $path = __DIR__ . DIRECTORY_SEPARATOR; $this->_fallback->expects($this->once()) - ->method('getViewFile') - ->with($file, $module) - ->will($this->returnValue(null)); - - // Empty at first - $this->assertNull($this->_model->getViewFile($file, $module)); - - // Store something - $publicFilePath = $this->_baseDir . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'file.ext'; - $result = $this->_model->notifyViewFilePublished($publicFilePath, $file, $module); - $this->assertSame($this->_model, $result); - - // Stored successfully - $storedFilePath = $this->_model->getViewFile($file, $module); - $this->assertEquals($publicFilePath, $storedFilePath); + ->method('getFile')->with($fileArg, $moduleArg)->will($this->returnValue("{$path}one")); + $this->_fallback->expects($this->once()) + ->method('getLocaleFile')->with($fileArg)->will($this->returnValue("{$path}two")); + $this->_fallback->expects($this->once()) + ->method('getViewFile')->with($fileArg, $moduleArg)->will($this->returnValue("{$path}three")); + + // Call each method twice to ensure the proxied method is called once + $this->assertEquals("{$path}one", $this->_model->getFile($fileArg, $moduleArg)); + $this->assertEquals("{$path}one", $this->_model->getFile($fileArg, $moduleArg)); + $this->assertEquals("{$path}two", $this->_model->getLocaleFile($fileArg)); + $this->assertEquals("{$path}two", $this->_model->getLocaleFile($fileArg)); + $this->assertEquals("{$path}three", $this->_model->getViewFile($fileArg, $moduleArg)); + $this->assertEquals("{$path}three", $this->_model->getViewFile($fileArg, $moduleArg)); } /** - * Tests that proxy saves data between instantiations + * Test that proxy caches published skin path, and further calls do not use fallback model */ - public function testSaving() + public function testNotifyViewFilePublished() { - $module = 'Some_Module'; - $file = 'internal/path/to/view_file.ext'; - $expectedPublicFile = 'public/path/to/view_file.ext'; - - $params = array( - 'area' => 'frontend', - 'themeModel' => $this->_theme, - 'locale' => 'en_US', - 'canSaveMap' => true, - 'mapDir' => self::$_tmpDir, - 'baseDir' => '' + $moduleArg = '...'; + $fixture = __DIR__ . DIRECTORY_SEPARATOR . uniqid(); + $anotherFixture = __DIR__ . DIRECTORY_SEPARATOR . uniqid(); + + $this->_fallback->expects($this->once())->method('getViewFile')->will($this->returnValue($fixture)); + $this->assertEquals($fixture, $this->_model->getViewFile('file.txt', $moduleArg)); + $this->assertSame( + $this->_model, $this->_model->notifyViewFilePublished($anotherFixture, 'file.txt', $moduleArg) ); - $model = new Mage_Core_Model_Design_Fallback_CachingProxy($this->_createFilesystem(), $params); - $model->notifyViewFilePublished($expectedPublicFile, $file, $module); - - $globPath = self::$_tmpDir . DIRECTORY_SEPARATOR . '*.*'; - $this->assertEmpty(glob($globPath)); - unset($model); - $this->assertNotEmpty(glob($globPath)); - - /** @var $model Mage_Core_Model_Design_Fallback_CachingProxy */ - $model = $this->getMock( - 'Mage_Core_Model_Design_Fallback_CachingProxy', - array('_getFallback'), - array($this->_createFilesystem(), $params) - ); - $model->expects($this->never()) - ->method('_getFallback'); - - $actualPublicFile = $model->getViewFile($file, $module); - $this->assertEquals($expectedPublicFile, $actualPublicFile); + $this->assertEquals($anotherFixture, $this->_model->getViewFile('file.txt', $moduleArg)); } protected function _createFilesystem() diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/DirTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/DirTest.php new file mode 100644 index 00000000000..8e90493146b --- /dev/null +++ b/dev/tests/unit/testsuite/Mage/Core/Model/DirTest.php @@ -0,0 +1,124 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class Mage_Core_Model_DirTest extends PHPUnit_Framework_TestCase +{ + public function testGetWritableDirCodes() + { + $codes = Mage_Core_Model_Dir::getWritableDirCodes(); + $this->assertInternalType('array', $codes); + $this->assertNotEmpty($codes); + $dir = new Mage_Core_Model_Dir(__DIR__); + foreach ($codes as $code) { + $this->assertNotEmpty($dir->getDir($code)); + } + } + + /** + * @param string $code + * @param string $value + * @expectedException InvalidArgumentException + * @dataProvider invalidUriDataProvider + */ + public function testInvalidUri($code, $value) + { + new Mage_Core_Model_Dir(__DIR__, array($code => $value)); + } + + /** + * @return array + */ + public function invalidUriDataProvider() + { + return array( + array(Mage_Core_Model_Dir::MEDIA, '/'), + array(Mage_Core_Model_Dir::MEDIA, '//'), + array(Mage_Core_Model_Dir::MEDIA, '/value'), + array(Mage_Core_Model_Dir::MEDIA, 'value/'), + array(Mage_Core_Model_Dir::MEDIA, '/value/'), + array(Mage_Core_Model_Dir::MEDIA, 'one\\two'), + array(Mage_Core_Model_Dir::MEDIA, '../dir'), + array(Mage_Core_Model_Dir::MEDIA, './dir'), + array(Mage_Core_Model_Dir::MEDIA, 'one/../two'), + ); + } + + public function testGetUri() + { + $dir = new Mage_Core_Model_Dir(__DIR__, array( + Mage_Core_Model_Dir::PUB => '', + Mage_Core_Model_Dir::MEDIA => 'test', + 'custom' => 'test2' + )); + + // arbitrary custom value + $this->assertEquals('test2', $dir->getUri('custom')); + + // setting empty value correctly adjusts its children + $this->assertEquals('', $dir->getUri(Mage_Core_Model_Dir::PUB)); + $this->assertEquals('lib', $dir->getUri(Mage_Core_Model_Dir::PUB_LIB)); + + // at the same time if another child has custom value, it must not be affected by its parent + $this->assertEquals('test', $dir->getUri(Mage_Core_Model_Dir::MEDIA)); + $this->assertEquals('test/upload', $dir->getUri(Mage_Core_Model_Dir::UPLOAD)); + + // dirs should not be affected (there is no getter for all directories, so use whatever getter is available) + $default = new Mage_Core_Model_Dir(__DIR__); + foreach (Mage_Core_Model_Dir::getWritableDirCodes() as $code) { + $this->assertEquals($default->getDir($code), $dir->getDir($code)); + } + } + + public function testGetDir() + { + $newRoot = __DIR__ . DIRECTORY_SEPARATOR . 'root'; + $newMedia = __DIR__ . DIRECTORY_SEPARATOR . 'media'; + $dir = new Mage_Core_Model_Dir(__DIR__, array(), array( + Mage_Core_Model_Dir::ROOT => $newRoot, + Mage_Core_Model_Dir::MEDIA => $newMedia, + 'custom' => 'test2' + )); + + // arbitrary custom value + $this->assertEquals('test2', $dir->getDir('custom')); + + // new root has affected all its non-customized children + $this->assertStringStartsWith($newRoot, $dir->getDir(Mage_Core_Model_Dir::APP)); + $this->assertStringStartsWith($newRoot, $dir->getDir(Mage_Core_Model_Dir::MODULES)); + + // but it didn't affect the customized dirs + $this->assertEquals($newMedia, $dir->getDir(Mage_Core_Model_Dir::MEDIA)); + $this->assertStringStartsWith($newMedia, $dir->getDir(Mage_Core_Model_Dir::UPLOAD)); + + // uris should not be affected + $default = new Mage_Core_Model_Dir(__DIR__); + foreach (array( + Mage_Core_Model_Dir::PUB, + Mage_Core_Model_Dir::PUB_LIB, + Mage_Core_Model_Dir::MEDIA, + Mage_Core_Model_Dir::UPLOAD) as $code + ) { + $this->assertEquals($default->getUri($code), $dir->getUri($code)); + } + } +} diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/EncryptionTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/EncryptionTest.php new file mode 100644 index 00000000000..cf39cb6648a --- /dev/null +++ b/dev/tests/unit/testsuite/Mage/Core/Model/EncryptionTest.php @@ -0,0 +1,71 @@ +<?php +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/osl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ + +class Mage_Core_Model_EncryptionTest extends PHPUnit_Framework_TestCase +{ + /** + * @dataProvider setHelperGetHashDataProvider + */ + public function testSetHelperGetHash($input) + { + $objectManager = $this->getMock('Magento_ObjectManager_Zend', array('get'), array(), '', false); + $objectManager->expects($this->once()) + ->method('get') + ->with('Mage_Core_Helper_Data') + ->will($this->returnValue(new Mage_Core_Helper_Data())); + + /** + * @var Mage_Core_Model_Encryption + */ + $model = new Mage_Core_Model_Encryption($objectManager); + $model->setHelper($input); + $model->getHash('password', 1); + } + + /** + * @return array + */ + public function setHelperGetHashDataProvider() + { + return array( + 'string' => array('Mage_Core_Helper_Data'), + 'object' => array(new Mage_Core_Helper_Data()), + ); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testSetHelperException() + { + $objectManager = $this->getMock('Magento_ObjectManager_Zend', array(), array(), '', false); + /** + * @var Mage_Core_Model_Encryption + */ + $model = new Mage_Core_Model_Encryption($objectManager); + /** Mock object is not instance of Mage_Code_Helper_Data and should not pass validation */ + $input = $this->getMock('Mage_Code_Helper_Data', array(), array(), '', false); + $model->setHelper($input); + } +} diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/LoggerTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/LoggerTest.php index 44626919808..d0c6e4a987b 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Model/LoggerTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Model/LoggerTest.php @@ -33,20 +33,16 @@ class Mage_Core_Model_LoggerTest extends PHPUnit_Framework_TestCase */ protected $_loggersProperty = null; - /** - * @var Mage_Core_Model_Config|PHPUnit_Framework_MockObject_MockObject - */ - protected $_config = null; - protected function setUp() { - $this->_config = $this->getMock('Mage_Core_Model_Config', array('getOptions', 'getNode'), array(), '', false); - $options = $this->getMock('StdClass', array('getLogDir')); - $options->expects($this->any())->method('getLogDir')->will($this->returnValue(TESTS_TEMP_DIR)); - $this->_config->expects($this->any())->method('getOptions')->will($this->returnValue($options)); - $this->_model = new Mage_Core_Model_Logger($this->_config); + $dirs = new Mage_Core_Model_Dir(TESTS_TEMP_DIR); + $this->_model = new Mage_Core_Model_Logger($dirs); $this->_loggersProperty = new ReflectionProperty($this->_model, '_loggers'); $this->_loggersProperty->setAccessible(true); + $logDir = $dirs->getDir(Mage_Core_Model_Dir::LOG); + if (!is_dir($logDir)) { + mkdir($logDir, 0777, true); + } } /** @@ -56,7 +52,6 @@ class Mage_Core_Model_LoggerTest extends PHPUnit_Framework_TestCase */ public function testAddStreamLog($key, $fileOrWrapper) { - $this->_config->expects($this->any())->method('getNode')->will($this->returnValue('')); $this->assertFalse($this->_model->hasLog($key)); $this->_model->addStreamLog($key, $fileOrWrapper); $this->assertTrue($this->_model->hasLog($key)); @@ -94,6 +89,11 @@ class Mage_Core_Model_LoggerTest extends PHPUnit_Framework_TestCase public function testInitForStore() { + $config = $this->getMock('Mage_Core_Model_Config', array('getNode'), array(), '', false); + $config->expects($this->atLeastOnce()) + ->method('getNode') + ->with('global/log/core/writer_model') + ->will($this->returnValue('StdClass')); $store = $this->getMock('Mage_Core_Model_Store', array('getConfig'), array(), '', false); $store->expects($this->at(0))->method('getConfig')->with('dev/log/active')->will($this->returnValue(false)); $store->expects($this->at(1))->method('getConfig')->with('dev/log/active')->will($this->returnValue(true)); @@ -101,10 +101,10 @@ class Mage_Core_Model_LoggerTest extends PHPUnit_Framework_TestCase $store->expects($this->at(3))->method('getConfig')->with('dev/log/exception_file')->will( $this->returnValue('') ); - $this->_model->initForStore($store); + $this->_model->initForStore($store, $config); $this->assertFalse($this->_model->hasLog(Mage_Core_Model_Logger::LOGGER_SYSTEM)); $this->assertFalse($this->_model->hasLog(Mage_Core_Model_Logger::LOGGER_EXCEPTION)); - $this->_model->initForStore($store); + $this->_model->initForStore($store, $config); $this->assertTrue($this->_model->hasLog(Mage_Core_Model_Logger::LOGGER_SYSTEM)); $this->assertTrue($this->_model->hasLog(Mage_Core_Model_Logger::LOGGER_EXCEPTION)); } diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/ThemeTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/ThemeTest.php index bcfe1d759e8..a7369feda35 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Model/ThemeTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Model/ThemeTest.php @@ -39,7 +39,6 @@ class Mage_Core_Model_ThemeTest extends PHPUnit_Framework_TestCase */ protected function _getThemeModel($designDir, $targetPath) { - Mage::getConfig()->getOptions()->setData('design_dir', $designDir); $objectManager = Mage::getObjectManager(); /** @var $themeCollection Mage_Core_Model_Resource_Theme_Collection */ @@ -57,31 +56,11 @@ class Mage_Core_Model_ThemeTest extends PHPUnit_Framework_TestCase ); /** @var $themeMock Mage_Core_Model_Theme */ $themeMock = $this->getMock('Mage_Core_Model_Theme', array('_init'), $arguments, '', true); - $filesystemMock = $this->getMockBuilder('Magento_Filesystem')->disableOriginalConstructor(true)->getMock(); - $filesystemMock->expects($this->any())->method('searchKeys') - ->will($this->returnValueMap(array( - array( - $designDir, 'frontend/default/iphone/theme.xml', - array( - str_replace('/', DIRECTORY_SEPARATOR, $designDir . '/frontend/default/iphone/theme.xml') - ) - ), - array( - $designDir, 'frontend/default/iphone/theme_invalid.xml', - array( - str_replace( - '/', - DIRECTORY_SEPARATOR, - $designDir . '/frontend/default/iphone/theme_invalid.xml' - ) - ) - ), - ) - )); + $filesystem = new Magento_Filesystem(new Magento_Filesystem_Adapter_Local); /** @var $collectionMock Mage_Core_Model_Theme_Collection|PHPUnit_Framework_MockObject_MockObject */ $collectionMock = $this->getMock('Mage_Core_Model_Theme_Collection', array('getNewEmptyItem'), - array($filesystemMock)); + array($filesystem)); $collectionMock->expects($this->any()) ->method('getNewEmptyItem') ->will($this->returnValue($themeMock)); diff --git a/dev/tests/unit/testsuite/Mage/Core/Model/Validator/FactoryTest.php b/dev/tests/unit/testsuite/Mage/Core/Model/Validator/FactoryTest.php index b13b90ae1f8..a91d18ec385 100644 --- a/dev/tests/unit/testsuite/Mage/Core/Model/Validator/FactoryTest.php +++ b/dev/tests/unit/testsuite/Mage/Core/Model/Validator/FactoryTest.php @@ -84,8 +84,9 @@ class Mage_Core_Model_Validator_FactoryTest extends PHPUnit_Framework_TestCase ->will($this->returnValue(array('/tmp/moduleOne/etc/validation.xml'))); // Translate adapter mock + $designMock = $this->getMock('Mage_Core_Model_Design_Package', array(), array(), '', false); $this->_translateAdapter = $this->getMockBuilder('Mage_Core_Model_Translate') - ->disableOriginalConstructor() + ->setConstructorArgs(array($designMock)) ->setMethods(array('_getTranslatedString')) ->getMock(); $this->_translateAdapter->expects($this->any()) diff --git a/dev/tests/unit/testsuite/Mage/DesignEditor/Controller/Varien/Router/StandardTest.php b/dev/tests/unit/testsuite/Mage/DesignEditor/Controller/Varien/Router/StandardTest.php index d3ea390aca7..1c73911e1f0 100644 --- a/dev/tests/unit/testsuite/Mage/DesignEditor/Controller/Varien/Router/StandardTest.php +++ b/dev/tests/unit/testsuite/Mage/DesignEditor/Controller/Varien/Router/StandardTest.php @@ -183,20 +183,26 @@ class Mage_DesignEditor_Controller_Varien_Router_StandardTest extends PHPUnit_Fr ) { // default mocks - not affected on method functionality $controllerFactory = $this->getMock('Mage_Core_Controller_Varien_Action_Factory', array(), array(), '', false); + $objectManager = $this->getMock('Magento_ObjectManager_Zend', array('get'), array(), '', false); $filesystem = $this->getMockBuilder('Magento_Filesystem')->disableOriginalConstructor()->getMock(); $app = $this->getMock('Mage_Core_Model_App', array(), array(), '', false); - $testArea = 'frontend'; - $testBaseController = 'Mage_Core_Controller_Varien_Action'; - $helper = $this->getMock('Mage_DesignEditor_Helper_Data', array('getFrontName'), array(), '', false); - $helper->expects($this->atLeastOnce()) - ->method('getFrontName') - ->will($this->returnValue(self::VDE_FRONT_NAME)); - - $backendSession = $this->getMock('Mage_Backend_Model_Auth_Session', array('isLoggedIn'), array(), '', false); - $backendSession->expects($isVde ? $this->once() : $this->never()) - ->method('isLoggedIn') - ->will($this->returnValue($isLoggedIn)); + $helper = $this->_getHelperMock(); + $backendSession = $this->_getBackendSessionMock($isVde, $isLoggedIn); + $stateModel = $this->_getStateModelMock($routers); + $configuration = $this->_getConfigurationMock($isVde, $isLoggedIn, $isConfiguration); + $callback = function ($name) use ($helper, $backendSession, $stateModel, $configuration) { + switch ($name) { + case 'Mage_DesignEditor_Helper_Data': return $helper; + case 'Mage_Backend_Model_Auth_Session': return $backendSession; + case 'Mage_DesignEditor_Model_State': return $stateModel; + case 'Mage_Core_Model_Config': return $configuration; + default: return null; + } + }; + $objectManager->expects($this->any()) + ->method('get') + ->will($this->returnCallback($callback)); $frontController = $this->getMock('Mage_Core_Controller_Varien_Front', array('applyRewrites', 'getRouters'), array(), '', false @@ -210,13 +216,68 @@ class Mage_DesignEditor_Controller_Varien_Router_StandardTest extends PHPUnit_Fr ->will($this->returnValue($routers)); } + $router = new Mage_DesignEditor_Controller_Varien_Router_Standard( + $controllerFactory, + $objectManager, + $filesystem, + $app, + 'frontend', + 'Mage_Core_Controller_Varien_Action' + ); + $router->setFront($frontController); + return $router; + } + + /** + * @return PHPUnit_Framework_MockObject_MockObject + */ + protected function _getHelperMock() + { + $helper = $this->getMock('Mage_DesignEditor_Helper_Data', array('getFrontName'), array(), '', false); + $helper->expects($this->atLeastOnce()) + ->method('getFrontName') + ->will($this->returnValue(self::VDE_FRONT_NAME)); + return $helper; + } + + /** + * @param bool $isVde + * @param bool $isLoggedIn + * @return PHPUnit_Framework_MockObject_MockObject + */ + protected function _getBackendSessionMock($isVde, $isLoggedIn) + { + $backendSession = $this->getMock('Mage_Backend_Model_Auth_Session', array('isLoggedIn'), array(), '', false); + $backendSession->expects($isVde ? $this->once() : $this->never()) + ->method('isLoggedIn') + ->will($this->returnValue($isLoggedIn)); + return $backendSession; + } + + /** + * @param array $routers + * @return PHPUnit_Framework_MockObject_MockObject + */ + protected function _getStateModelMock(array $routers) + { $stateModel = $this->getMock('Mage_DesignEditor_Model_State', array('update'), array(), '', false); if (array_key_exists('matched', $routers)) { $stateModel->expects($this->once()) ->method('update') ->with(self::AREA_CODE); + return $stateModel; } + return $stateModel; + } + /** + * @param bool $isVde + * @param bool $isLoggedIn + * @param bool $isConfiguration + * @return PHPUnit_Framework_MockObject_MockObject + */ + protected function _getConfigurationMock($isVde, $isLoggedIn, $isConfiguration) + { $configuration = $this->getMock('Mage_Core_Model_Config', array('getNode'), array(), '', false); if ($isVde && $isLoggedIn) { $configurationData = null; @@ -240,19 +301,6 @@ class Mage_DesignEditor_Controller_Varien_Router_StandardTest extends PHPUnit_Fr ->will($this->returnValue($elementMock)); } } - - $router = new Mage_DesignEditor_Controller_Varien_Router_Standard( - $controllerFactory, - $filesystem, - $app, - $testArea, - $testBaseController, - $backendSession, - $helper, - $stateModel, - $configuration - ); - $router->setFront($frontController); - return $router; + return $configuration; } } diff --git a/dev/tests/unit/testsuite/Mage/DesignEditor/Model/StateTest.php b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/StateTest.php index 4f11e30e20b..d1c71b1a352 100644 --- a/dev/tests/unit/testsuite/Mage/DesignEditor/Model/StateTest.php +++ b/dev/tests/unit/testsuite/Mage/DesignEditor/Model/StateTest.php @@ -59,12 +59,10 @@ class Mage_DesignEditor_Model_StateTest extends PHPUnit_Framework_TestCase */ const AREA_CODE = 'front'; - /**#@+ - * Test theme data + /** + * Test theme id */ const THEME_ID = 1; - const THEME_CONFIGURATION = 'test_config'; - /**#@-*/ /** * @var Mage_DesignEditor_Model_State @@ -136,9 +134,7 @@ class Mage_DesignEditor_Model_StateTest extends PHPUnit_Framework_TestCase $this->_objectManager = $this->getMock('Magento_ObjectManager_Zend', array('addAlias'), array(), '', false ); - $this->_designPackage = $this->getMock('Mage_Core_Model_Design_Package', array('getConfigPathByArea'), - array(), '', false - ); + $this->_designPackage = $this->getMock('Mage_Core_Model_Design_Package', array(), array(), '', false); $this->_application = $this->getMock('Mage_Core_Model_App', array('getStore'), array(), '', false ); @@ -225,15 +221,10 @@ class Mage_DesignEditor_Model_StateTest extends PHPUnit_Framework_TestCase ->with(self::LAYOUT_UPDATE_RESOURCE_MODEL_CORE_CLASS_NAME, self::LAYOUT_UPDATE_RESOURCE_MODEL_VDE_CLASS_NAME); - $this->_designPackage->expects($this->once()) - ->method('getConfigPathByArea') - ->with(Mage_Core_Model_App_Area::AREA_FRONTEND) - ->will($this->returnValue(self::THEME_CONFIGURATION)); - $store = $this->getMock('Mage_Core_Model_Store', array('setConfig'), array(), '', false); $store->expects($this->once()) ->method('setConfig') - ->with(self::THEME_CONFIGURATION, self::THEME_ID); + ->with(Mage_Core_Model_Design_Package::XML_PATH_THEME_ID, self::THEME_ID); $this->_application->expects($this->once()) ->method('getStore') diff --git a/dev/tests/unit/testsuite/Mage/Index/Model/Lock/StorageTest.php b/dev/tests/unit/testsuite/Mage/Index/Model/Lock/StorageTest.php index 203f27499d4..136cf2d14f0 100644 --- a/dev/tests/unit/testsuite/Mage/Index/Model/Lock/StorageTest.php +++ b/dev/tests/unit/testsuite/Mage/Index/Model/Lock/StorageTest.php @@ -24,38 +24,18 @@ * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - -/** - * Test for Mage_Index_Model_Lock_Storage - */ class Mage_Index_Model_Lock_StorageTest extends PHPUnit_Framework_TestCase { - /** - * Test var directory - */ - const VAR_DIRECTORY = 'test'; - - /** - * Locks storage model - * - * @var Mage_Index_Model_Lock_Storage - */ - protected $_storage; - /** * Keep current process id for tests * * @var integer */ - protected $_currentProcessId; + protected $_callbackProcessId; - protected function setUp() + public function testGetFile() { - $config = $this->getMock('Mage_Core_Model_Config', array('getVarDir'), array(), '', false); - $config->expects($this->exactly(2)) - ->method('getVarDir') - ->will($this->returnValue(self::VAR_DIRECTORY)); - + $dirs = new Mage_Core_Model_Dir(__DIR__); $fileModel = $this->getMock('Mage_Index_Model_Process_File', array( 'setAllowCreateFolders', @@ -70,7 +50,7 @@ class Mage_Index_Model_Lock_StorageTest extends PHPUnit_Framework_TestCase ->with(true); $fileModel->expects($this->exactly(2)) ->method('open') - ->with(array('path' => self::VAR_DIRECTORY)); + ->with(array('path' => __DIR__ . DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'locks')); $fileModel->expects($this->exactly(2)) ->method('streamOpen') ->will($this->returnCallback(array($this, 'checkFilenameCallback'))); @@ -85,31 +65,28 @@ class Mage_Index_Model_Lock_StorageTest extends PHPUnit_Framework_TestCase ->method('createFromArray') ->will($this->returnValue($fileModel)); - $this->_storage = new Mage_Index_Model_Lock_Storage($config, $fileFactory); - } + $storage = new Mage_Index_Model_Lock_Storage($dirs, $fileFactory); - public function testGetFile() - { /** * List if test process IDs. * We need to test cases when new ID and existed ID passed into tested method. */ $processIdList = array(1, 2, 2); foreach ($processIdList as $processId) { - $this->_currentProcessId = $processId; - $this->assertInstanceOf('Mage_Index_Model_Process_File', $this->_storage->getFile($processId)); + $this->_callbackProcessId = $processId; + $this->assertInstanceOf('Mage_Index_Model_Process_File', $storage->getFile($processId)); } - $this->assertAttributeCount(2, '_fileHandlers', $this->_storage); + $this->assertAttributeCount(2, '_fileHandlers', $storage); } /** - * Check file name + * Check file name (callback subroutine for testGetFile()) * * @param string $filename */ public function checkFilenameCallback($filename) { - $expected = 'index_process_' . $this->_currentProcessId . '.lock'; + $expected = 'index_process_' . $this->_callbackProcessId . '.lock'; $this->assertEquals($expected, $filename); } } diff --git a/dev/tests/unit/testsuite/Mage/Page/Block/Html/HeaderTest.php b/dev/tests/unit/testsuite/Mage/Page/Block/Html/HeaderTest.php index b335bb2d68c..251b67fb5b1 100644 --- a/dev/tests/unit/testsuite/Mage/Page/Block/Html/HeaderTest.php +++ b/dev/tests/unit/testsuite/Mage/Page/Block/Html/HeaderTest.php @@ -42,11 +42,6 @@ class Mage_Page_Block_Html_HeaderTest extends PHPUnit_Framework_TestCase ->method('getBaseUrl') ->will($this->returnValue('http://localhost/pub/media/')); - $configOptions = $this->getMock('Mage_Core_Model_Config_Options', array('getDir')); - $configOptions->expects($this->once()) - ->method('getDir') - ->will($this->returnValue(__DIR__ . DIRECTORY_SEPARATOR . '_files')); - $helper = $this->getMockBuilder('Mage_Core_Helper_File_Storage_Database') ->setMethods(array('checkDbUsage')) ->disableOriginalConstructor() @@ -60,16 +55,22 @@ class Mage_Page_Block_Html_HeaderTest extends PHPUnit_Framework_TestCase ->method('get') ->will($this->returnValue($helper)); + $dirsMock = $this->getMock('Mage_Core_Model_Dir', array('getDir'), array(), '', false); + $dirsMock->expects($this->any()) + ->method('getDir') + ->with(Mage_Core_Model_Dir::MEDIA) + ->will($this->returnValue(__DIR__ . DIRECTORY_SEPARATOR . '_files')); + $objectManager = new Magento_Test_Helper_ObjectManager($this); $arguments = array( 'storeConfig' => $storeConfig, 'urlBuilder' => $urlBuilder, - 'configOptions' => $configOptions, - 'helperFactory' => $helperFactory + 'helperFactory' => $helperFactory, + 'dirs' => $dirsMock ); - $this->_block = $objectManager->getBlock('Mage_Page_Block_Html_Header', $arguments); + $block = $objectManager->getBlock('Mage_Page_Block_Html_Header', $arguments); - $this->assertEquals('http://localhost/pub/media/logo/default/image.gif', $this->_block->getLogoSrc()); + $this->assertEquals('http://localhost/pub/media/logo/default/image.gif', $block->getLogoSrc()); } } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php index 9a8958abc66..0552c3c827a 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/Tab/ResourceTest.php @@ -44,7 +44,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_ResourceTest extends PHPUnit_Fra $helper = new Magento_Test_Helper_ObjectManager($this); $this->_block = $helper->getBlock('Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_Resource', array( - // TODO Remove injecting of 'urlBuilder' and 'authorizationConfig' after MAGETWO-5038 complete + // TODO: Remove injecting of 'urlBuilder' and 'authorizationConfig' after MAGETWO-5038 complete 'urlBuilder' => $this->getMockBuilder('Mage_Backend_Model_Url') ->disableOriginalConstructor() ->getMock(), @@ -56,7 +56,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_ResourceTest extends PHPUnit_Fra } /** - * Test isEverythingAllowed method + * Test isEverythingAllowed method. * * @dataProvider isEverythingAllowedDataProvider * @param array $selectedResources @@ -85,11 +85,11 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_Tab_ResourceTest extends PHPUnit_Fra public function isEverythingAllowedDataProvider() { return array( - 'Not Everything Allowed' => array( + 'Not everything is allowed' => array( array('customer', 'customer/get'), false ), - 'Everything Allowed' => array( + 'Everything is allowed' => array( array('customer', 'customer/get', Mage_Webapi_Model_Authorization::API_ACL_RESOURCES_ROOT_ID), true ) diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/TabsTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/TabsTest.php index b1bc38ea13c..1fc1582ac25 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/TabsTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/Edit/TabsTest.php @@ -69,7 +69,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_TabsTest extends PHPUnit_Framework_T } /** - * Test _construct method + * Test _construct method. */ public function testConstruct() { @@ -79,7 +79,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_TabsTest extends PHPUnit_Framework_T } /** - * Test for _beforeToHtml method + * Test for _beforeToHtml method. * * @dataProvider beforeToHtmlDataProvider * @param object $apiRole @@ -105,7 +105,7 @@ class Mage_Webapi_Block_Adminhtml_Role_Edit_TabsTest extends PHPUnit_Framework_T array('active_tab', null, 'main_section') ))); - // todo: do checks using toHtml() when DI is implemented for abstract blocks + // TODO: do checks using toHtml() when DI is implemented for abstract blocks $toHtmlMethod = new ReflectionMethod($this->_block, '_beforeToHtml'); $toHtmlMethod->setAccessible(true); $toHtmlMethod ->invoke($this->_block); diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/EditTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/EditTest.php index ea20048df2b..761bd99ac6c 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/EditTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/Role/EditTest.php @@ -75,7 +75,7 @@ class Mage_Webapi_Block_Adminhtml_Role_EditTest extends PHPUnit_Framework_TestCa } /** - * Test _construct method + * Test _construct method. */ public function testConstruct() { @@ -87,7 +87,7 @@ class Mage_Webapi_Block_Adminhtml_Role_EditTest extends PHPUnit_Framework_TestCa } /** - * Test getSaveAndContinueUrl method + * Test getSaveAndContinueUrl method. */ public function testGetSaveAndContinueUrl() { @@ -102,7 +102,7 @@ class Mage_Webapi_Block_Adminhtml_Role_EditTest extends PHPUnit_Framework_TestCa } /** - * Test getHeaderText method + * Test getHeaderText method. */ public function testGetHeaderText() { @@ -130,7 +130,7 @@ class Mage_Webapi_Block_Adminhtml_Role_EditTest extends PHPUnit_Framework_TestCa } /** - * Asserts that block has button with id and label at level + * Asserts that block has button with ID and label at level. * * @param int $level * @param string $buttonId @@ -141,10 +141,10 @@ class Mage_Webapi_Block_Adminhtml_Role_EditTest extends PHPUnit_Framework_TestCa $buttonsProperty = new ReflectionProperty($this->_block, '_buttons'); $buttonsProperty->setAccessible(true); $buttons = $buttonsProperty->getValue($this->_block); - $this->assertInternalType('array', $buttons, 'Cannot get bloc buttons'); + $this->assertInternalType('array', $buttons, 'Cannot get block buttons.'); $this->assertArrayHasKey($level, $buttons, "Block doesn't have buttons at level $level"); $this->assertArrayHasKey($buttonId, $buttons[$level], "Block doesn't have '$buttonId' button at level $level"); - $this->assertArrayHasKey('label', $buttons[$level][$buttonId], "Block button doesn't have label"); - $this->assertEquals($label, $buttons[$level][$buttonId]['label'], "Block button label has unexpected value"); + $this->assertArrayHasKey('label', $buttons[$level][$buttonId], "Block button doesn't have label."); + $this->assertEquals($label, $buttons[$level][$buttonId]['label'], "Block button label has unexpected value."); } } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/RoleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/RoleTest.php index 9cd6f2a7e1e..54a45d8be4b 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/RoleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/RoleTest.php @@ -48,7 +48,7 @@ class Mage_Webapi_Block_Adminhtml_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test _construct method + * Test _construct method. */ public function testConstruct() { @@ -59,7 +59,7 @@ class Mage_Webapi_Block_Adminhtml_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test getCreateUrl method + * Test getCreateUrl method. */ public function testGetCreateUrl() { @@ -74,7 +74,7 @@ class Mage_Webapi_Block_Adminhtml_RoleTest extends PHPUnit_Framework_TestCase } /** - * Asserts that block has button with id and label at level + * Asserts that block has button with ID and label at level. * * @param int $level * @param string $buttonId @@ -85,10 +85,10 @@ class Mage_Webapi_Block_Adminhtml_RoleTest extends PHPUnit_Framework_TestCase $buttonsProperty = new ReflectionProperty($this->_block, '_buttons'); $buttonsProperty->setAccessible(true); $buttons = $buttonsProperty->getValue($this->_block); - $this->assertInternalType('array', $buttons, 'Cannot get bloc buttons'); + $this->assertInternalType('array', $buttons, 'Cannot get block buttons.'); $this->assertArrayHasKey($level, $buttons, "Block doesn't have buttons at level $level"); $this->assertArrayHasKey($buttonId, $buttons[$level], "Block doesn't have '$buttonId' button at level $level"); - $this->assertArrayHasKey('label', $buttons[$level][$buttonId], "Block button doesn't have label"); - $this->assertEquals($label, $buttons[$level][$buttonId]['label'], "Block button label has unexpected value"); + $this->assertArrayHasKey('label', $buttons[$level][$buttonId], "Block button doesn't have label."); + $this->assertEquals($label, $buttons[$level][$buttonId]['label'], "Block button label has unexpected value."); } } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php index d7cc0295cad..d3bdf778433 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/User/EditTest.php @@ -59,7 +59,7 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa $helper = new Magento_Test_Helper_ObjectManager($this); $this->_block = $helper->getBlock('Mage_Webapi_Block_Adminhtml_User_Edit', array( - // TODO Remove injecting of 'urlBuilder' after MAGETWO-5038 complete + // TODO: Remove injecting of 'urlBuilder' after MAGETWO-5038 complete 'urlBuilder' => $this->getMockBuilder('Mage_Backend_Model_Url') ->disableOriginalConstructor() ->getMock(), @@ -69,7 +69,7 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa } /** - * Test _construct method + * Test _construct method. */ public function testConstruct() { @@ -82,7 +82,7 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa } /** - * Test getHeaderText method + * Test getHeaderText method. */ public function testGetHeaderText() { @@ -110,7 +110,7 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa } /** - * Asserts that block has button with id and attribute at level + * Asserts that block has button with ID and attribute at level. * * @param int $level * @param string $buttonId @@ -122,12 +122,12 @@ class Mage_Webapi_Block_Adminhtml_User_EditTest extends PHPUnit_Framework_TestCa $buttonsProperty = new ReflectionProperty($this->_block, '_buttons'); $buttonsProperty->setAccessible(true); $buttons = $buttonsProperty->getValue($this->_block); - $this->assertInternalType('array', $buttons, 'Cannot get bloc buttons'); + $this->assertInternalType('array', $buttons, 'Cannot get block buttons.'); $this->assertArrayHasKey($level, $buttons, "Block doesn't have buttons at level $level"); $this->assertArrayHasKey($buttonId, $buttons[$level], "Block doesn't have '$buttonId' button at level $level"); $this->assertArrayHasKey($attributeName, $buttons[$level][$buttonId], "Block button doesn't have attribute $attributeName"); $this->assertEquals($attributeValue, $buttons[$level][$buttonId][$attributeName], - "Block button $attributeName' has unexpected value"); + "Block button $attributeName' has unexpected value."); } } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/UserTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/UserTest.php index 096db188f9e..3ee5bb31c4d 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/UserTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Block/Adminhtml/UserTest.php @@ -34,7 +34,7 @@ class Mage_Webapi_Block_Adminhtml_UserTest extends PHPUnit_Framework_TestCase { $helper = new Magento_Test_Helper_ObjectManager($this); $this->_block = $helper->getBlock('Mage_Webapi_Block_Adminhtml_User', array( - // TODO Remove injecting of 'urlBuilder' after MAGETWO-5038 complete + // TODO: Remove injecting of 'urlBuilder' after MAGETWO-5038 complete 'urlBuilder' => $this->getMockBuilder('Mage_Backend_Model_Url') ->disableOriginalConstructor() ->getMock(), @@ -42,7 +42,7 @@ class Mage_Webapi_Block_Adminhtml_UserTest extends PHPUnit_Framework_TestCase } /** - * Test _construct method + * Test _construct method. */ public function testConstruct() { @@ -53,7 +53,7 @@ class Mage_Webapi_Block_Adminhtml_UserTest extends PHPUnit_Framework_TestCase } /** - * Asserts that block has button with id and label at level + * Asserts that block has button with ID and label at level. * * @param int $level * @param string $buttonId @@ -64,10 +64,10 @@ class Mage_Webapi_Block_Adminhtml_UserTest extends PHPUnit_Framework_TestCase $buttonsProperty = new ReflectionProperty($this->_block, '_buttons'); $buttonsProperty->setAccessible(true); $buttons = $buttonsProperty->getValue($this->_block); - $this->assertInternalType('array', $buttons, 'Cannot get bloc buttons'); + $this->assertInternalType('array', $buttons, 'Cannot get block buttons.'); $this->assertArrayHasKey($level, $buttons, "Block doesn't have buttons at level $level"); $this->assertArrayHasKey($buttonId, $buttons[$level], "Block doesn't have '$buttonId' button at level $level"); - $this->assertArrayHasKey('label', $buttons[$level][$buttonId], "Block button doesn't have label"); - $this->assertEquals($label, $buttons[$level][$buttonId]['label'], "Block button label has unexpected value"); + $this->assertArrayHasKey('label', $buttons[$level][$buttonId], "Block button doesn't have label."); + $this->assertEquals($label, $buttons[$level][$buttonId]['label'], "Block button label has unexpected value."); } } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/ErrorProcessorTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/ErrorProcessorTest.php index 381d6974ede..bc713579956 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/ErrorProcessorTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/ErrorProcessorTest.php @@ -64,12 +64,12 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame } /** - * Test render method in Json format. + * Test render method in JSON format. */ public function testRenderJson() { $_SERVER['HTTP_ACCEPT'] = 'json'; - /** Assert jsonEncode method will be executed once. */ + /** Assert that jsonEncode method will be executed once. */ $this->_helperMock->expects($this->once())->method('jsonEncode')->will( $this->returnCallback(array($this, 'callbackJsonEncode'), $this->returnArgument(0)) ); @@ -80,13 +80,13 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame $actualResult = ob_get_contents(); ob_end_clean(); $expectedResult = '{"messages":{"error":[{"code":500,"message":"Message"}]}}'; - $this->assertEquals($expectedResult, $actualResult, 'Wrong rendering in Json.'); + $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in JSON.'); } /** * Callback function for RenderJson and RenderJsonInDeveloperMode tests. * - * Method encode data to Json and return it. + * Method encodes data to JSON and returns it. * * @param $data * @return string @@ -97,14 +97,14 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame } /** - * Test render method in Json format with turned on developer mode. + * Test render method in JSON format with turned on developer mode. */ public function testRenderJsonInDeveloperMode() { $_SERVER['HTTP_ACCEPT'] = 'json'; /** Mock app to return enabled developer mode flag. */ $this->_appMock->expects($this->any())->method('isDeveloperMode')->will($this->returnValue(true)); - /** Assert jsonEncode method will be executed once. */ + /** Assert that jsonEncode method will be executed once. */ $this->_helperMock->expects($this->once())->method('jsonEncode')->will( $this->returnCallback(array($this, 'callbackJsonEncode'), $this->returnArgument(0)) ); @@ -113,7 +113,7 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame $actualResult = ob_get_contents(); ob_end_clean(); $expectedResult = '{"messages":{"error":[{"code":401,"message":"Message","trace":"Message trace."}]}}'; - $this->assertEquals($expectedResult, $actualResult, 'Wrong rendering in Json.'); + $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in JSON.'); } /** @@ -130,7 +130,7 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame ob_end_clean(); $expectedResult = '<?xml version="1.0"?><error><messages><error><data_item><code>500</code>' . '<message>Message</message></data_item></error></messages></error>'; - $this->assertEquals($expectedResult, $actualResult, 'Wrong rendering in XML.'); + $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in XML.'); } /** @@ -149,17 +149,17 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame ob_end_clean(); $expectedResult = '<?xml version="1.0"?><error><messages><error><data_item><code>401</code><message>' . 'Message</message><trace><![CDATA[Trace message.]]></trace></data_item></error></messages></error>'; - $this->assertEquals($expectedResult, $actualResult, 'Wrong rendering in XML with turned on developer mode.'); + $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in XML with turned on developer mode.'); } /** - * Test default render format is Json. + * Test default render format is JSON. */ public function testRenderDefaultFormat() { /** Set undefined rendering format. */ $_SERVER['HTTP_ACCEPT'] = 'undefined'; - /** Assert jsonEncode method will be executed at least once. */ + /** Assert that jsonEncode method will be executed at least once. */ $this->_helperMock->expects($this->atLeastOnce())->method('jsonEncode'); $this->_errorProcessor->render('Message'); } @@ -173,13 +173,13 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame $_SERVER['HTTP_ACCEPT'] = 'json'; /** Init Mage_Webapi_Exception. */ $apiException = new Mage_Webapi_Exception('Exception message', 500); - /** Assert jsonEncode will be executed once. */ + /** Assert that jsonEncode will be executed once. */ $this->_helperMock->expects($this->once())->method('jsonEncode'); $this->_errorProcessor->renderException($apiException); } /** - * Test renderException method with turned on Developer mode. + * Test renderException method with turned on developer mode. */ public function testRenderExecutionInDeveloperMode() { @@ -189,7 +189,7 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame $exception = new Exception('Message'); /** Mock app to return enabled developer mode flag. */ $this->_appMock->expects($this->any())->method('isDeveloperMode')->will($this->returnValue(true)); - /** Assert jsonEncode will be executed once. */ + /** Assert that jsonEncode will be executed once. */ $this->_helperMock->expects($this->once())->method('jsonEncode'); $this->_errorProcessor->renderException($exception); } @@ -201,7 +201,7 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame { /** Init mage_webapi_Exception. */ $apiException = new Mage_Webapi_Exception('Message', 400); - /** Asser Webapi exception was not masked. */ + /** Assert that Webapi exception was not masked. */ $this->assertEquals( $this->_errorProcessor->maskException($apiException), $apiException, @@ -218,7 +218,7 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame $this->_appMock->expects($this->once())->method('isDeveloperMode')->will($this->returnValue(true)); /** Init Logical exception. */ $logicalException = new LogicException(); - /** Asser Webapi exception was not masked. */ + /** Assert that Webapi exception was not masked. */ $this->assertEquals( $this->_errorProcessor->maskException($logicalException), $logicalException, @@ -231,22 +231,22 @@ class Mage_Webapi_Controller_Dispatcher_ErrorProcessorTest extends PHPUnit_Frame */ public function testMaskNonWebapiException() { - /** Assert exception was logged. */ + /** Assert that exception was logged. */ $this->_loggerMock->expects($this->once())->method('logException'); $maskedException = $this->_errorProcessor->maskException(new LogicException()); - /** Assert masked exception type is Mage_Webapi_Exception. */ + /** Assert that masked exception type is Mage_Webapi_Exception. */ $this->assertInstanceOf('Mage_Webapi_Exception', $maskedException, 'Masked exception type is not Webapi.'); - /** Asser masked exception code is 500. */ + /** Assert that masked exception code is 500. */ $this->assertEquals( Mage_Webapi_Exception::HTTP_INTERNAL_ERROR, $maskedException->getCode(), - 'Masked exception code is wrong.' + 'Masked exception code is invalid.' ); /** Assert masked exception message. */ $this->assertEquals( 'Internal Error. Details are available in Magento log file. Report ID: "%s"', $maskedException->getMessage(), - 'Masked exception message is wrong.' + 'Masked exception message is invalid.' ); } } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/RestTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/RestTest.php index 4c0136fc6f7..edcf32a7bb9 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/RestTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/RestTest.php @@ -107,7 +107,7 @@ class Mage_Webapi_Controller_Dispatcher_RestTest extends PHPUnit_Framework_TestC $this->_authenticationMock->expects($this->once())->method('authenticate')->will( $this->throwException($logicalException) ); - /** Assert setException method will be executed with thrown logical Exception. */ + /** Assert that setException method will be executed with thrown logical Exception. */ $this->_responseMock->expects($this->once())->method('setException')->with($this->equalTo($logicalException)); $this->_restDispatcher->dispatch(); @@ -124,7 +124,7 @@ class Mage_Webapi_Controller_Dispatcher_RestTest extends PHPUnit_Framework_TestC ->getMock(); $routeMock->expects($this->any())->method('getResourceName'); $this->_routerMock->expects($this->once())->method('match')->will($this->returnValue($routeMock)); - /** Mock Api Config getMethodNameByOperation method to return isDeleted method of Varien_Onject. */ + /** Mock Api Config getMethodNameByOperation method to return isDeleted method of Varien_Object. */ $this->_apiConfigMock->expects($this->once())->method('getMethodNameByOperation')->will( $this->returnValue('isDeleted') ); @@ -132,9 +132,9 @@ class Mage_Webapi_Controller_Dispatcher_RestTest extends PHPUnit_Framework_TestC $this->_apiConfigMock->expects($this->once())->method('identifyVersionSuffix')->will($this->returnValue('')); $this->_apiConfigMock->expects($this->once())->method('checkDeprecationPolicy'); $this->_authorizationMock->expects($this->once())->method('checkResourceAcl'); - /** Create fake controller mock, e. g. Varien_Object object. */ + /** Create fake controller mock, e.g., Varien_Object object. */ $controllerMock = $this->getMockBuilder('Varien_Object')->disableOriginalConstructor()->getMock(); - /** Assert isDeleted method will be executed once. */ + /** Assert that isDeleted method will be executed once. */ $controllerMock->expects($this->once())->method('isDeleted'); /** Mock factory mock to return fake action controller. */ $this->_controllerFactory->expects($this->once())->method('createActionController')->will( @@ -144,7 +144,7 @@ class Mage_Webapi_Controller_Dispatcher_RestTest extends PHPUnit_Framework_TestC $this->_restPresentation->expects($this->once())->method('fetchRequestData')->will( $this->returnValue(array()) ); - /** Assert response sendResponse method will be executed once. */ + /** Assert that response sendResponse method will be executed once. */ $this->_responseMock->expects($this->once())->method('sendResponse'); $this->_restDispatcher->dispatch(); diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/AuthenticationTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/AuthenticationTest.php index 554232b2865..c54c21f2cdd 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/AuthenticationTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/AuthenticationTest.php @@ -133,7 +133,7 @@ class Mage_Webapi_Controller_Dispatcher_Soap_AuthenticationTest extends PHPUnit_ } /** - * Exception data provider for authenticate() method + * Exception data provider for authenticate() method. * * @return array */ diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/HandlerTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/HandlerTest.php index 7c78ae3ab7e..f53360ff3f3 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/HandlerTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/Soap/HandlerTest.php @@ -146,7 +146,7 @@ class Mage_Webapi_Controller_Dispatcher_Soap_HandlerTest extends PHPUnit_Framewo ->method('maskException') ->with($exception) ->will($this->returnValue($exception)); - /** Model situation: authenticate() method throw Exception(). */ + /** Model situation: authenticate() method throws Exception(). */ $this->_authenticationMock->expects($this->once()) ->method('authenticate') ->will($this->throwException($exception)); diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/SoapTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/SoapTest.php index e4b61f9c70d..5f32756fc34 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/SoapTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Dispatcher/SoapTest.php @@ -106,7 +106,7 @@ class Mage_Webapi_Controller_Dispatcher_SoapTest extends PHPUnit_Framework_TestC } /** - * Clean up dispatcher and it's dependencies. + * Clean up dispatcher and its dependencies. */ protected function tearDown() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/FrontTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/FrontTest.php index 3e76f082a63..3437990cf5a 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/FrontTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/FrontTest.php @@ -25,6 +25,8 @@ */ class Mage_Webapi_Controller_FrontTest extends PHPUnit_Framework_TestCase { + const WEBAPI_AREA_FRONT_NAME = 'webapi'; + /** @var Mage_Webapi_Controller_Front */ protected $_frontControllerMock; @@ -37,6 +39,9 @@ class Mage_Webapi_Controller_FrontTest extends PHPUnit_Framework_TestCase /** @var Mage_Webapi_Controller_Dispatcher_ErrorProcessor. */ protected $_errorProcessorMock; + /** @var Mage_Core_Model_Config */ + protected $_configMock; + protected function setUp() { /** Prepare mocks for SUT constructor. */ @@ -48,9 +53,16 @@ class Mage_Webapi_Controller_FrontTest extends PHPUnit_Framework_TestCase $helperFactory = $this->getMock('Mage_Core_Model_Factory_Helper'); $helperFactory->expects($this->any())->method('get')->will($this->returnValue($helper)); + $this->_configMock = $this->getMockBuilder('Mage_Core_Model_Config')->disableOriginalConstructor()->getMock(); + $this->_configMock->expects($this->any())->method('getAreaFrontName')->will( + $this->returnValue(self::WEBAPI_AREA_FRONT_NAME) + ); + $this->_dispatcherFactory = $this->getMockBuilder('Mage_Webapi_Controller_Dispatcher_Factory') ->disableOriginalConstructor()->getMock(); $application = $this->getMockBuilder('Mage_Core_Model_App')->disableOriginalConstructor()->getMock(); + $application->expects($this->any())->method('getConfig')->will($this->returnValue($this->_configMock)); + $this->_routeFactoryMock = $this->getMockBuilder('Magento_Controller_Router_Route_Factory') ->disableOriginalConstructor()->getMock(); $this->_errorProcessorMock = $this->getMockBuilder('Mage_Webapi_Controller_Dispatcher_ErrorProcessor') @@ -105,7 +117,7 @@ class Mage_Webapi_Controller_FrontTest extends PHPUnit_Framework_TestCase $restDispatcherMock = $this->getMockBuilder('Mage_Webapi_Controller_Dispatcher_Rest') ->disableOriginalConstructor() ->getMock(); - /** Assert handle method in mocked object will be executed only once. */ + /** Assert that handle method in mocked object will be executed only once. */ $restDispatcherMock->expects($this->once())->method('dispatch'); $this->_dispatcherFactory->expects($this->any())->method('get') ->will($this->returnValue($restDispatcherMock)); @@ -126,7 +138,7 @@ class Mage_Webapi_Controller_FrontTest extends PHPUnit_Framework_TestCase /** Mock dispatcher to throw Logical exception. */ $restDispatcherMock->expects($this->any())->method('dispatch')->will($this->throwException($logicalException)); $this->_dispatcherFactory->expects($this->any())->method('get')->will($this->returnValue($restDispatcherMock)); - /** Assert error processor renderException method will be executed with Logical Exception. */ + /** Assert that error processor renderException method will be executed with Logical Exception. */ $this->_errorProcessorMock->expects($this->once())->method('renderException')->with( $this->equalTo($logicalException) ); @@ -170,7 +182,7 @@ class Mage_Webapi_Controller_FrontTest extends PHPUnit_Framework_TestCase */ protected function _createMockForApiRouteAndFactory($apiType) { - $apiRouteMock = $this->getMockBuilder('Mage_Webapi_Controller_Router_Route_Webapi') + $apiRouteMock = $this->getMockBuilder('Mage_Webapi_Controller_Router_Route') ->disableOriginalConstructor()->getMock(); $apiRouteMock->expects($this->any())->method('match')->will($this->returnValue($apiType)); $this->_routeFactoryMock->expects($this->any())->method('createRoute')->will( @@ -181,7 +193,7 @@ class Mage_Webapi_Controller_FrontTest extends PHPUnit_Framework_TestCase public function testDeterminateApiTypeApiIsSet() { $this->_createMockForApiRouteAndFactory(array('api_type' => Mage_Webapi_Controller_Front::API_TYPE_SOAP)); - /** Assert createRoute method will be executed only once */ + /** Assert that createRoute method will be executed only once */ $this->_routeFactoryMock->expects($this->once())->method('createRoute'); /** The first method call will set apiType property using createRoute method. */ $this->_frontControllerMock->determineApiType(); diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/FactoryTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/FactoryTest.php index 89b3af60266..66a758c94a7 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/FactoryTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/FactoryTest.php @@ -1,6 +1,6 @@ <?php /** - * Test Webapi Json Interpreter Request Rest Controller + * Test Webapi Json Interpreter Request Rest Controller. * * Magento * diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/JsonTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/JsonTest.php index 64371705a4a..8f444ef4b0e 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/JsonTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/JsonTest.php @@ -1,6 +1,6 @@ <?php /** - * Test Webapi Json Interpreter Request Rest Controller + * Test Webapi Json Interpreter Request Rest Controller. * * Magento * @@ -68,7 +68,7 @@ class Mage_Webapi_Controller_Request_Rest_Interpreter_JsonTest extends PHPUnit_F public function testInterpretInvalidArgumentException() { - $this->setExpectedException('InvalidArgumentException', 'Invalid data type "boolean". String is expected.'); + $this->setExpectedException('InvalidArgumentException', '"boolean" data type is invalid. String is expected.'); $this->_jsonInterpreter->interpret(false); } @@ -91,7 +91,7 @@ class Mage_Webapi_Controller_Request_Rest_Interpreter_JsonTest extends PHPUnit_F $this->assertEquals( $expectedDecodedJson, $this->_jsonInterpreter->interpret($inputEncodedJson), - 'Invalid interpretation from json to array.' + 'Interpretation from JSON to array is invalid.' ); } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/XmlTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/XmlTest.php index 4588d164aeb..2d34455a7e3 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/XmlTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/Rest/Interpreter/XmlTest.php @@ -77,7 +77,7 @@ class Mage_Webapi_Controller_Request_Rest_Interpreter_XmlTest extends PHPUnit_Fr public function testInterpretInvalidArgumentException() { - $this->setExpectedException('InvalidArgumentException', 'Invalid data type "boolean". String is expected.'); + $this->setExpectedException('InvalidArgumentException', '"boolean" data type is invalid. String is expected.'); $this->_xmlInterpreter->interpret(false); } @@ -93,7 +93,7 @@ class Mage_Webapi_Controller_Request_Rest_Interpreter_XmlTest extends PHPUnit_Fr $this->assertEquals( $expectedArray, $this->_xmlInterpreter->interpret($validInputXml), - 'Request xml body was parsed incorrectly into array of params' + 'Request XML body was parsed incorrectly into array of params.' ); } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/RestTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/RestTest.php index 8a25cf1e806..11391373c5f 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/RestTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/RestTest.php @@ -1,6 +1,6 @@ <?php /** - * Test Webapi Request model + * Test Webapi Request model. * * Magento * @@ -26,7 +26,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase { /** - * Request mock + * Request mock. * * @var PHPUnit_Framework_MockObject_MockObject */ @@ -64,7 +64,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase } /** - * Test for getAcceptTypes() method + * Test for getAcceptTypes() method. * * @dataProvider providerAcceptType * @param string $acceptHeader Value of Accept HTTP header @@ -127,7 +127,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase } /** - * Test for getContentType() method + * Test for getContentType() method. * * @dataProvider providerContentType * @param string $contentTypeHeader 'Content-Type' header value @@ -149,20 +149,20 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase $this->assertEquals( $exceptionMessage, $e->getMessage(), - 'Exception message does not match expected one' + 'Exception message does not match the expected one.' ); return; } else { - $this->fail('Exception thrown on valid header: ' . $e->getMessage()); + $this->fail('Exception is thrown on valid header: ' . $e->getMessage()); } } if ($exceptionMessage) { - $this->fail('Expected exception was not raised'); + $this->fail('Expected exception was not raised.'); } } /** - * Test for getOperation() method + * Test for getOperation() method. * * @dataProvider providerRequestMethod * @param string $requestMethod Request method @@ -200,20 +200,20 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase $this->assertEquals( $exceptionMessage, $e->getMessage(), - 'Exception message does not match expected one' + 'Exception message does not match the expected one.' ); return; } else { - $this->fail('Exception thrown on valid header: ' . $e->getMessage()); + $this->fail('Exception is thrown on valid header: ' . $e->getMessage()); } } if ($exceptionMessage) { - $this->fail('Expected exception was not raised'); + $this->fail('Expected exception was not raised.'); } } /** - * Test for getResourceType() method + * Test for getResourceType() method. * */ public function testGetResourceType() @@ -225,7 +225,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase } /** - * Data provider for testGetAcceptTypes() + * Data provider for testGetAcceptTypes(). * * @return array */ @@ -261,7 +261,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase } /** - * Data provider for testGetContentType() + * Data provider for testGetContentType(). * * @return array */ @@ -269,20 +269,20 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase { return array( // Each element is: array(Content-Type header value, content-type part[, expected exception message]) - array('', null, 'Content-Type header is empty'), - array('_?', null, 'Invalid Content-Type header'), + array('', null, 'Content-Type header is empty.'), + array('_?', null, 'Content-Type header is invalid.'), array('application/x-www-form-urlencoded; charset=UTF-8', 'application/x-www-form-urlencoded'), array('application/x-www-form-urlencoded; charset=utf-8', 'application/x-www-form-urlencoded'), array('text/html; charset=uTf-8', 'text/html'), - array('text/html; charset=', null, 'Invalid Content-Type header'), - array('text/html;', null, 'Invalid Content-Type header'), + array('text/html; charset=', null, 'Content-Type header is invalid.'), + array('text/html;', null, 'Content-Type header is invalid.'), array('application/dialog.dot-info7+xml', 'application/dialog.dot-info7+xml'), - array('application/x-www-form-urlencoded; charset=cp1251', null, 'UTF-8 is the only supported charset') + array('application/x-www-form-urlencoded; charset=cp1251', null, 'UTF-8 is the only supported charset.') ); } /** - * Data provider for testGetOperation() + * Data provider for testGetOperation(). * * @return array */ @@ -290,7 +290,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase { return array( // Each element is: array(Request method, CRUD operation name[, expected exception message]) - array('INVALID_METHOD', null, 'Invalid request method'), + array('INVALID_METHOD', null, 'Request method is invalid.'), array('GET', Mage_Webapi_Controller_Request_Rest::HTTP_METHOD_GET), array('POST', Mage_Webapi_Controller_Request_Rest::HTTP_METHOD_CREATE), array('PUT', Mage_Webapi_Controller_Request_Rest::HTTP_METHOD_UPDATE), @@ -394,7 +394,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase } /** - * Success getOperationName() method data provider + * Success getOperationName() method data provider. * * @return array */ @@ -444,7 +444,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase $this->assertEquals( 'resourceNameCreate', $this->_request->getOperationName(), - 'Invalid resource name for create method.' + 'Resource name for create method is invalid.' ); } @@ -462,7 +462,7 @@ class Mage_Webapi_Controller_Request_RestTest extends PHPUnit_Framework_TestCase $this->assertEquals( 'resourceNameMultiCreate', $this->_request->getOperationName(), - 'Invalid resource name for multi create method.' + 'Resource name for multi create method is invalid.' ); } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/SoapTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/SoapTest.php index d4f8e4a45a7..89ff95abc6e 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/SoapTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Request/SoapTest.php @@ -1,6 +1,6 @@ <?php /** - * Soap API Request Test. + * SOAP API Request Test. * * Magento * @@ -60,7 +60,7 @@ class Mage_Webapi_Controller_Request_SoapTest extends PHPUnit_Framework_TestCase 'param_1' => 'foo', 'param_2' => 'bar', $wsdlParam => true, - Mage_Webapi_Controller_Router_Route_Webapi::PARAM_API_TYPE => true, + Mage_Webapi_Controller_Request::PARAM_API_TYPE => true, $resourcesParam => true ); $this->_soapRequest->setParams($requestParams); @@ -106,7 +106,7 @@ class Mage_Webapi_Controller_Request_SoapTest extends PHPUnit_Framework_TestCase $requestParams = array( Mage_Webapi_Model_Soap_Server::REQUEST_PARAM_WSDL => true, Mage_Webapi_Model_Soap_Server::REQUEST_PARAM_RESOURCES => $resources, - Mage_Webapi_Controller_Router_Route_Webapi::PARAM_API_TYPE => 'soap' + Mage_Webapi_Controller_Request::PARAM_API_TYPE => 'soap' ); $this->_soapRequest->setParams($requestParams); /** Execute SUT. */ diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/RequestTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/RequestTest.php index 0a65d90d599..85524bcda48 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/RequestTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/RequestTest.php @@ -26,7 +26,7 @@ class Mage_Webapi_Controller_RequestTest extends PHPUnit_Framework_TestCase { /** - * Request object + * Request object. * * @var Mage_Webapi_Controller_Request */ @@ -40,7 +40,7 @@ class Mage_Webapi_Controller_RequestTest extends PHPUnit_Framework_TestCase } /** - * Test for getFilter() method + * Test for getFilter() method. */ public function testGetFilter() { @@ -55,7 +55,7 @@ class Mage_Webapi_Controller_RequestTest extends PHPUnit_Framework_TestCase } /** - * Test for getOrderDirection() method + * Test for getOrderDirection() method. */ public function testGetOrderDirection() { @@ -70,7 +70,7 @@ class Mage_Webapi_Controller_RequestTest extends PHPUnit_Framework_TestCase } /** - * Test for getOrderField() method + * Test for getOrderField() method. */ public function testGetOrderField() { @@ -85,7 +85,7 @@ class Mage_Webapi_Controller_RequestTest extends PHPUnit_Framework_TestCase } /** - * Test for getPageNumber() method + * Test for getPageNumber() method. */ public function testGetPageNumber() { @@ -100,7 +100,7 @@ class Mage_Webapi_Controller_RequestTest extends PHPUnit_Framework_TestCase } /** - * Test for getPageSize() method + * Test for getPageSize() method. */ public function testGetPageSize() { @@ -113,7 +113,7 @@ class Mage_Webapi_Controller_RequestTest extends PHPUnit_Framework_TestCase } /** - * Test for getRequestedAttributes() method + * Test for getRequestedAttributes() method. */ public function testGetRequestedAttributes() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/FactoryTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/FactoryTest.php index 496b9ff9836..70189fd5a2b 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/FactoryTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/FactoryTest.php @@ -55,26 +55,26 @@ class Mage_Webapi_Controller_Response_FactoryTest extends PHPUnit_Framework_Test } /** - * Test get method. + * Test GET method. */ public function testGet() { - /** Mock front controller mock to return Soap api type. */ + /** Mock front controller mock to return SOAP API type. */ $this->_apiFrontController->expects($this->once())->method('determineApiType')->will( $this->returnValue(Mage_Webapi_Controller_Front::API_TYPE_SOAP) ); - /** Assert object manager get method will be executed once with Mage_Webapi_Controller_Response parameter. */ + /** Assert that object manager get() will be executed once with Mage_Webapi_Controller_Response parameter. */ $this->_objectManager->expects($this->once())->method('get')->with('Mage_Webapi_Controller_Response'); $this->_factory->get(); } /** - * Test get method with wrong API type. + * Test GET method with wrong API type. */ public function testGetWithWrongApiType() { $wrongApiType = 'Wrong SOAP'; - /**Mock front controller determine api method to return wrong api type */ + /**Mock front controller determine API method to return wrong API type */ $this->_apiFrontController->expects($this->once())->method('determineApiType')->will( $this->returnValue($wrongApiType) ); diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/FactoryTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/FactoryTest.php index 2e4313d5121..4a2afa1f19b 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/FactoryTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/FactoryTest.php @@ -71,7 +71,7 @@ class Mage_Webapi_Controller_Response_Rest_Renderer_FactoryTest extends PHPUnit_ } /** - * Test get method. + * Test GET method. */ public function testGet() { @@ -96,7 +96,7 @@ class Mage_Webapi_Controller_Response_Rest_Renderer_FactoryTest extends PHPUnit_ protected function _createConfigElementForRenders() { - /** Xml with the list of renders types and models. */ + /** XML with the list of renders types and models. */ $rendersXml = <<<XML <renders> <default> @@ -114,7 +114,7 @@ XML; } /** - * Test get method with wrong Accept Http Header. + * Test GET method with wrong Accept HTTP Header. */ public function testGetWithWrongAcceptHttpHeader() { @@ -129,7 +129,7 @@ XML; } /** - * Test get method with wrong Renderer class. + * Test GET method with wrong Renderer class. */ public function testGetWithWrongRendererClass() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/JsonTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/JsonTest.php index 5102307865a..ce67726aea4 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/JsonTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/JsonTest.php @@ -1,6 +1,6 @@ <?php /** - * Test Json Renderer for REST. + * Test JSON Renderer for REST. * * Magento * @@ -50,18 +50,18 @@ class Mage_Webapi_Controller_Response_Rest_Renderer_JsonTest extends PHPUnit_Fra } /** - * Test render method + * Test render method. */ public function testRender() { $arrayToRender = array('key' => 'value'); - /** Assert jsonEncode method in mocked helper will run once */ + /** Assert that jsonEncode method in mocked helper will run once */ $this->_helperMock->expects($this->once())->method('jsonEncode'); $this->_restJsonRenderer->render($arrayToRender); } /** - * Test GetMimeType method + * Test GetMimeType method. */ public function testGetMimeType() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/XmlTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/XmlTest.php index f49d0718c31..be76536c9a0 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/XmlTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/Rest/Renderer/XmlTest.php @@ -71,7 +71,7 @@ class Mage_Webapi_Controller_Response_Rest_Renderer_XmlTest extends PHPUnit_Fram public function providerXmlRender() { return array( - //Each array consist of data to render, expected XML and assert message + //Each array consists of data to render, expected XML and assert message array( array('value1', 'value2'), '<?xml version="1.0"?><response><item>value1</item><item>value2</item></response>', diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/RestTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/RestTest.php index 303f29f07ad..e276db7b714 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/RestTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Response/RestTest.php @@ -79,7 +79,7 @@ class Mage_Webapi_Controller_Response_RestTest extends PHPUnit_Framework_TestCas /** Init Mage_Webapi_Exception */ $apiException = new Mage_Webapi_Exception('Exception message.', 401); $this->_responseRest->setException($apiException); - /** Assert Mage_Webapi_Exception was set and presented in the list. */ + /** Assert that Mage_Webapi_Exception was set and presented in the list. */ $this->assertTrue( $this->_responseRest->hasExceptionOfType('Mage_Webapi_Exception'), 'Mage_Webapi_Exception was not set.' @@ -97,7 +97,7 @@ class Mage_Webapi_Controller_Response_RestTest extends PHPUnit_Framework_TestCas $this->_rendererMock->expects($this->any())->method('getMimeType')->will( $this->throwException($logicException) ); - /** Assert renderException method will be executed once with specified parameters. */ + /** Assert that renderException method will be executed once with specified parameters. */ $this->_errorProcessorMock->expects($this->once())->method('renderException')->with( $logicException, Mage_Webapi_Exception::HTTP_INTERNAL_ERROR @@ -108,7 +108,7 @@ class Mage_Webapi_Controller_Response_RestTest extends PHPUnit_Framework_TestCas } /** - * Test sendResponse method with Http Not Acceptable error exception during messages rendering. + * Test sendResponse method with HTTP Not Acceptable error exception during messages rendering. */ public function testSendResponseRenderMessagesHttpNotAcceptable() { @@ -118,7 +118,7 @@ class Mage_Webapi_Controller_Response_RestTest extends PHPUnit_Framework_TestCas $this->_rendererMock->expects($this->any())->method('getMimeType')->will( $this->throwException($logicException) ); - /** Assert renderException method will be executed once with specified parameters. */ + /** Assert that renderException method will be executed once with specified parameters. */ $this->_errorProcessorMock->expects($this->once())->method('renderException')->with( $logicException, Mage_Webapi_Exception::HTTP_NOT_ACCEPTABLE @@ -199,12 +199,12 @@ class Mage_Webapi_Controller_Response_RestTest extends PHPUnit_Framework_TestCas 'Mage_Webapi_Exception' => array( new Mage_Webapi_Exception('Message', 400), '{"messages":{"error":[{"code":400,"message":"Message"}]}}', - 'Wrong response sending with Mage_Webapi_Exception' + 'Response sending with Mage_Webapi_Exception is invalid' ), 'Logical Exception' => array( new LogicException('Message', 100), '{"messages":{"error":[{"code":500,"message":"Message"}]}}', - 'Wrong response sending with Logical Exception' + 'Response sending with Logical Exception is invalid' ), ); } @@ -220,12 +220,12 @@ class Mage_Webapi_Controller_Response_RestTest extends PHPUnit_Framework_TestCas 'Mage_Webapi_Exception' => array( new Mage_Webapi_Exception('Message', 400), '{"messages":{"error":[{"code":400,"message":"Message","trace":"', - 'Wrong response sending with Mage_Webapi_Exception in developer mode' + 'Response sending with Mage_Webapi_Exception in developer mode is invalid' ), 'Logical Exception' => array( new LogicException('Message'), '{"messages":{"error":[{"code":500,"message":"Message","trace":"', - 'Wrong response sending with Logical Exception in developer mode' + 'Response sending with Logical Exception in developer mode is invalid' ), ); } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/ResponseTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/ResponseTest.php index 186f852018e..40efbdbc707 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/ResponseTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/ResponseTest.php @@ -59,16 +59,16 @@ class Mage_Webapi_Controller_ResponseTest extends PHPUnit_Framework_TestCase ), ); $actualHeader = $this->_response->setMimeType('application/xml')->getHeaders(); - /** Assert headers are equal */ + /** Assert that headers are equal */ $this->assertEquals($expectedHeader, $actualHeader, 'Mime type is not set.'); } /** - * Test addMessage, hasMessage, getMessage and clearMessages methods. + * Test addMessage, hasMessage, getMessage, and clearMessages methods. */ public function testMessagesCrud() { - /** Test new object does not contain any messages. */ + /** Test that new object does not contain any messages. */ $this->assertFalse($this->_response->hasMessages(), 'New object contains messages.'); /** Test message adding functionality. */ @@ -78,7 +78,7 @@ class Mage_Webapi_Controller_ResponseTest extends PHPUnit_Framework_TestCase array('key' => 'value'), Mage_Webapi_Controller_Response::MESSAGE_TYPE_SUCCESS ); - $this->assertTrue($this->_response->hasMessages(), 'New message is not added right.'); + $this->assertTrue($this->_response->hasMessages(), 'New message is not added correctly.'); /** Test message getting functionality. */ $expectedMessage = array( @@ -86,7 +86,7 @@ class Mage_Webapi_Controller_ResponseTest extends PHPUnit_Framework_TestCase array('key' => 'value', 'message' => 'Message text', 'code' => 200) ) ); - $this->assertEquals($expectedMessage, $this->_response->getMessages(), 'Message is got wrong.'); + $this->assertEquals($expectedMessage, $this->_response->getMessages(), 'Message is got incorrectly.'); /** Test message clearing functionality. */ $this->_response->clearMessages(); diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/Route/RestTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/Route/RestTest.php index 58c8b331d81..44f4d5d9921 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/Route/RestTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/Route/RestTest.php @@ -46,12 +46,12 @@ class Mage_Webapi_Controller_Router_Route_RestTest extends PHPUnit_Framework_Tes */ public function testResourceName() { - /** Assert new object has no Resource name set. */ - $this->assertNull($this->_restRoute->getResourceName(), 'New object has an set Resource name.'); + /** Assert that new object has no Resource name set. */ + $this->assertNull($this->_restRoute->getResourceName(), 'New object has a set Resource name.'); /** Set Resource name. */ $resourceName = 'Resource name'; $this->_restRoute->setResourceName($resourceName); - /** Assert Resource name was set. */ + /** Assert that Resource name was set. */ $this->assertEquals($resourceName, $this->_restRoute->getResourceName(), 'Resource name is wrong.'); } @@ -60,12 +60,12 @@ class Mage_Webapi_Controller_Router_Route_RestTest extends PHPUnit_Framework_Tes */ public function testResourceType() { - /** Assert new object has no Resource type set. */ - $this->assertNull($this->_restRoute->getResourceType(), 'New object has an set Resource type.'); + /** Assert that new object has no Resource type set. */ + $this->assertNull($this->_restRoute->getResourceType(), 'New object has a set Resource type.'); /** Set Resource type. */ $resourceType = 'Resource type'; $this->_restRoute->setResourceType($resourceType); - /** Assert Resource type was set. */ + /** Assert that Resource type was set. */ $this->assertEquals($resourceType, $this->_restRoute->getResourceType(), 'Resource type is wrong.'); } } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/Route/ApiTypeTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/RouteTest.php similarity index 78% rename from dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/Route/ApiTypeTest.php rename to dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/RouteTest.php index a84868ecaaf..b86e93ea7fd 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/Route/ApiTypeTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Controller/Router/RouteTest.php @@ -25,15 +25,17 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -class Mage_Webapi_Controller_Router_Route_WebapiTest extends PHPUnit_Framework_TestCase +class Mage_Webapi_Controller_Router_RouteTest extends PHPUnit_Framework_TestCase { public function testMatch() { - $route = new Mage_Webapi_Controller_Router_Route_Webapi( - Mage_Webapi_Controller_Router_Route_Webapi::getApiRoute()); + $areaName = 'webapi'; + $route = new Mage_Webapi_Controller_Router_Route( + $areaName . '/:' . Mage_Webapi_Controller_Request::PARAM_API_TYPE + ); $testApiType = 'test_api'; - $testUri = str_replace(':api_type', $testApiType, Mage_Webapi_Controller_Router_Route_Webapi::getApiRoute()); + $testUri = "$areaName/$testApiType"; $request = new Zend_Controller_Request_Http(); $request->setRequestUri($testUri); diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/FactoryTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/FactoryTest.php index 8243e10e3ec..77184718fd2 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/FactoryTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/FactoryTest.php @@ -1,6 +1,6 @@ <?php /** - * Test class for Mage_Webapi_Model_Acl_Role_Factory + * Test class for Mage_Webapi_Model_Acl_Role_Factory. * * Magento * @@ -59,7 +59,7 @@ class Mage_Webapi_Model_Acl_Role_FactoryTest extends PHPUnit_Framework_TestCase } /** - * Test create method + * Test create method. */ public function testCreate() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/InRoleUserUpdaterTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/InRoleUserUpdaterTest.php index 885d38fc410..223cd2d48e8 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/InRoleUserUpdaterTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/Role/InRoleUserUpdaterTest.php @@ -1,6 +1,6 @@ <?php /** - * Test class for Mage_Webapi_Model_Acl_Role_InRoleUserUpdater + * Test class for Mage_Webapi_Model_Acl_Role_InRoleUserUpdater. * * Magento * diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RoleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RoleTest.php index 329f8141184..d3040ea4200 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RoleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RoleTest.php @@ -66,7 +66,7 @@ class Mage_Webapi_Model_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Create Role model + * Create Role model. * * @param Mage_Webapi_Model_Resource_Acl_Role $roleResource * @param Mage_Webapi_Model_Resource_Acl_Role_Collection $resourceCollection @@ -83,7 +83,7 @@ class Mage_Webapi_Model_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test constructor + * Test constructor. */ public function testConstructor() { @@ -94,7 +94,7 @@ class Mage_Webapi_Model_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Test get collection and _construct + * Test GET collection and _construct */ public function testGetCollection() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RuleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RuleTest.php index e5ffbe455f9..742016a500c 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RuleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/RuleTest.php @@ -66,7 +66,7 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Create Rule model + * Create Rule model. * * @param Mage_Webapi_Model_Resource_Acl_Rule|PHPUnit_Framework_MockObject_MockObject $ruleResource * @param Mage_Webapi_Model_Resource_Acl_User_Collection $resourceCollection @@ -83,7 +83,7 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Test constructor + * Test constructor. */ public function testConstructor() { @@ -94,7 +94,7 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Test method getRoleUsers() + * Test getRoleUsers() method. */ public function testGetRoleUsers() { @@ -109,7 +109,7 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase } /** - * Test get collection and _construct + * Test GET collection and _construct */ public function testGetCollection() { @@ -131,13 +131,13 @@ class Mage_Webapi_Model_Acl_RuleTest extends PHPUnit_Framework_TestCase $model = $this->_createModel($this->_ruleResource, $collection); - // test _construct + // Test _construct $result = $model->getCollection(); $this->assertAttributeEquals('Mage_Webapi_Model_Acl_Rule', '_model', $result); $this->assertAttributeEquals('Mage_Webapi_Model_Resource_Acl_Rule', '_resourceModel', $result); - // test getByRole + // Test getByRole $resultColl = $result->getByRole(1); $this->assertInstanceOf('Mage_Webapi_Model_Resource_Acl_Rule_Collection', $resultColl); } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/User/FactoryTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/User/FactoryTest.php index 0c9a2fb783d..b5528f2bd34 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/User/FactoryTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/User/FactoryTest.php @@ -59,7 +59,7 @@ class Mage_Webapi_Model_Acl_User_FactoryTest extends PHPUnit_Framework_TestCase } /** - * Test create method + * Test create method. */ public function testCreate() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/UserTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/UserTest.php index f1258d3906d..b3e97f53964 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/UserTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Acl/UserTest.php @@ -66,7 +66,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Create User model + * Create User model. * * @param Mage_Webapi_Model_Resource_Acl_User $userResource * @param Mage_Webapi_Model_Resource_Acl_User_Collection $resourceCollection @@ -83,7 +83,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Test constructor + * Test constructor. */ public function testConstructor() { @@ -94,7 +94,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Test method getRoleUsers() + * Test getRoleUsers() method. */ public function testGetRoleUsers() { @@ -111,7 +111,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Test method loadByKey() + * Test loadByKey() method. */ public function testLoadByKey() { @@ -127,7 +127,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Test public getters + * Test public getters. */ public function testPublicGetters() { @@ -140,7 +140,7 @@ class Mage_Webapi_Model_Acl_UserTest extends PHPUnit_Framework_TestCase } /** - * Test get collection and _construct + * Test GET collection and _construct */ public function testGetCollection() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Config/ReaderTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Config/ReaderTest.php index 3c80c106904..9006aecb4e5 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Config/ReaderTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Config/ReaderTest.php @@ -54,7 +54,7 @@ class Mage_Webapi_Model_Authorization_Config_ReaderTest extends PHPUnit_Framewor } /** - * Unset reader instance + * Unset reader instance. */ protected function tearDown() { @@ -63,7 +63,7 @@ class Mage_Webapi_Model_Authorization_Config_ReaderTest extends PHPUnit_Framewor } /** - * Check that correct xsd file is provided + * Check that correct XSD file is provided. */ public function testGetSchemaFile() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/ConfigTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/ConfigTest.php index bb75a1490ae..c85263a87b2 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/ConfigTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/ConfigTest.php @@ -46,7 +46,7 @@ class Mage_Webapi_Model_Authorization_ConfigTest extends PHPUnit_Framework_TestC protected $_config; /** - * Set up before test + * Set up before test. */ protected function setUp() { @@ -82,7 +82,7 @@ class Mage_Webapi_Model_Authorization_ConfigTest extends PHPUnit_Framework_TestC } /** - * Test for Mage_Webapi_Model_Authorization_Config::getAclResources() + * Test for Mage_Webapi_Model_Authorization_Config::getAclResources(). */ public function testGetAclResources() { @@ -111,7 +111,7 @@ class Mage_Webapi_Model_Authorization_ConfigTest extends PHPUnit_Framework_TestC } /** - * Get resources array recursively + * Get resources array recursively. * * @param DOMNodeList $resources * @return array @@ -133,7 +133,7 @@ class Mage_Webapi_Model_Authorization_ConfigTest extends PHPUnit_Framework_TestC } /** - * Test for Mage_Webapi_Model_Authorization_Config::getAclVirtualResources + * Test for Mage_Webapi_Model_Authorization_Config::getAclVirtualResources. */ public function testGetAclVirtualResources() { @@ -167,7 +167,7 @@ class Mage_Webapi_Model_Authorization_ConfigTest extends PHPUnit_Framework_TestC } /** - * Test for Mage_Webapi_Model_Authorization_Config::getAclResourcesAsArray + * Test for Mage_Webapi_Model_Authorization_Config::getAclResourcesAsArray. * * @dataProvider aclResourcesDataProvider * @param string $actualXmlFile @@ -244,7 +244,7 @@ class Mage_Webapi_Model_Authorization_ConfigTest extends PHPUnit_Framework_TestC } /** - * Test for method _getSortedBySortOrder + * Test for _getSortedBySortOrder method. * * @dataProvider getSortedBySortOrderDataProvider * @param array $originArray diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/ResourceTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/ResourceTest.php index cba83036b14..b67d2dbbbed 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/ResourceTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/ResourceTest.php @@ -46,7 +46,7 @@ class Mage_Webapi_Model_Authorization_Loader_ResourceTest extends PHPUnit_Framew protected $_config; /** - * Set up before test + * Set up before test. */ protected function setUp() { @@ -77,7 +77,7 @@ class Mage_Webapi_Model_Authorization_Loader_ResourceTest extends PHPUnit_Framew } /** - * Test for Mage_Webapi_Model_Authorization_Loader_Resource::populateAcl + * Test for Mage_Webapi_Model_Authorization_Loader_Resource::populateAcl. */ public function testPopulateAcl() { @@ -105,7 +105,7 @@ class Mage_Webapi_Model_Authorization_Loader_ResourceTest extends PHPUnit_Framew } /** - * Test for Mage_Webapi_Model_Authorization_Loader_Resource::populateAcl with invalid Virtual resources DOM + * Test for Mage_Webapi_Model_Authorization_Loader_Resource::populateAcl with invalid Virtual resources DOM. */ public function testPopulateAclWithInvalidDOM() { @@ -124,7 +124,7 @@ class Mage_Webapi_Model_Authorization_Loader_ResourceTest extends PHPUnit_Framew } /** - * Get Resources DOMXPath from fixture + * Get Resources DOMXPath from fixture. * * @return DOMXPath */ diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RoleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RoleTest.php index 62217937fc3..8f95375b4b7 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RoleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RoleTest.php @@ -46,7 +46,7 @@ class Mage_Webapi_Model_Authorization_Loader_RoleTest extends PHPUnit_Framework_ protected $_acl; /** - * Set up before test + * Set up before test. */ protected function setUp() { @@ -68,9 +68,9 @@ class Mage_Webapi_Model_Authorization_Loader_RoleTest extends PHPUnit_Framework_ } /** - * Test for Mage_Webapi_Model_Authorization_Loader_Role::populateAcl + * Test for Mage_Webapi_Model_Authorization_Loader_Role::populateAcl. * - * Test with existing role Ids + * Test with existing role IDs. */ public function testPopulateAclWithRoles() { @@ -101,9 +101,9 @@ class Mage_Webapi_Model_Authorization_Loader_RoleTest extends PHPUnit_Framework_ } /** - * Test for Mage_Webapi_Model_Authorization_Loader_Role::populateAcl + * Test for Mage_Webapi_Model_Authorization_Loader_Role::populateAcl. * - * Test with No existing role Ids + * Test with No existing role IDs. */ public function testPopulateAclWithNoRoles() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RuleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RuleTest.php index 8f04a84accb..c63127754a0 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RuleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Authorization/Loader/RuleTest.php @@ -58,7 +58,7 @@ class Mage_Webapi_Model_Authorization_Loader_RuleTest extends PHPUnit_Framework_ } /** - * Test for Mage_Webapi_Model_Authorization_Loader_Rule::populateAcl + * Test for Mage_Webapi_Model_Authorization_Loader_Rule::populateAcl. */ public function testPopulateAcl() { @@ -97,7 +97,7 @@ class Mage_Webapi_Model_Authorization_Loader_RuleTest extends PHPUnit_Framework_ } /** - * Test for Mage_Webapi_Model_Authorization_Loader_Rule::populateAcl without rules + * Test for Mage_Webapi_Model_Authorization_Loader_Rule::populateAcl without rules. */ public function testPopulateAclWithoutRules() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php index d4124a66d56..e9621c509b1 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RoleTest.php @@ -26,7 +26,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends Mage_Webapi_Model_Resource_Acl_TestAbstract { /** - * Create resource model + * Create resource model. * * @param Varien_Db_Select $selectMock * @return Mage_Webapi_Model_Resource_Acl_Role @@ -80,7 +80,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends Mage_Webapi_Model_Resource } /** - * Test constructor + * Test constructor. */ public function testConstructor() { @@ -91,7 +91,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends Mage_Webapi_Model_Resource } /** - * Test _initUniqueFields() + * Test _initUniqueFields(). */ public function testGetUniqueFields() { @@ -102,7 +102,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends Mage_Webapi_Model_Resource } /** - * Test getRolesList() + * Test getRolesList(). */ public function testGetRolesList() { @@ -127,7 +127,7 @@ class Mage_Webapi_Model_Resource_Acl_RoleTest extends Mage_Webapi_Model_Resource } /** - * Test getRolesIds() + * Test getRolesIds(). */ public function testGetRolesIds() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php index c0108298a67..0e194f91a33 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/RuleTest.php @@ -26,7 +26,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource_Acl_TestAbstract { /** - * Create resource model + * Create resource model. * * @param Varien_Db_Select $selectMock * @return Mage_Webapi_Model_Resource_Acl_Rule @@ -86,7 +86,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource } /** - * Test constructor + * Test constructor. */ public function testConstructor() { @@ -97,7 +97,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource } /** - * Test getRuleList() + * Test getRuleList(). */ public function testGetRuleList() { @@ -117,7 +117,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource } /** - * Test getResourceIdsByRole() + * Test getResourceIdsByRole(). */ public function testGetResourceIdsByRole() { @@ -142,11 +142,11 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource } /** - * Test saveResources() + * Test saveResources(). */ public function testSaveResources() { - // init rule resource + // Init rule resource. $ruleResource = $this->getMockBuilder('Mage_Webapi_Model_Resource_Acl_Rule') ->disableOriginalConstructor() ->setMethods(array('saveResources', 'getIdFieldName', 'getReadConnection', 'getResources')) @@ -162,7 +162,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource ->withAnyParameters() ->will($this->returnValue($this->getMock('Varien_Db_Adapter_Pdo_Mysql', array(), array(), '', false))); - // init rule + // Init rule. $rule = $this->getMockBuilder('Mage_Webapi_Model_Acl_Rule') ->setConstructorArgs(array( 'eventDispatcher' => $this->getMock('Mage_Core_Model_Event_Manager', array(), array(), '', false), @@ -179,7 +179,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource $model = $this->_createModel(); - // init adapter + // Init adapter. $this->_adapter->expects($this->any()) ->method('delete') ->withAnyParameters() @@ -194,7 +194,7 @@ class Mage_Webapi_Model_Resource_Acl_RuleTest extends Mage_Webapi_Model_Resource $rule->setRoleId(1); $model->saveResources($rule); - // init adapter + // Init adapter. $this->_adapter->expects($this->any()) ->method('delete') ->withAnyParameters() diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/UserTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/UserTest.php index 30003fdd3ea..e49ecdf0603 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/UserTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Resource/Acl/UserTest.php @@ -26,7 +26,7 @@ class Mage_Webapi_Model_Resource_Acl_UserTest extends Mage_Webapi_Model_Resource_Acl_TestAbstract { /** - * Create resource model + * Create resource model. * * @param Varien_Db_Select $selectMock * @return Mage_Webapi_Model_Resource_Acl_User @@ -75,7 +75,7 @@ class Mage_Webapi_Model_Resource_Acl_UserTest extends Mage_Webapi_Model_Resource } /** - * Test constructor + * Test constructor. */ public function testConstructor() { @@ -86,7 +86,7 @@ class Mage_Webapi_Model_Resource_Acl_UserTest extends Mage_Webapi_Model_Resource } /** - * Test _initUniqueFields() + * Test _initUniqueFields(). */ public function testGetUniqueFields() { @@ -97,7 +97,7 @@ class Mage_Webapi_Model_Resource_Acl_UserTest extends Mage_Webapi_Model_Resource } /** - * Test getRoleUsers() + * Test getRoleUsers(). */ public function testGetRoleUsers() { diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Rest/Oauth/ServerTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Rest/Oauth/ServerTest.php index 22ed8a88245..e01a6b9d5e5 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Rest/Oauth/ServerTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Rest/Oauth/ServerTest.php @@ -1,6 +1,6 @@ <?php /** - * Two-legged oAuth server test. + * Two-legged OAuth server test. * * Magento * @@ -66,14 +66,14 @@ class Mage_Webapi_Model_Rest_Oauth_ServerTest extends PHPUnit_Framework_TestCase } /** - * Test two legged authentication + * Test two-legged authentication */ public function testAuthenticateTwoLegged() { $testUserKey = 'foo_user'; $testUserSecret = 'bar_secret'; $testUrl = 'http://foo.bar/api/rest/v1/baz'; - // Prepare signature and oAuth parameters + // Prepare signature and OAuth parameters. $utility = new Zend_Oauth_Http_Utility(); $params = array( 'oauth_consumer_key' => $testUserKey, diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php index 1b58c2199a2..cb0e5020710 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/AutoDiscoverTest.php @@ -160,20 +160,20 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Test handle method with loading wsdl from cache. + * Test handle method with loading WSDL from cache. */ public function testHandleLoadWsdlFromCache() { /** Mock cache canUse method to return true. */ $this->_cacheMock->expects($this->once())->method('canUse')->will($this->returnValue(true)); - /** Mock cache load method to return cache Id. */ + /** Mock cache load method to return cache ID. */ $this->_cacheMock->expects($this->once())->method('load')->will($this->returnArgument(0)); $requestedResources = array( 'res1' => 'v1', 'res2' => 'v2' ); $result = $this->_autoDiscover->handle($requestedResources, 'http://magento.host'); - /** Assert handle method will return string that starts with WSDL. */ + /** Assert that handle method will return string that starts with WSDL. */ $this->assertStringStartsWith( Mage_Webapi_Model_Soap_AutoDiscover::WSDL_CACHE_ID, $result, @@ -202,7 +202,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Data provider for generate() test + * Data provider for generate() test. * * @return array */ @@ -274,7 +274,7 @@ class Mage_Webapi_Model_Soap_AutoDiscoverTest extends PHPUnit_Framework_TestCase } /** - * Create mock for DOMElement + * Create mock for DOMElement. * * @return PHPUnit_Framework_MockObject_MockObject */ diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/FaultTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/FaultTest.php index b2d146ab456..ff742cce490 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/FaultTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/FaultTest.php @@ -62,14 +62,14 @@ XML; $this->assertXmlStringEqualsXmlString( $expectedResult, $actualXml, - 'Wrong soap fault message with default parameters.' + 'Wrong SOAP fault message with default parameters.' ); } public function testToXmlDeveloperModeOn() { $actualXml = $this->_soapFault->toXml(true); - $this->assertContains('<ExceptionTrace>', $actualXml, 'Exception trace not found in XML.'); + $this->assertContains('<ExceptionTrace>', $actualXml, 'Exception trace is not found in XML.'); } /** @@ -101,17 +101,17 @@ XML; */ public function dataProviderForGetSoapFaultMessageTest() { - /** Include file with all expected soap fault XMLs. */ + /** Include file with all expected SOAP fault XMLs. */ $expectedXmls = include __DIR__ . '/../../_files/soap_fault/soap_fault_expected_xmls.php'; return array( - //Each array contains data for SOAP Fault Message, Expected XML and Assert Message. + //Each array contains data for SOAP Fault Message, Expected XML, and Assert Message. array( 'Fault reason', 'Sender', 'cn', array('key1' => 'value1', 'key2' => 'value2'), $expectedXmls['expectedResultArrayDataDetails'], - 'Wrong soap fault message with associated array data details.' + 'SOAP fault message with associated array data details is invalid.' ), array( 'Fault reason', @@ -119,7 +119,7 @@ XML; 'en', array('value1', 'value2'), $expectedXmls['expectedResultIndexArrayDetails'], - 'Wrong soap fault message with index array data details.' + 'SOAP fault message with index array data details is invalid.' ), array( 'Fault reason', @@ -127,7 +127,7 @@ XML; 'en', array(), $expectedXmls['expectedResultEmptyArrayDetails'], - 'Wrong soap fault message with empty array data details.' + 'SOAP fault message with empty array data details is invalid.' ), array( 'Fault reason', @@ -135,7 +135,7 @@ XML; 'en', (object)array('key' => 'value'), $expectedXmls['expectedResultObjectDetails'], - 'Wrong soap fault message with object data details.' + 'SOAP fault message with object data details is invalid.' ), array( 'Fault reason', @@ -143,7 +143,7 @@ XML; 'en', 'String details', $expectedXmls['expectedResultStringDetails'], - 'Wrong soap fault message with string data details.' + 'SOAP fault message with string data details is invalid.' ), array( 'Fault reason', @@ -151,7 +151,7 @@ XML; 'en', array('key' => array('sub_key' => 'value')), $expectedXmls['expectedResultComplexDataDetails'], - 'Wrong soap fault message with complex data details.' + 'SOAP fault message with complex data details is invalid.' ), ); } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php index dd072623f37..007d2324c94 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Security/UsernameTokenTest.php @@ -52,7 +52,7 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor { $this->_nonceStorageMock = $this->getMockBuilder('Mage_Webapi_Model_Soap_Security_UsernameToken_NonceStorage') ->disableOriginalConstructor() - ->setConstructorArgs(array('validateNonce')) + ->setMethods(array('validateNonce')) ->getMock(); $this->_userMock = $this->getMockBuilder('Mage_Webapi_Model_Acl_User') ->disableOriginalConstructor() @@ -119,7 +119,7 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor } /** - * Data provider for testConstructNewUsernameToken + * Data provider for testConstructNewUsernameToken. * * @return array */ @@ -154,7 +154,7 @@ class Mage_Webapi_Model_Soap_Security_UsernameTokenTest extends PHPUnit_Framewor } /** - * Data provider for testConstructNewUsernameTokenWithInvalidCreatedDate + * Data provider for testConstructNewUsernameTokenWithInvalidCreatedDate. * * @return array */ diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/ServerTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/ServerTest.php index 2f9441f02b2..ab29dd0c223 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/ServerTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/ServerTest.php @@ -25,15 +25,20 @@ */ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase { + const WEBAPI_AREA_FRONT_NAME = 'webapi'; + /** @var Mage_Webapi_Model_Soap_Server */ protected $_soapServer; /** @var Mage_Core_Model_App */ - protected $_applicationMock; + protected $_appMock; /** @var Mage_Core_Model_Store */ protected $_storeMock; + /** @var Mage_Core_Model_Config */ + protected $_configMock; + /** @var Mage_Webapi_Controller_Request_Soap */ protected $_requestMock; @@ -44,8 +49,13 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase { /** Init all dependencies for SUT. */ $this->_storeMock = $this->getMockBuilder('Mage_Core_Model_Store')->disableOriginalConstructor()->getMock(); - $this->_applicationMock = $this->getMockBuilder('Mage_Core_Model_App')->disableOriginalConstructor()->getMock(); - $this->_applicationMock->expects($this->any())->method('getStore')->will($this->returnValue($this->_storeMock)); + $this->_configMock = $this->getMockBuilder('Mage_Core_Model_Config')->disableOriginalConstructor()->getMock(); + $this->_configMock->expects($this->any())->method('getAreaFrontName')->will( + $this->returnValue(self::WEBAPI_AREA_FRONT_NAME) + ); + $this->_appMock = $this->getMockBuilder('Mage_Core_Model_App')->disableOriginalConstructor()->getMock(); + $this->_appMock->expects($this->any())->method('getStore')->will($this->returnValue($this->_storeMock)); + $this->_appMock->expects($this->any())->method('getConfig')->will($this->returnValue($this->_configMock)); $this->_requestMock = $this->getMockBuilder('Mage_Webapi_Controller_Request_Soap')->disableOriginalConstructor() ->getMock(); $this->_domDocumentFactory = $this->getMockBuilder('Magento_DomDocument_Factory') @@ -53,7 +63,7 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase /** Init SUT. */ $this->_soapServer = new Mage_Webapi_Model_Soap_Server( - $this->_applicationMock, + $this->_appMock, $this->_requestMock, $this->_domDocumentFactory ); @@ -64,7 +74,7 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase protected function tearDown() { unset($this->_soapServer); - unset($this->_applicationMock); + unset($this->_appMock); unset($this->_requestMock); unset($this->_storeMock); parent::tearDown(); @@ -76,7 +86,11 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase public function testGetApiCharset() { $this->_storeMock->expects($this->once())->method('getConfig')->will($this->returnValue('Windows-1251')); - $this->assertEquals('Windows-1251', $this->_soapServer->getApiCharset(), 'Wrong API charset encoding getting.'); + $this->assertEquals( + 'Windows-1251', + $this->_soapServer->getApiCharset(), + 'API charset encoding getting is invalid.' + ); } /** @@ -88,7 +102,7 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase $this->assertEquals( Mage_Webapi_Model_Soap_Server::SOAP_DEFAULT_ENCODING, $this->_soapServer->getApiCharset(), - 'Wrong default API charset encoding getting.' + 'Default API charset encoding getting is invalid.' ); } @@ -104,8 +118,8 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase $this->returnValue(array('res' => 'v1')) ); $actualResult = $this->_soapServer->generateUri(); - $expectedResult = 'http://magento.com/api/soap?resources%5Bres%5D=v1'; - $this->assertEquals($expectedResult, $actualResult, 'Wrong URI generation with default parameter.'); + $expectedResult = 'http://magento.com/' . self::WEBAPI_AREA_FRONT_NAME . '/soap?resources%5Bres%5D=v1'; + $this->assertEquals($expectedResult, $actualResult, 'URI generation with default parameter is invalid.'); } /** @@ -133,10 +147,10 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase $this->_storeMock->expects($this->once())->method('getBaseUrl')->will( $this->returnValue('http://magento.com/') ); - $expectedResult = 'http://magento.com/' . Mage_Webapi_Controller_Router_Route_Webapi::API_AREA_NAME . '/' + $expectedResult = 'http://magento.com/' . self::WEBAPI_AREA_FRONT_NAME . '/' . Mage_Webapi_Controller_Front::API_TYPE_SOAP; $actualResult = $this->_soapServer->getEndpointUri(); - $this->assertEquals($expectedResult, $actualResult, 'Wrong endpoint URI building.'); + $this->assertEquals($expectedResult, $actualResult, 'Endpoint URI building is invalid.'); } /** @@ -147,7 +161,7 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase /** Init Exception. */ $exception = new Exception(); $faultResult = $this->_soapServer->fault($exception); - /** Assert returned object is instance of SoapFault class. */ + /** Assert that returned object is instance of SoapFault class. */ $this->assertInstanceOf('SoapFault', $faultResult, 'SoapFault was not returned.'); } @@ -158,7 +172,7 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase { /** Mock Webapi Soap fault. */ $apiFault = $this->getMockBuilder('Mage_Webapi_Model_Soap_Fault')->disableOriginalConstructor()->getMock(); - /** Assert mocked fault toXml method will be executed once. */ + /** Assert that mocked fault toXml method will be executed once. */ $apiFault->expects($this->once())->method('toXml'); $this->_soapServer->fault($apiFault); } @@ -168,25 +182,26 @@ class Mage_Webapi_Model_Soap_ServerTest extends PHPUnit_Framework_TestCase */ public function providerForGenerateUriTest() { + $webapiFrontName = self::WEBAPI_AREA_FRONT_NAME; return array( //Each array contains isWsdl flag, resources, expected URI and assert message. 'Several resources' => array( false, array('customer' => 'v1', 'product' => 'v2'), - 'http://magento.com/api/soap?resources%5Bcustomer%5D=v1&resources%5Bproduct%5D=v2', - 'Wrong URI generation with several resources.' + "http://magento.com/$webapiFrontName/soap?resources%5Bcustomer%5D=v1&resources%5Bproduct%5D=v2", + 'URI generation with several resources is invalid.' ), 'Several resources with WSDL' => array( true, array('customer' => 'v1', 'product' => 'v2'), - 'http://magento.com/api/soap?resources%5Bcustomer%5D=v1&resources%5Bproduct%5D=v2&wsdl=1', - 'Wrong URI generation with several resources and WSDL.' + "http://magento.com/$webapiFrontName/soap?resources%5Bcustomer%5D=v1&resources%5Bproduct%5D=v2&wsdl=1", + 'URI generation with several resources and WSDL is invalid.' ), 'Empty resources list' => array( true, array(), - 'http://magento.com/api/soap?wsdl=1', - 'Wrong URI generation without resources.' + "http://magento.com/$webapiFrontName/soap?wsdl=1", + 'URI generation without resources is invalid.' ), ); } diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Wsdl/ComplexTypeStrategy/ConfigBasedTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Wsdl/ComplexTypeStrategy/ConfigBasedTest.php index 5012207f262..0525cfa307c 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Wsdl/ComplexTypeStrategy/ConfigBasedTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Soap/Wsdl/ComplexTypeStrategy/ConfigBasedTest.php @@ -74,7 +74,7 @@ class Mage_Webapi_Model_Soap_Wsdl_ComplexTypeStrategy_ConfigBasedTest extends PH } /** - * Test that addComplexType returns type wsdl name + * Test that addComplexType returns type WSDL name * if it has already been processed (registered at includedTypes in WSDL) */ public function testCheckTypeName() @@ -124,7 +124,7 @@ class Mage_Webapi_Model_Soap_Wsdl_ComplexTypeStrategy_ConfigBasedTest extends PH } /** - * Data provider for testAddComplexTypeSimpleParameters() + * Data provider for testAddComplexTypeSimpleParameters(). * * @return array */ @@ -279,7 +279,7 @@ class Mage_Webapi_Model_Soap_Wsdl_ComplexTypeStrategy_ConfigBasedTest extends PH } /** - * Create mock for DOMElement + * Create mock for DOMElement. * * @return PHPUnit_Framework_MockObject_MockObject */ diff --git a/dev/tests/unit/testsuite/Mage/Webapi/Model/Source/Acl/RoleTest.php b/dev/tests/unit/testsuite/Mage/Webapi/Model/Source/Acl/RoleTest.php index cf131431b58..f31c97ca8d2 100644 --- a/dev/tests/unit/testsuite/Mage/Webapi/Model/Source/Acl/RoleTest.php +++ b/dev/tests/unit/testsuite/Mage/Webapi/Model/Source/Acl/RoleTest.php @@ -31,7 +31,7 @@ class Mage_Webapi_Model_Source_Acl_RoleTest extends PHPUnit_Framework_TestCase { /** - * Check output format + * Check output format. * * @dataProvider toOptionsHashDataProvider * @@ -58,7 +58,7 @@ class Mage_Webapi_Model_Source_Acl_RoleTest extends PHPUnit_Framework_TestCase } /** - * Data provider for testing toOptionHash + * Data provider for testing toOptionHash. * * @return array */ diff --git a/dev/tests/unit/testsuite/Magento/ShellTest.php b/dev/tests/unit/testsuite/Magento/ShellTest.php index f4f8e78c819..88788b34e1d 100644 --- a/dev/tests/unit/testsuite/Magento/ShellTest.php +++ b/dev/tests/unit/testsuite/Magento/ShellTest.php @@ -27,50 +27,74 @@ class Magento_ShellTest extends PHPUnit_Framework_TestCase { - public function testGetSetVerbose() + /** + * Test that a command with input arguments returns an expected result + * + * @param Magento_Shell $shell + * @param string $command + * @param array $commandArgs + * @param string $expectedResult + */ + protected function _testExecuteCommand(Magento_Shell $shell, $command, $commandArgs, $expectedResult) { - $shell = new Magento_Shell(false); - $this->assertFalse($shell->isVerbose()); - - $shell->setVerbose(true); - $this->assertTrue($shell->isVerbose()); + $this->expectOutputString(''); // nothing is expected to be ever printed to the standard output + $actualResult = $shell->execute($command, $commandArgs); + $this->assertEquals($expectedResult, $actualResult); + } - $shell->setVerbose(false); - $this->assertFalse($shell->isVerbose()); + /** + * @param string $command + * @param array $commandArgs + * @param string $expectedResult + * @dataProvider executeDataProvider + */ + public function testExecute($command, $commandArgs, $expectedResult) + { + $this->_testExecuteCommand(new Magento_Shell(), $command, $commandArgs, $expectedResult); } /** - * @param string $phpCommand - * @param bool $isVerbose - * @param string $expectedOutput + * @param string $command + * @param array $commandArgs * @param string $expectedResult + * @param array $expectedLogRecords * @dataProvider executeDataProvider */ - public function testExecute($phpCommand, $isVerbose, $expectedOutput, $expectedResult = '') + public function testExecuteLog($command, $commandArgs, $expectedResult, $expectedLogRecords) { - $this->expectOutputString($expectedOutput); - $shell = new Magento_Shell($isVerbose); - $actualResult = $shell->execute('php -r %s', array($phpCommand)); - $this->assertEquals($expectedResult, $actualResult); + $quoteChar = substr(escapeshellarg(' '), 0, 1); // environment-dependent quote character + $logger = $this->getMock('Zend_Log', array('log')); + foreach ($expectedLogRecords as $logRecordIndex => $expectedLogMessage) { + $expectedLogMessage = str_replace('`', $quoteChar, $expectedLogMessage); + $logger + ->expects($this->at($logRecordIndex)) + ->method('log') + ->with($expectedLogMessage, Zend_Log::INFO) + ; + } + $this->_testExecuteCommand(new Magento_Shell($logger), $command, $commandArgs, $expectedResult); } public function executeDataProvider() { - $quote = substr(escapeshellarg(' '), 0, 1); - $eol = PHP_EOL; + // backtick symbol (`) has to be replaced with environment-dependent quote character return array( - 'capture STDOUT' => array( - 'echo 27181;', false, '', '27181', + 'STDOUT' => array( + 'php -r %s', array('echo 27181;'), '27181', + array('php -r `echo 27181;` 2>&1', '27181'), ), - 'print STDOUT' => array( - 'echo 27182;', true, "php -r {$quote}echo 27182;{$quote} 2>&1{$eol}27182{$eol}", '27182', + 'STDERR' => array( + 'php -r %s', array('fwrite(STDERR, 27182);'), '27182', + array('php -r `fwrite(STDERR, 27182);` 2>&1', '27182'), ), - 'capture STDERR' => array( - 'fwrite(STDERR, 27183);', false, '', '27183', + 'piping STDERR -> STDOUT' => array( + // intentionally no spaces around the pipe symbol + 'php -r %s|php -r %s', array('fwrite(STDERR, 27183);', 'echo fgets(STDIN);'), '27183', + array('php -r `fwrite(STDERR, 27183);` 2>&1|php -r `echo fgets(STDIN);` 2>&1', '27183'), ), - 'print STDERR' => array( - 'fwrite(STDERR, 27184);', true, "php -r {$quote}fwrite(STDERR, 27184);{$quote} 2>&1{$eol}27184{$eol}", - '27184', + 'piping STDERR -> STDERR' => array( + 'php -r %s | php -r %s', array('fwrite(STDERR, 27184);', 'fwrite(STDERR, fgets(STDIN));'), '27184', + array('php -r `fwrite(STDERR, 27184);` 2>&1 | php -r `fwrite(STDERR, fgets(STDIN));` 2>&1', '27184'), ), ); } @@ -87,31 +111,21 @@ class Magento_ShellTest extends PHPUnit_Framework_TestCase } /** - * @param string $phpCommand - * @param bool $isVerbose - * @param string $expectedOutput + * @param string $command + * @param array $commandArgs * @param string $expectedError * @dataProvider executeDataProvider */ - public function testExecuteFailureDetails($phpCommand, $isVerbose, $expectedOutput, $expectedError) + public function testExecuteFailureDetails($command, $commandArgs, $expectedError) { try { /* Force command to return non-zero exit code */ - $phpFailingCommand = $phpCommand . ' exit(42);'; - $expectedOutput = str_replace($phpCommand, $phpFailingCommand, $expectedOutput); - $this->testExecute($phpFailingCommand, $isVerbose, $expectedOutput); + $commandArgs[count($commandArgs) - 1] .= ' exit(42);'; + $this->testExecute($command, $commandArgs, ''); // no result is expected in a case of a command failure } catch (Magento_Exception $e) { $this->assertInstanceOf('Exception', $e->getPrevious()); $this->assertEquals($expectedError, $e->getPrevious()->getMessage()); $this->assertEquals(42, $e->getPrevious()->getCode()); } } - - public function testOutput() - { - $fixture = uniqid(); - $this->expectOutputString($fixture . PHP_EOL); - $shell = new Magento_Shell; - $shell->output($fixture); - } } diff --git a/index.php b/index.php index 3c539f7b347..ced5562a056 100644 --- a/index.php +++ b/index.php @@ -26,7 +26,14 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -require_once __DIR__ . '/app/bootstrap.php'; +require __DIR__ . '/app/bootstrap.php'; +Mage::run($_SERVER); -$appOptions = new Mage_Core_Model_App_Options($_SERVER); -Mage::run($appOptions->getRunCode(), $appOptions->getRunType(), $appOptions->getRunOptions()); +/** + * Example - run a particular store or website: + * + * $params = $_SERVER; + * $params['MAGE_RUN_CODE'] = 'website2'; + * $params['MAGE_RUN_TYPE'] = 'website'; + * Mage::run($params) + */ diff --git a/lib/Magento/Filesystem/Adapter/Local.php b/lib/Magento/Filesystem/Adapter/Local.php index 176a89978e5..74f189e5c3a 100644 --- a/lib/Magento/Filesystem/Adapter/Local.php +++ b/lib/Magento/Filesystem/Adapter/Local.php @@ -290,7 +290,12 @@ class Magento_Filesystem_Adapter_Local implements */ public function touch($key, $fileModificationTime = null) { - if (!@touch($key, $fileModificationTime)) { + if ($fileModificationTime === null) { + $success = @touch($key); + } else { + $success = @touch($key, $fileModificationTime); + } + if (!$success) { throw new Magento_Filesystem_Exception(sprintf('Failed to touch %s', $key)); } } diff --git a/lib/Magento/ObjectManager/Zend.php b/lib/Magento/ObjectManager/Zend.php index 6f28e52e3a4..130fc7bda04 100644 --- a/lib/Magento/ObjectManager/Zend.php +++ b/lib/Magento/ObjectManager/Zend.php @@ -117,7 +117,12 @@ class Magento_ObjectManager_Zend implements Magento_ObjectManager } /** - * Add shared instance + * A proxy for adding shared instance + * + * Normally Di object manager determines a hash based on the class name and incoming arguments. + * But in client code it is inconvenient (or nearly impossible) to "know" arguments for the objects you depend on. + * This is a dirty hack that allows bypassing "hash checking" by Di object manager and therefore referring + * to an instance using class name (or alias), but not specifying its non-injectable arguments. * * @param object $instance * @param string $classOrAlias diff --git a/lib/Magento/Shell.php b/lib/Magento/Shell.php index 175c38181a5..bf31706cfd7 100644 --- a/lib/Magento/Shell.php +++ b/lib/Magento/Shell.php @@ -30,42 +30,20 @@ class Magento_Shell { /** - * Verbosity of command execution - whether command output is printed to the standard output or not + * Logger instance * - * @var bool + * @var Zend_Log */ - protected $_isVerbose; + protected $_logger; /** * Constructor * - * @param bool $isVerbose Whether command output is printed to the standard output or not + * @param Zend_Log $logger Logger instance to be used to log commands and their output */ - public function __construct($isVerbose = false) + public function __construct(Zend_Log $logger = null) { - $this->_isVerbose = $isVerbose; - } - - /** - * Set verbosity - * - * @param bool $isVerbose - * @return Magento_Shell - */ - public function setVerbose($isVerbose) - { - $this->_isVerbose = $isVerbose; - return $this; - } - - /** - * Get verbosity - * - * @return bool - */ - public function isVerbose() - { - return $this->_isVerbose; + $this->_logger = $logger; } /** @@ -79,15 +57,12 @@ class Magento_Shell public function execute($command, array $arguments = array()) { $arguments = array_map('escapeshellarg', $arguments); - $command = vsprintf("$command 2>&1", $arguments); // Output errors to STDOUT instead of STDERR - if ($this->_isVerbose) { - $this->output($command); - } + $command = preg_replace('/\s?\||$/', ' 2>&1$0', $command); // Output errors to STDOUT instead of STDERR + $command = vsprintf($command, $arguments); + $this->_log($command); exec($command, $output, $exitCode); $output = implode(PHP_EOL, $output); - if ($this->_isVerbose) { - $this->output($output); - } + $this->_log($output); if ($exitCode) { $commandError = new Exception($output, $exitCode); throw new Magento_Exception("Command `$command` returned non-zero exit code.", 0, $commandError); @@ -96,12 +71,14 @@ class Magento_Shell } /** - * Echo the specified message + * Log a message, if a logger is specified * * @param string $message */ - public function output($message) + protected function _log($message) { - echo $message . PHP_EOL; + if ($this->_logger) { + $this->_logger->log($message, Zend_Log::INFO); + } } } diff --git a/lib/Varien/Data/Form/Element/Date.php b/lib/Varien/Data/Form/Element/Date.php index 5178fbf56ae..da00b74644f 100644 --- a/lib/Varien/Data/Form/Element/Date.php +++ b/lib/Varien/Data/Form/Element/Date.php @@ -38,7 +38,7 @@ class Varien_Data_Form_Element_Date extends Varien_Data_Form_Element_Abstract */ protected $_value; - public function __construct($attributes=array()) + public function __construct($attributes = array()) { parent::__construct($attributes); $this->setType('text'); @@ -104,8 +104,7 @@ class Varien_Data_Form_Element_Date extends Varien_Data_Form_Element_Abstract } try { $this->_value = new Zend_Date($value, $format, $locale); - } - catch (Exception $e) { + } catch (Exception $e) { $this->_value = ''; } return $this; @@ -124,7 +123,7 @@ class Varien_Data_Form_Element_Date extends Varien_Data_Form_Element_Abstract return ''; } if (null === $format) { - $format = $this->getFormat(); + $format = $this->getDateFormat(); } return $this->_value->toString($format); } @@ -148,6 +147,7 @@ class Varien_Data_Form_Element_Date extends Varien_Data_Form_Element_Abstract * - the value must be instantiated (Zend_Date) * - output format must be set (compatible with Zend_Date) * + * @throws Exception * @return string */ public function getElementHtml() @@ -155,19 +155,21 @@ class Varien_Data_Form_Element_Date extends Varien_Data_Form_Element_Abstract $this->addClass('input-text'); $html = sprintf( - '<input name="%s" id="%s" value="%s" %s style="width:110px !important;" ' . $this->_getUiId('hidden') . '/>', - $this->getName(), $this->getHtmlId(), $this->_escape($this->getValue()), $this->serialize($this->getHtmlAttributes()), - $this->getImage(), $this->getHtmlId(), 'Select Date', ($this->getDisabled() ? 'display:none;' : '') + '<input name="%s" id="%s" value="%s" %s style="width:110px !important;" />', + $this->getName(), + $this->getHtmlId(), + $this->_escape($this->getValue()), + $this->serialize($this->getHtmlAttributes()) ); $dateFormat = $this->getDateFormat(); $timeFormat = $this->getTimeFormat(); if (empty($dateFormat)) { - throw new Exception('Output format is not specified. Please, specify "format" key in constructor, or set it using setFormat().'); + throw new Exception('Output format is not specified. ' + . 'Please, specify "format" key in constructor, or set it using setFormat().'); } $html .= sprintf(' <script type="text/javascript"> - //<![CDATA[ (function($) { $("#%s").calendar({ dateFormat: "%s", @@ -177,8 +179,7 @@ class Varien_Data_Form_Element_Date extends Varien_Data_Form_Element_Abstract buttonText: "%s", disabled: %s }) - })(jQuery) - //]]> + })(jQuery); </script>', $this->getHtmlId(), $dateFormat, diff --git a/pub/.htaccess b/pub/.htaccess index 51fde249567..518d6c87420 100644 --- a/pub/.htaccess +++ b/pub/.htaccess @@ -134,11 +134,6 @@ RewriteCond %{REQUEST_METHOD} ^TRAC[EK] RewriteRule .* - [L,R=405] -############################################ -## always send 404 on missing files in these folders - - RewriteCond %{REQUEST_URI} !^/(media|js)/ - ############################################ ## never rewrite for existing files, directories and links diff --git a/pub/get.php b/pub/get.php index 2e2c763d1fb..050d2eb26d2 100644 --- a/pub/get.php +++ b/pub/get.php @@ -26,21 +26,17 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -require_once __DIR__ . '/../app/bootstrap.php'; - -$varDirectory = BP . DS . Mage_Core_Model_Config_Options::VAR_DIRECTORY; -$publicDirectory = BP . DS . Mage_Core_Model_Config_Options::PUB_DIRECTORY; -$configCacheFile = $varDirectory . DS . 'resource_config.json'; +require dirname(__DIR__) . '/app/bootstrap.php'; $mediaDirectory = null; $allowedResources = array(); - +$configCacheFile = dirname(__DIR__) . '/var/resource_config.json'; if (file_exists($configCacheFile) && is_readable($configCacheFile)) { $config = json_decode(file_get_contents($configCacheFile), true); //checking update time if (filemtime($configCacheFile) + $config['update_time'] > time()) { - $mediaDirectory = trim(str_replace($publicDirectory, '', $config['media_directory']), DS); + $mediaDirectory = trim(str_replace(__DIR__, '', $config['media_directory']), DS); $allowedResources = array_merge($allowedResources, $config['allowed_resources']); } } @@ -49,7 +45,7 @@ $request = new Zend_Controller_Request_Http(); $pathInfo = str_replace('..', '', ltrim($request->getPathInfo(), '/')); -$filePath = str_replace('/', DS, $publicDirectory . DS . $pathInfo); +$filePath = str_replace('/', DS, __DIR__ . DS . $pathInfo); if ($mediaDirectory) { if (0 !== stripos($pathInfo, $mediaDirectory . '/') || is_dir($filePath)) { @@ -61,18 +57,20 @@ if ($mediaDirectory) { sendFile($filePath); } -$appOptions = new Mage_Core_Model_App_Options($_SERVER); if (empty($mediaDirectory)) { - Mage::init($appOptions->getRunCode(), $appOptions->getRunType(), $appOptions->getRunOptions()); + Mage::init($_SERVER); } else { - $appRunOptions = array_merge($appOptions->getRunOptions(), array('cache' => array('disallow_save' => true))); - Mage::init($appOptions->getRunCode(), $appOptions->getRunType(), $appRunOptions, array('Mage_Core')); + $params = array_merge( + $_SERVER, + array(Mage_Core_Model_Cache::APP_INIT_PARAM => array('disallow_save' => true)) + ); + Mage::init($params, array('Mage_Core')); } Mage::app()->requireInstalledInstance(); if (!$mediaDirectory) { $config = Mage_Core_Model_File_Storage::getScriptConfig(); - $mediaDirectory = str_replace($publicDirectory, '', $config['media_directory']); + $mediaDirectory = str_replace(__DIR__, '', $config['media_directory']); $allowedResources = array_merge($allowedResources, $config['allowed_resources']); $relativeFilename = str_replace($mediaDirectory . '/', '', $pathInfo); @@ -93,11 +91,11 @@ if (0 !== stripos($pathInfo, $mediaDirectory . '/')) { } try { - $databaseFileSotrage = Mage::getModel('Mage_Core_Model_File_Storage_Database'); - $databaseFileSotrage->loadByFilename($relativeFilename); + $databaseFileStorage = Mage::getModel('Mage_Core_Model_File_Storage_Database'); + $databaseFileStorage->loadByFilename($relativeFilename); } catch (Exception $e) { } -if ($databaseFileSotrage->getId()) { +if ($databaseFileStorage->getId()) { $directory = dirname($filePath); if (!is_dir($directory)) { mkdir($directory, 0777, true); @@ -106,7 +104,7 @@ if ($databaseFileSotrage->getId()) { $fp = fopen($filePath, 'w'); if (flock($fp, LOCK_EX | LOCK_NB)) { ftruncate($fp, 0); - fwrite($fp, $databaseFileSotrage->getContent()); + fwrite($fp, $databaseFileStorage->getContent()); } flock($fp, LOCK_UN); fclose($fp); diff --git a/pub/index.php b/pub/index.php index 64099054a49..15c5b4a4674 100644 --- a/pub/index.php +++ b/pub/index.php @@ -26,4 +26,7 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -require __DIR__ . '/../index.php'; +require __DIR__ . '/../app/bootstrap.php'; +$params = $_SERVER; +$params[Mage_Core_Model_App::INIT_OPTION_URIS][Mage_Core_Model_Dir::PUB] = ''; +Mage::run($params); diff --git a/pub/lib/.htaccess b/pub/lib/.htaccess new file mode 100644 index 00000000000..0932cbcce43 --- /dev/null +++ b/pub/lib/.htaccess @@ -0,0 +1,6 @@ +############################################ +## always send 404 on missing files + +<IfModule mod_rewrite.c> + RewriteEngine off +</IfModule> diff --git a/pub/lib/jquery/jstree/jquery.hotkeys.js b/pub/lib/jquery/jstree/jquery.hotkeys.js new file mode 100644 index 00000000000..fbd71c71ec7 --- /dev/null +++ b/pub/lib/jquery/jstree/jquery.hotkeys.js @@ -0,0 +1,99 @@ +/* + * jQuery Hotkeys Plugin + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * + * Based upon the plugin by Tzury Bar Yochay: + * http://github.com/tzuryby/hotkeys + * + * Original idea by: + * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/ +*/ + +(function(jQuery){ + + jQuery.hotkeys = { + version: "0.8", + + specialKeys: { + 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", + 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", + 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", + 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", + 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", + 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", + 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta" + }, + + shiftNums: { + "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", + "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", + ".": ">", "/": "?", "\\": "|" + } + }; + + function keyHandler( handleObj ) { + // Only care when a possible input has been specified + if ( typeof handleObj.data !== "string" ) { + return; + } + + var origHandler = handleObj.handler, + keys = handleObj.data.toLowerCase().split(" "); + + handleObj.handler = function( event ) { + // Don't fire in text-accepting inputs that we didn't directly bind to + if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || + event.target.type === "text") ) { + return; + } + + // Keypress represents characters, not special keys + var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ], + character = String.fromCharCode( event.which ).toLowerCase(), + key, modif = "", possible = {}; + + // check combinations (alt|ctrl|shift+anything) + if ( event.altKey && special !== "alt" ) { + modif += "alt+"; + } + + if ( event.ctrlKey && special !== "ctrl" ) { + modif += "ctrl+"; + } + + // TODO: Need to make sure this works consistently across platforms + if ( event.metaKey && !event.ctrlKey && special !== "meta" ) { + modif += "meta+"; + } + + if ( event.shiftKey && special !== "shift" ) { + modif += "shift+"; + } + + if ( special ) { + possible[ modif + special ] = true; + + } else { + possible[ modif + character ] = true; + possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; + + // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" + if ( modif === "shift+" ) { + possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; + } + } + + for ( var i = 0, l = keys.length; i < l; i++ ) { + if ( possible[ keys[i] ] ) { + return origHandler.apply( this, arguments ); + } + } + }; + } + + jQuery.each([ "keydown", "keyup", "keypress" ], function() { + jQuery.event.special[ this ] = { add: keyHandler }; + }); + +})( jQuery ); \ No newline at end of file diff --git a/pub/lib/mage/adminhtml/grid.js b/pub/lib/mage/adminhtml/grid.js index 1797ec04d87..9cc58f2012a 100644 --- a/pub/lib/mage/adminhtml/grid.js +++ b/pub/lib/mage/adminhtml/grid.js @@ -40,6 +40,7 @@ varienGrid.prototype = { this.initCallback = false; this.initRowCallback = false; this.doFilterCallback = false; + this.sortableUpdateCallback = false; this.reloadParams = false; @@ -280,6 +281,22 @@ varienGrid.prototype = { Event.observe(dataElements[i], 'change', dataElements[i].setHasChanges.bind(dataElements[i])); } }, + bindSortable: function(){ + if (jQuery('#' + this.containerId).find('.ui-icon-grip-dotted-vertical').length) { + jQuery('#' + this.containerId).find('tbody').sortable({ + axis: 'y', + handle: '.ui-icon-grip-dotted-vertical', + helper: function(event, ui) { + ui.children().each(function() { + jQuery(this).width(jQuery(this).width()); + }); + return ui; + }, + update: this.sortableUpdateCallback ? this.sortableUpdateCallback : function(){}, + tolerance: 'pointer' + }); + } + }, filterKeyPress:function (event) { if (event.keyCode == Event.KEY_RETURN) { this.doFilter(); diff --git a/pub/lib/mage/backend/action-link.js b/pub/lib/mage/backend/action-link.js index 821c7d4c7cd..7fe481f9fc6 100644 --- a/pub/lib/mage/backend/action-link.js +++ b/pub/lib/mage/backend/action-link.js @@ -56,4 +56,4 @@ }); } }); -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/pub/lib/mage/backend/multisuggest.js b/pub/lib/mage/backend/multisuggest.js new file mode 100644 index 00000000000..9044d15df61 --- /dev/null +++ b/pub/lib/mage/backend/multisuggest.js @@ -0,0 +1,152 @@ +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category mage + * @package mage + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +/*jshint jquery:true browser:true*/ +(function($) { + 'use strict'; + $.widget('mage.multisuggest', $.mage.suggest, { + /** + * @override + */ + _create: function() { + this._super(); + this.valueField.hide(); + }, + + /** + * @override + */ + _prepareValueField: function() { + this._super(); + if (!this.options.valueField && this.options.selectedItems) { + $.each(this.options.selectedItems, $.proxy(function(i, item) { + this._addOption(item); + }, this)); + } + }, + + /** + * @override + */ + _createValueField: function() { + return $('<select/>', { + type: 'hidden', + multiple: 'multiple' + }); + }, + + /** + * @override + */ + _selectItem: function() { + if (this.isDropdownShown() && this._focused) { + this._selectedItem = this._readItemData(this._focused); + if (this.valueField.find('option[value=' + this._selectedItem.id + ']').length) { + this._selectedItem = this._nonSelectedItem; + } + if (this._selectedItem !== this._nonSelectedItem) { + this._term = ''; + this._addOption(this._selectedItem); + } + } + }, + + /** + * Add selected item in to select options + * @param item + * @private + */ + _addOption: function(item) { + this.valueField.append( + '<option value="' + item.id + '" selected="selected">' + item.label + '</option>' + ); + }, + + /** + * Remove item from select options + * @param item + * @private + */ + _removeOption: function(item) { + this.valueField.find('option[value=' + item.id + ']').remove(); + }, + + /** + * @override + */ + _hideDropdown: function() { + this._super(); + this.element.val(''); + } + }); + + $.widget('mage.multisuggest', $.mage.multisuggest, { + options: { + multiSuggestWrapper: '<ul class="category-selector-choices">' + + '<li class="category-selector-search-field"></li></ul>', + choiceTemplate: '<li class="category-selector-search-choice button"><div>${text}</div>' + + '<span class="category-selector-search-choice-close" tabindex="-1" ' + + 'data-mage-init="{"actionLink":{"event":"removeOption"}}"></span></li>' + }, + + /** + * @override + */ + _render: function() { + this._super(); + this.element.wrap(this.options.multiSuggestWrapper); + this.elementWrapper = this.element.parent(); + this.valueField.find('option').each($.proxy(function(i, option) { + option = $(option); + this._renderOption({id: option.val(), label: option.text()}); + }, this)); + }, + + /** + * @override + */ + _selectItem: function() { + this._superApply(arguments); + if (this._selectedItem !== this._nonSelectedItem) { + this._renderOption(this._selectedItem); + } + }, + + /** + * Render visual element of selected item + * @param {Object} item - selected item + * @private + */ + _renderOption: function(item) { + $.tmpl(this.options.choiceTemplate, {text: item.label}) + .data(item) + .insertBefore(this.elementWrapper) + .trigger('contentUpdated') + .on('removeOption', $.proxy(function(e) { + this._removeOption($(e.currentTarget).data()); + $(e.currentTarget).remove(); + }, this)); + } + }); +})(jQuery); diff --git a/pub/lib/mage/backend/suggest.js b/pub/lib/mage/backend/suggest.js index d4d7f2cdc55..bd099ce4338 100644 --- a/pub/lib/mage/backend/suggest.js +++ b/pub/lib/mage/backend/suggest.js @@ -40,23 +40,17 @@ delay: 500, events: {}, appendMethod: 'after', - control: 'menu', controls: { - menu: { - selector: ':ui-menu', - eventsMap: { - focus: 'menufocus', - blur: 'menublur', - select: 'menuselect' - } + selector: ':ui-menu, .jstree', + eventsMap: { + focus: ['menufocus', 'hover_node'], + blur: ['menublur', 'dehover_node'], + select: ['menuselect', 'select_tree_node'] } }, - wrapperAttributes: { - 'class': 'mage-suggest' - }, - attributes: { - 'class': 'mage-suggest-dropdown' - } + className: null, + inputWrapper:'<div class="mage-suggest"><div class="mage-suggest-inner"></div></div>', + dropdownWrapper: '<div class="mage-suggest-dropdown"></div>' }, /** @@ -64,22 +58,57 @@ * @private */ _create: function() { - this._setTemplate(); this._term = ''; - this._selectedItem = {value: '', label: ''}; - this.dropdown = $('<div/>', this.options.attributes).hide(); + this._nonSelectedItem = {id: '', label: ''}; + this._renderedContext = null; + this._selectedItem = this._nonSelectedItem; + this._control = this.options.controls || {}; + this._setTemplate(); + this._prepareValueField(); + this._render(); + this._bind(); + }, + + /** + * Render base elemments for suggest component + * @private + */ + _render: function() { + this.dropdown = $(this.options.dropdownWrapper).hide(); + var wrapper = this.options.className ? + $(this.options.inputWrapper).addClass(this.options.className) : + $(this.options.inputWrapper); this.element - .wrap($('<div><div class="mage-suggest-inner"></div></div>') - .prop(this.options.wrapperAttributes)) + .wrap(wrapper) [this.options.appendMethod](this.dropdown) .attr('autocomplete', 'off'); - this.hiddenInput = $('<input/>', { - type: 'hidden', - name: this.element.attr('name') - }).insertBefore(this.element); - this.element.removeAttr('name'); - this._control = this.options.controls[this.options.control] || {}; - this._bind(); + }, + + /** + * Define a field for storing item id (find in DOM or create a new one) + * @private + */ + _prepareValueField: function() { + if (this.options.valueField) { + this.valueField = $(this.options.valueField); + } else { + this.valueField = this._createValueField() + .insertBefore(this.element) + .attr('name', this.element.attr('name')); + this.element.removeAttr('name'); + } + }, + + /** + * Create value field which keeps a id for selected option + * can be overridden in descendants + * @return {jQuery} + * @private + */ + _createValueField: function() { + return $('<input/>', { + type: 'hidden' + }); }, /** @@ -87,11 +116,14 @@ * @private */ _destroy: function() { - this.element.removeAttr('autocomplete') + this.element .unwrap() - .attr('name', this.hiddenInput.attr('name')); + .removeAttr('autocomplete'); + if (!this.options.valueField) { + this.element.attr('name', this.valueField.attr('name')); + this.valueField.remove(); + } this.dropdown.remove(); - this.hiddenInput.remove(); this._off(this.element, 'keydown keyup blur'); }, @@ -110,7 +142,12 @@ * @private */ _proxyEvents: function(event) { - this.dropdown.find(this._control.selector).triggerHandler(event); + var fakeEvent = $.extend({}, $.Event(event.type), { + ctrlKey: event.ctrlKey, + keyCode: event.keyCode, + which: event.keyCode + }); + this.dropdown.find(this._control.selector).trigger(fakeEvent); }, /** @@ -122,15 +159,12 @@ keydown: function(event) { var keyCode = $.ui.keyCode; switch (event.keyCode) { - case keyCode.HOME: - case keyCode.END: case keyCode.PAGE_UP: case keyCode.PAGE_DOWN: case keyCode.UP: case keyCode.DOWN: - case keyCode.LEFT: - case keyCode.RIGHT: if (!event.shiftKey) { + event.preventDefault(); this._proxyEvents(event); } break; @@ -190,43 +224,77 @@ */ _bindDropdown: function() { var events = { - click: this._selectItem, + click: function(e) { + // prevent default browser's behavior of changing location by anchor href + e.preventDefault(); + }, mousedown: function(e) { e.preventDefault(); } }; - events[this._control.eventsMap.select] = this._selectItem; - events[this._control.eventsMap.focus] = function(e, ui) { - this.element.val(ui.item.text()); - }; - events[this._control.eventsMap.blur] = function() { - this.element.val(this._term); - }; + $.each(this._control.eventsMap, $.proxy(function(suggestEvent, controlEvents) { + $.each(controlEvents, $.proxy(function(i, handlerName) { + switch(suggestEvent) { + case 'select' : + events[handlerName] = this._selectItem; + break; + case 'focus' : + events[handlerName] = this._focusItem; + break; + case 'blur' : + events[handlerName] = this._blurItem; + break; + } + }, this)); + }, this)); this._on(this.dropdown, events); }, + /** + * Handle focus event of options item + * @param {Object} e - event object + * @param {Object} option + * @private + */ + _focusItem: function(e, option) { + this._focused = option.item; + this.element.val(this._readItemData(this._focused).label); + }, + + /** + * Handle blur event of options item + * @private + */ + _blurItem: function() { + this._focused = null; + this.element.val(this._term); + }, + /** * Save selected item and hide dropdown * @private */ _selectItem: function() { - var term = this._value(); - if (this.isDropdownShown() && term) { - /** - * @type {(Object|null)} - label+value object of selected item - * @private - */ - this._selectedItem = $.grep(this._items, $.proxy(function(v) { - return v.label === term; - }, this))[0] || {value: '', label: ''}; - if (this._selectedItem.value) { + if (this.isDropdownShown() && this._focused) { + this._selectedItem = this._readItemData(this._focused); + if (this._selectedItem !== this._nonSelectedItem) { this._term = this._selectedItem.label; - this.hiddenInput.val(this._selectedItem.value); + this.valueField.val(this._selectedItem.id); this._hideDropdown(); } } }, + /** + * Read option data from item element + * @param {Element} item + * @return {Object} + * @private + */ + _readItemData: function(item) { + return item.data('suggestOption') || this._nonSelectedItem; + }, + /** * Check if dropdown is shown * @return {boolean} @@ -251,6 +319,7 @@ */ _hideDropdown: function() { this.element.val(this._selectedItem.label); + this._renderedContext = null; this.dropdown.hide().empty(); }, @@ -259,9 +328,12 @@ * @private */ _setTemplate: function() { - this.template = $(this.options.template).length ? - $(this.options.template).template() : - $.template('suggestTemplate', this.options.template); + this.templateName = 'suggest' + Math.random().toString(36).substr(2); + if ($(this.options.template).length) { + $(this.options.template).template(this.templateName); + } else { + $.template(this.templateName, this.options.template); + } }, /** @@ -275,8 +347,8 @@ if (term) { this._search(term); } else { - this._selectedItem = {value: '', label: ''}; - this.hiddenInput.val(this._selectedItem.value); + this._selectedItem = this._nonSelectedItem; + this.valueField.val(this._selectedItem.id); } } }, @@ -311,21 +383,28 @@ _prepareDropdownContext: function(context) { return $.extend(context, { items: this._items, - term: this._term + term: this._term, + optionData: function(item) { + return 'data-suggest-option="' + JSON.stringify(item).replace(/"/g, '"') + '"'; + } }); }, /** * Render content of suggest's dropdown - * @param {Array} items - list of label+value objects + * @param {Array} items - list of label+id objects * @param {Object} context - template's context * @private */ _renderDropdown: function(items, context) { this._items = items; - $.tmpl(this.template, this._prepareDropdownContext(context)) + $.tmpl(this.templateName, this._prepareDropdownContext(context)) .appendTo(this.dropdown.empty()); - this.dropdown.trigger('contentUpdated'); + this.dropdown.trigger('contentUpdated') + .find(this._control.selector).on('focus', function(e) { + e.preventDefault(); + }); + this._renderedContext = context; this._showDropdown(); }, @@ -347,13 +426,19 @@ url: this.options.source, type: 'POST', dataType: 'json', - data: {q: term}, - success: renderer, - showLoader: true + data: {name_part: term}, + success: renderer }, this.options.ajaxOptions || {})); } }, + _abortSearch: function() { + clearTimeout(this._searchTimeout); + if (this._xhr) { + this._xhr.abort(); + } + }, + /** * Perform filtering in advance loaded items and returns search result * @param {Array} items - all available items @@ -363,7 +448,7 @@ filter: function(items, term) { var matcher = new RegExp(term, 'i'); return $.grep(items, function(value) { - return matcher.test(value.label || value.value || value); + return matcher.test(value.label || value.id || value); }); } }); @@ -371,10 +456,10 @@ /** * Implements height prediction functionality to dropdown item */ - $.widget('mage.suggest', $.mage.suggest, { + /*$.widget('mage.suggest', $.mage.suggest, { /** * Extension specific options - */ + *//* options: { bottomMargin: 35 }, @@ -382,7 +467,7 @@ /** * @override * @private - */ + *//* _renderDropdown: function() { this._superApply(arguments); this._recalculateDropdownHeight(); @@ -391,7 +476,7 @@ /** * Recalculates height of dropdown and cut it if needed * @private - */ + *//* _recalculateDropdownHeight: function() { var dropdown = this.dropdown.css('visibility', 'hidden'), fromTop = dropdown.offset().top, @@ -403,14 +488,14 @@ [isOverflowApplied ? 'addClass':'removeClass']('overflow-y') .height(isOverflowApplied ? winHeight - fromTop - this.options.bottomMargin : ''); } - }); + });*/ /** * Implement storing search history and display recent searches */ $.widget('mage.suggest', $.mage.suggest, { options: { - showRecent: true, + showRecent: false, storageKey: 'suggest', storageLimit: 10 }, @@ -437,13 +522,15 @@ */ _bind: function() { this._super(); - this._on({ - focus: function() { - if (!this._value()) { - this._renderDropdown(this._recentItems); + if (this.options.showRecent) { + this._on({ + focus: function() { + if (!this._value()) { + this._renderDropdown(this._recentItems); + } } - } - }); + }); + } }, /** @@ -451,12 +538,11 @@ */ search: function() { this._super(); - if (!this._term) { - clearTimeout(this._searchTimeout); - if (this._xhr) { - this._xhr.abort(); + if (this.options.showRecent) { + if (!this._term) { + this._abortSearch(); + this._renderDropdown(this._recentItems); } - this._renderDropdown(this._recentItems); } }, @@ -465,20 +551,20 @@ * @private */ _selectItem: function() { - this._super(); - if (this._selectedItem.value) { + this._superApply(arguments); + if (this._selectedItem.id && this.options.showRecent) { this._addRecent(this._selectedItem); } }, /** * Add selected item of search result into storage of recents - * @param {Object} item - label+value object + * @param {Object} item - label+id object * @private */ _addRecent: function(item) { this._recentItems = $.grep(this._recentItems, function(obj){ - return obj.value !== item.value; + return obj.id !== item.id; }); this._recentItems.unshift(item); this._recentItems = this._recentItems.slice(0, this.options.storageLimit); @@ -497,21 +583,47 @@ _bind: function() { this._super(); this._on(this.dropdown, { - showAll: function() { - this._search('', {_allSown: true}); - } + showAll: this._showAll }); }, + /** + * + * @private + */ + _showAll: function() { + this._abortSearch(); + if (!this._allItems) { + this._search('', {_allShown: true}); + } else if (!this._renderedContext || !this._renderedContext._allShown) { + this._renderDropdown(this._allItems, {_allShown: true}); + } + }, + + /** + * @override + * @param items + * @param context + * @private + */ + _renderDropdown: function(items, context) { + this._superApply(arguments); + if (context && context._allShown && !this.allItems) { + this._allItems = this._items; + } + }, + /** * @override * @private */ _prepareDropdownContext: function() { var context = this._superApply(arguments); - return $.extend(context, {allShown: function(){ - return !!context._allSown; - }}); + return $.extend(context, { + allShown: function(){ + return !!context._allShown; + } + }); } }); })(jQuery); diff --git a/pub/lib/mage/backend/tree-suggest.js b/pub/lib/mage/backend/tree-suggest.js new file mode 100644 index 00000000000..2153a696061 --- /dev/null +++ b/pub/lib/mage/backend/tree-suggest.js @@ -0,0 +1,169 @@ +/** + * Magento + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE_AFL.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@magentocommerce.com so we can send you a copy immediately. + * + * DISCLAIMER + * + * Do not edit or add to this file if you wish to upgrade Magento to newer + * versions in the future. If you wish to customize Magento for your + * needs please refer to http://www.magentocommerce.com for more information. + * + * @category mage + * @package mage + * @copyright Copyright (c) 2013 X.commerce, Inc. (http://www.magentocommerce.com) + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + */ +/*jshint jquery:true browser:true*/ +(function($) { + 'use strict'; + $.extend(true, $, { + // @TODO: Move method 'treeToList' in file with utility functions + mage: { + treeToList: function(list, nodes, level, path) { + $.each(nodes, function() { + list.push({ + label: this.label, + id: this.id, + level: level, + item: this, + path: path + this.label + }); + if ('children' in this) { + $.mage.treeToList(list, this.children, level + 1, path + this.label + ' / ' ); + } + }); + return list; + } + } + }); + + var hover_node = $.jstree._instance.prototype.hover_node; + var dehover_node = $.jstree._instance.prototype.dehover_node; + var select_node = $.jstree._instance.prototype.select_node; + var init = $.jstree._instance.prototype.init; + $.extend(true, $.jstree._instance.prototype, { + /** + * @override + */ + init: function() { + this.get_container() + .show() + .on('keydown', $.proxy(function(e) { + if (e.keyCode === $.ui.keyCode.ENTER) { + var o = this.data.ui.hovered || this.data.ui.last_selected || -1; + this.select_node(o, true); + } + }, this)); + init.call(this); + }, + + /** + * @override + */ + hover_node: function(obj) { + hover_node.apply(this, arguments); + obj = this._get_node(obj); + if (!obj.length) { + return false; + } + this.get_container().trigger('hover_node', [{item: obj.find('a:first')}]); + }, + + /** + * @override + */ + dehover_node: function() { + dehover_node.call(this); + this.get_container().trigger('dehover_node'); + }, + + /** + * @override + */ + select_node: function(o) { + select_node.apply(this, arguments); + (o ? $(o) : this.data.ui.last_selected).trigger('select_tree_node'); + } + }); + + $.widget('mage.treeSuggest', $.mage.multisuggest, { + /** + * @override + */ + _bind: function() { + this._super(); + this._on({ + keydown: function(event) { + var keyCode = $.ui.keyCode; + switch (event.keyCode) { + case keyCode.LEFT: + case keyCode.RIGHT: + if (this.isDropdownShown()) { + event.preventDefault(); + this._proxyEvents(event); + } + } + } + }); + this._on({ + focus: function() { + this.search(); + } + }); + }, + + /** + * @override + */ + search: function() { + if (!this.options.showRecent && !this._value()) { + this._showAll(); + } else { + this._super(); + } + }, + + /** + * @override + */ + _prepareDropdownContext: function() { + var context = this._superApply(arguments), + optionData = context.optionData, + templateName = this.templateName; + context.optionData = function(item) { + item = $.extend({}, item); + delete item.children; + return optionData(item); + }; + return $.extend(context, { + renderTreeLevel: function(children) { + var _context = $.extend({}, this.data, {items: children, nested: true}); + return $('<div>').append($.tmpl(templateName, _context)).html(); + } + }); + }, + + /** + * @override + */ + _renderDropdown: function(items, context) { + if(!context._allShown) { + items = this.filter($.mage.treeToList([], items, 0, ''), this._term); + } + var control = this.dropdown.find(this._control.selector); + if (control.length && control.hasClass('jstree')) { + control.jstree("destroy"); + } + this._superApply([items, context]); + } + }); +})(jQuery); diff --git a/pub/lib/mage/mage.js b/pub/lib/mage/mage.js index a4ec587480f..bf6f6a56f73 100644 --- a/pub/lib/mage/mage.js +++ b/pub/lib/mage/mage.js @@ -23,18 +23,37 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ /*jshint eqnull:true browser:true jquery:true*/ -/*global head:true */ +/*global head:true console:true*/ (function($) { "use strict"; /** - * Main namespace for Magento extansions + * Store developer mode flag value + * @type {boolean} + * @private + */ + var _isDevMode = false; + + /** + * Main namespace for Magento extensions * @type {Object} */ - $.mage = {}; + $.mage = { + /** + * Setter and getter for developer mode flag + * @param {(undefined|boolean)} flag + * @return {boolean} + */ + isDevMode: function(flag) { + if (typeof flag !== 'undefined') { + _isDevMode = !!flag; + } + return _isDevMode && typeof console !== 'undefined'; + } + }; })(jQuery); /** - * Plugin mage and group of heplers for it + * Plugin mage and group of helpers for it */ (function($) { "use strict"; @@ -44,9 +63,8 @@ * @param {} * @return {Object} */ - $.fn.mage = function() { - var name = arguments[0], - args = Array.prototype.slice.call(arguments, 1); + $.fn.mage = function(name) { + var args = Array.prototype.slice.call(arguments, 1); return this.each(function(){ var inits = _getInitData(this); if (name) { @@ -66,18 +84,30 @@ /** * Execute initialization callback when all resources are loaded * @param {Array} args - list of resources - * @param {Function} handler - initialization callback + * @param {(Function|undefined)} handler - initialization callback * @private */ function _onload(args, handler) { - args.push(handler); - head.js.apply(head, args); + args = $.grep(args, function(resource) { + var script = $('script[src="' + resource + '"]'); + return !script.length || typeof script[0].onload === 'function'; + }); + + if (typeof handler === 'function' && args.length) { + args.push(handler); + } + + if (args.length) { + head.js.apply(head, args); + } else { + handler(); + } } /** * Run initialization of a component - * @param {Object} init - setting for a component in format - * {name: {string}[, options: {Object}][, args: {Array}][, resources: {Array}]} + * @param {String} name + * @param {Array} args * @private */ function _initComponent(name, args) { @@ -100,13 +130,13 @@ } // Build an initialization handler var handler = $.proxy(function() { - this[init.name].apply(this, init.args); + if (typeof this[init.name] === 'function') { + this[init.name].apply(this, init.args); + } else if ($.mage.isDevMode()) { + console.error('Cannot initialize components "' + init.name + '"'); + } }, $(this)); - if (init.resources.length) { - _onload(init.resources, handler); - } else { - handler(); - } + _onload(init.resources, handler); } /** @@ -175,9 +205,9 @@ /** * Declare a new component or several components at a time in the mage widget * @param {(string|Object)} component - name of component - * or several componets with lists of required resources + * or several components with lists of required resources * {component1: {Array}, component2: {Array}} - * @param {(string|Array)} resources - URL of one resource or list of URLs + * @param {(string|Array)} component - URL of one resource or list of URLs * @return {Object} $.mage */ component: function(component) { @@ -192,7 +222,7 @@ /** * Helper allows easily bind handler with component's initialisation * @param {string} component - name of a component - * which initialization shold be customized + * which initialization should be customized * @param {(string|Function)} selector [optional]- filter of component's elements * or a handler function if selector is not defined * @param {Function} handler - handler function @@ -213,14 +243,14 @@ /** * Load all resource for certain component or several components - * @param {string} component - name of a component + * @param {String} component - name of a component * (several components may be passed also as separate arguments) * @return {Object} $.mage */ - load: function() { + load: function(component) { $.each(arguments, function(i, component) { if (_resources[component] && _resources[component].length) { - head.js.apply(head, _resources[component]); + _onload(_resources[component]); } }); return this; diff --git a/pub/lib/mage/validation.js b/pub/lib/mage/validation.js index 8906c55a4af..5cb77cb5a6d 100644 --- a/pub/lib/mage/validation.js +++ b/pub/lib/mage/validation.js @@ -785,12 +785,6 @@ }, 'Please select a file' ], - 'validate-super-product-attributes': [ - function(v) { - return (v !== "no-attributes"); - }, - 'Please select one or more attributes.' - ], "validate-ajax-error": [ function(v, element) { element = $(element); -- GitLab