From b7dc90c8630a7584451503009c193036d7bfb2dc Mon Sep 17 00:00:00 2001 From: Lee Saferite Date: Wed, 8 Dec 2010 17:38:07 -0500 Subject: [PATCH] Import Magento Release 1.4.2.0 --- RELEASE_NOTES.txt | 1016 ++ app/Mage.php | 4 +- .../Find/Feed/Block/Adminhtml/Edit/Codes.php | 64 + .../Block/Adminhtml/Edit/Codes/Edit/Form.php | 124 + .../Find/Feed/Block/Adminhtml/List/Codes.php | 53 + .../Feed/Block/Adminhtml/List/Codes/Grid.php | 131 + .../Find/Feed/Block/Adminhtml/List/Items.php | 51 + .../Feed/Block/Adminhtml/List/Items/Grid.php | 183 + app/code/community/Find/Feed/Helper/Data.php | 69 + .../System/Source/Cron/Frequency.php | 63 + .../Adminhtml/System/Source/Cron/Hours.php | 50 + app/code/community/Find/Feed/Model/Codes.php | 43 + app/code/community/Find/Feed/Model/Import.php | 241 + .../Find/Feed/Model/Mysql4/Codes.php} | 31 +- .../Feed/Model/Mysql4/Codes/Collection.php | 55 + .../Find/Feed/Model/Mysql4/Setup.php} | 29 +- .../community/Find/Feed/Model/Observer.php | 92 + .../Adminhtml/Codes/GridController.php | 161 + .../Adminhtml/Items/GridController.php | 115 + .../community/Find/Feed/etc/adminhtml.xml | 51 + app/code/community/Find/Feed/etc/config.xml | 480 + app/code/community/Find/Feed/etc/system.xml | 128 + .../find_feed_setup/mysql4-install-0.0.1.php | 41 + .../mysql4-upgrade-0.0.1-0.0.2.php | 50 + .../controllers/ProcessingController.php | 16 +- .../Block/Catalog/Category/Edit/Form.php | 31 +- .../Catalog/Category/Helper/Pricestep.php | 64 + .../Block/Catalog/Category/Tab/Attributes.php | 17 +- .../Block/Catalog/Category/Tab/General.php | 18 +- .../Adminhtml/Block/Catalog/Category/Tabs.php | 9 + .../Block/Catalog/Category/Widget/Chooser.php | 5 +- .../Form/Renderer/Attribute/Urlkey.php | 6 +- .../Form/Renderer/Fieldset/Element.php | 12 +- .../Product/Attribute/Edit/Tab/Main.php | 15 +- .../Adminhtml/Block/Catalog/Product/Edit.php | 2 +- .../Catalog/Product/Edit/Tab/Related.php | 13 +- .../Product/Edit/Tab/Super/Config/Simple.php | 13 +- .../Block/Catalog/Product/Edit/Tab/Tag.php | 2 +- .../Catalog/Product/Edit/Tab/Tag/Customer.php | 2 +- .../Block/Catalog/Product/Edit/Tabs.php | 10 +- .../Adminhtml/Block/Catalog/Product/Grid.php | 4 +- .../Catalog/Product/Helper/Form/Gallery.php | 4 +- .../Block/Catalog/Product/Widget/Chooser.php | 6 +- .../Adminhtml/Block/Customer/Edit/Form.php | 7 +- .../Block/Customer/Edit/Tab/Account.php | 37 +- .../Block/Customer/Edit/Tab/Addresses.php | 47 +- .../Block/Customer/Edit/Tab/Orders.php | 1 + .../Adminhtml/Block/Customer/Edit/Tab/Tag.php | 2 +- .../Block/Customer/Form/Element/Boolean.php | 56 + .../Block/Customer/Form/Element/File.php | 212 + .../Block/Customer/Form/Element/Image.php | 104 + .../core/Mage/Adminhtml/Block/Dashboard.php | 16 +- .../Mage/Adminhtml/Block/Dashboard/Grids.php | 4 +- .../Block/Dashboard/Tab/Products/Ordered.php | 18 +- .../Adminhtml/Block/Newsletter/Queue/Edit.php | 65 +- .../Block/Newsletter/Queue/Edit/Form.php | 87 +- .../Adminhtml/Block/Newsletter/Queue/Grid.php | 5 +- .../Newsletter/Queue/Grid/Renderer/Action.php | 6 +- .../Block/Newsletter/Queue/Preview.php | 79 + .../Block/Newsletter/Subscriber/Grid.php | 1 + .../Block/Newsletter/Template/Edit.php | 20 + .../Block/Newsletter/Template/Edit/Form.php | 12 +- .../Template/Grid/Renderer/Action.php | 6 + .../Block/Newsletter/Template/Preview.php | 17 +- .../Newsletter/Template/Preview/Form.php | 70 + .../Adminhtml/Block/Notification/Security.php | 93 + .../Block/Promo/Quote/Edit/Tab/Actions.php | 8 +- .../Block/Report/Shopcart/Product/Grid.php | 13 +- .../Block/Review/Grid/Renderer/Type.php | 9 +- .../Adminhtml/Block/Review/Product/Grid.php | 1 + .../Block/Review/Rating/Detailed.php | 16 +- .../Adminhtml/Block/Sales/Creditmemo/Grid.php | 2 +- .../Adminhtml/Block/Sales/Invoice/Grid.php | 2 +- .../Adminhtml/Block/Sales/Items/Abstract.php | 27 + .../Sales/Order/Create/Billing/Address.php | 48 +- .../Order/Create/Billing/Method/Form.php | 13 + .../Block/Sales/Order/Create/Form.php | 8 +- .../Sales/Order/Create/Form/Abstract.php | 186 + .../Block/Sales/Order/Create/Form/Account.php | 170 +- .../Block/Sales/Order/Create/Form/Address.php | 138 +- .../Sales/Order/Create/Giftmessage/Form.php | 22 +- .../Block/Sales/Order/Create/Items/Grid.php | 8 + .../Sales/Order/Create/Shipping/Address.php | 64 +- .../Order/Creditmemo/Create/Adjustments.php | 2 +- .../Sales/Order/Creditmemo/Create/Items.php | 6 +- .../Sales/Order/Shipment/Create/Items.php | 2 +- .../Mage/Adminhtml/Block/Sales/Order/View.php | 8 +- .../Adminhtml/Block/Sales/Order/View/Info.php | 56 + .../Adminhtml/Block/Sales/Shipment/Grid.php | 2 +- .../Block/Shipping/Carrier/Tablerate/Grid.php | 165 + .../Adminhtml/Block/System/Config/Form.php | 13 + .../System/Config/Form/Field/Heading.php | 4 +- .../Form/Fieldset/Modules/DisableOutput.php | 12 +- .../Block/System/Convert/Profile/Run.php | 379 +- .../Adminhtml/Block/Tag/Assigned/Grid.php | 10 +- .../Adminhtml/Block/Tag/Customer/Grid.php | 2 +- .../Mage/Adminhtml/Block/Tag/Grid/Pending.php | 24 +- .../Mage/Adminhtml/Block/Tag/Product/Grid.php | 2 +- .../Mage/Adminhtml/Block/Tag/Tag/Grid.php | 54 +- .../Adminhtml/Block/Urlrewrite/Edit/Form.php | 31 +- .../core/Mage/Adminhtml/Block/Widget/Form.php | 8 +- .../core/Mage/Adminhtml/Block/Widget/Grid.php | 41 +- .../Widget/Grid/Column/Renderer/Country.php | 2 +- .../Adminhtml/Block/Widget/Tab/Interface.php | 23 + .../Adminhtml/Controller/Sales/Creditmemo.php | 3 - .../Adminhtml/Controller/Sales/Invoice.php | 3 - .../Adminhtml/Controller/Sales/Shipment.php | 3 - .../Catalog/Product/Edit/Action/Attribute.php | 69 +- .../Model/Customer/Renderer/Region.php | 37 +- .../Mage/Adminhtml/Model/Giftmessage/Save.php | 30 +- .../core/Mage/Adminhtml/Model/Observer.php | 11 + .../Adminhtml/Model/Sales/Order/Create.php | 304 +- .../Backend/Customer/Address/Street.php | 83 + .../Config/Backend/Customer/Show/Address.php | 48 + .../Config/Backend/Customer/Show/Customer.php | 124 + .../Model/System/Config/Backend/Image.php | 96 +- .../System/Config/Backend/Image/Favicon.php | 82 + .../Model/System/Config/Backend/Secure.php | 39 + .../System/Config/Backend/Serialized.php | 3 +- .../Model/System/Config/Source/Price/Step.php | 42 + .../Config/Source/Shipping/Allowedmethods.php | 5 +- .../System/Config/Source/Web/Redirect.php | 38 + .../Adminhtml/controllers/CacheController.php | 2 +- .../Catalog/CategoryController.php | 40 +- .../Product/Action/AttributeController.php | 5 + .../Catalog/Product/AttributeController.php | 38 +- .../controllers/Catalog/ProductController.php | 37 +- .../controllers/Catalog/SearchController.php | 13 +- .../controllers/CustomerController.php | 339 +- .../Extensions/CustomController.php | 2 +- .../Newsletter/QueueController.php | 82 +- .../Newsletter/TemplateController.php | 64 +- .../Permissions/RoleController.php | 2 +- .../Sales/Order/CreateController.php | 11 +- .../Sales/Order/CreditmemoController.php | 11 +- .../Sales/Order/InvoiceController.php | 13 +- .../Sales/Order/ShipmentController.php | 9 +- .../controllers/Sales/OrderController.php | 19 +- .../controllers/System/ConfigController.php | 61 +- .../System/Convert/GuiController.php | 1 - .../System/Convert/ProfileController.php | 15 +- .../controllers/UrlrewriteController.php | 10 +- .../core/Mage/Adminhtml/etc/adminhtml.xml | 11 +- app/code/core/Mage/Adminhtml/etc/config.xml | 11 + app/code/core/Mage/Api/Model/Mysql4/Acl.php | 2 +- .../Mage/Api/Model/Server/Adapter/Soap.php | 104 +- .../Mage/Api/Model/Server/Adapter/Xmlrpc.php | 8 +- .../Api/Model/Server/Handler/Abstract.php | 9 + .../Mage/Api/Model/Server/V2/Adapter/Soap.php | 47 +- app/code/core/Mage/Api/Model/User.php | 2 +- app/code/core/Mage/Api/etc/config.xml | 1 + app/code/core/Mage/Api/etc/system.xml | 10 +- app/code/core/Mage/Api/etc/wsdl.xml | 2 +- .../Edit/Tab/Bundle/Option/Selection.php | 69 +- .../Block/Checkout/Cart/Item/Renderer.php | 47 +- .../Bundle/Model/Mysql4/Indexer/Price.php | 27 +- .../Bundle/Model/Mysql4/Option/Collection.php | 30 + .../Mage/Bundle/Model/Mysql4/Selection.php | 28 + .../Model/Mysql4/Selection/Collection.php | 40 + .../core/Mage/Bundle/Model/Product/Price.php | 12 +- .../core/Mage/Bundle/Model/Product/Type.php | 36 +- app/code/core/Mage/Bundle/Model/Selection.php | 23 + app/code/core/Mage/Bundle/etc/config.xml | 5 +- .../mysql4-upgrade-0.1.12-0.1.13.php | 54 + .../core/Mage/Catalog/Block/Breadcrumbs.php | 6 +- .../Mage/Catalog/Block/Layer/Filter/Price.php | 1 + .../core/Mage/Catalog/Block/Layer/View.php | 83 +- .../core/Mage/Catalog/Block/Navigation.php | 20 +- .../Mage/Catalog/Block/Product/Abstract.php | 14 +- .../Catalog/Block/Product/Compare/List.php | 4 +- .../core/Mage/Catalog/Block/Product/List.php | 30 +- .../core/Mage/Catalog/Block/Product/New.php | 7 + .../core/Mage/Catalog/Block/Product/Price.php | 13 + .../Catalog/Block/Product/View/Attributes.php | 26 +- .../Block/Product/View/Type/Configurable.php | 19 +- .../Mage/Catalog/Block/Product/Widget/New.php | 5 +- .../core/Mage/Catalog/Block/Widget/Link.php | 13 +- app/code/core/Mage/Catalog/Helper/Output.php | 8 +- app/code/core/Mage/Catalog/Helper/Product.php | 60 + app/code/core/Mage/Catalog/Model/Abstract.php | 31 + app/code/core/Mage/Catalog/Model/Category.php | 32 +- .../core/Mage/Catalog/Model/Category/Api.php | 37 +- .../Category/Attribute/Backend/Image.php | 4 +- .../Category/Attribute/Backend/Sortby.php | 38 +- .../Model/Category/Indexer/Product.php | 2 +- .../Catalog/Model/Convert/Adapter/Product.php | 7 +- .../Catalog/Model/Convert/Parser/Product.php | 2 +- app/code/core/Mage/Catalog/Model/Design.php | 177 +- .../core/Mage/Catalog/Model/Indexer/Url.php | 8 +- app/code/core/Mage/Catalog/Model/Layer.php | 22 +- .../Catalog/Model/Layer/Filter/Category.php | 7 + .../Catalog/Model/Layer/Filter/Decimal.php | 12 +- .../Mage/Catalog/Model/Layer/Filter/Price.php | 86 +- app/code/core/Mage/Catalog/Model/Product.php | 53 +- .../core/Mage/Catalog/Model/Product/Api.php | 2 + .../Mage/Catalog/Model/Product/Api/V2.php | 4 +- .../Model/Product/Attribute/Backend/Media.php | 34 +- .../Product/Attribute/Backend/Tierprice.php | 50 +- .../Model/Product/Attribute/Media/Api.php | 38 + .../Model/Product/Attribute/Media/Api/V2.php | 143 +- .../Model/Product/Attribute/Source/Layout.php | 2 +- .../Catalog/Model/Product/Indexer/Price.php | 4 +- .../Model/Product/Option/Type/File.php | 35 +- .../Catalog/Model/Product/Type/Abstract.php | 43 +- .../Model/Product/Type/Configurable.php | 19 + .../Model/Product/Type/Configurable/Price.php | 7 +- .../core/Mage/Catalog/Model/Product/Url.php | 10 +- .../Model/Resource/Eav/Mysql4/Abstract.php | 19 +- .../Model/Resource/Eav/Mysql4/Category.php | 38 +- .../Category/Attribute/Source/Layout.php | 2 +- .../Resource/Eav/Mysql4/Category/Flat.php | 36 +- .../Eav/Mysql4/Category/Indexer/Product.php | 132 +- .../Eav/Mysql4/Layer/Filter/Price.php | 10 +- .../Model/Resource/Eav/Mysql4/Product.php | 48 +- .../Mysql4/Product/Attribute/Collection.php | 64 +- .../Eav/Mysql4/Product/Collection.php | 274 +- .../Eav/Mysql4/Product/Compare/Item.php | 19 +- .../Resource/Eav/Mysql4/Product/Flat.php | 6 +- .../Eav/Mysql4/Product/Flat/Indexer.php | 15 +- .../Eav/Mysql4/Product/Option/Collection.php | 12 + .../Model/Resource/Eav/Mysql4/Setup.php | 24 +- .../Catalog/Model/Resource/Eav/Mysql4/Url.php | 212 +- .../Config/Backend/Catalog/Category/Flat.php | 46 + .../Config/Backend/Catalog/Product/Flat.php | 46 + .../Backend/Catalog/Url/Rewrite/Suffix.php | 42 + app/code/core/Mage/Catalog/Model/Url.php | 188 +- .../controllers/CategoryController.php | 81 +- .../Catalog/controllers/ProductController.php | 84 +- app/code/core/Mage/Catalog/etc/config.xml | 10 +- app/code/core/Mage/Catalog/etc/system.xml | 32 +- app/code/core/Mage/Catalog/etc/widget.xml | 2 +- .../mysql4-upgrade-0.7.71-0.7.72.php | 2 +- .../mysql4-upgrade-1.4.0.0.14-1.4.0.0.15.php | 9 - .../mysql4-upgrade-1.4.0.0.28-1.4.0.0.29.php | 99 + .../mysql4-upgrade-1.4.0.0.30-1.4.0.0.31.php | 36 + .../mysql4-upgrade-1.4.0.0.31-1.4.0.0.32.php | 34 + .../mysql4-upgrade-1.4.0.0.32-1.4.0.0.33.php | 41 + .../mysql4-upgrade-1.4.0.0.33-1.4.0.0.34.php | 32 + .../mysql4-upgrade-1.4.0.0.34-1.4.0.0.35.php | 35 + .../mysql4-upgrade-1.4.0.0.35-1.4.0.0.36.php | 47 + .../mysql4-upgrade-1.4.0.0.36-1.4.0.0.37.php | 81 + .../mysql4-upgrade-1.4.0.0.37-1.4.0.0.38.php | 31 + .../CatalogInventory/Model/Indexer/Stock.php | 21 +- .../Model/Mysql4/Indexer/Stock.php | 12 + .../Model/Mysql4/Indexer/Stock/Default.php | 2 +- .../Mage/CatalogInventory/Model/Observer.php | 143 +- .../Mage/CatalogInventory/Model/Stock.php | 5 +- .../CatalogInventory/Model/Stock/Item.php | 95 +- .../System/Config/Backend/Qtyincrements.php | 43 + .../core/Mage/CatalogInventory/etc/config.xml | 8 + .../core/Mage/CatalogInventory/etc/system.xml | 1 + .../core/Mage/CatalogRule/Helper/Data.php | 27 +- .../Mage/CatalogRule/Model/Mysql4/Rule.php | 88 +- .../core/Mage/CatalogRule/Model/Observer.php | 150 +- app/code/core/Mage/CatalogRule/Model/Rule.php | 46 + .../Model/Rule/Condition/Product.php | 129 +- app/code/core/Mage/CatalogRule/etc/config.xml | 24 + .../core/Mage/CatalogSearch/Block/Layer.php | 23 +- .../core/Mage/CatalogSearch/Block/Result.php | 25 +- .../core/Mage/CatalogSearch/Helper/Data.php | 43 +- .../Mage/CatalogSearch/Model/Advanced.php | 168 +- .../Mage/CatalogSearch/Model/Fulltext.php | 19 +- .../CatalogSearch/Model/Indexer/Fulltext.php | 82 +- .../core/Mage/CatalogSearch/Model/Layer.php | 20 +- .../CatalogSearch/Model/Mysql4/Advanced.php | 105 +- .../Model/Mysql4/Advanced/Collection.php | 26 +- .../CatalogSearch/Model/Mysql4/Fulltext.php | 118 +- .../Model/Mysql4/Fulltext/Collection.php | 10 + .../Model/Mysql4/Fulltext/Engine.php | 31 +- .../Model/Mysql4/Indexer/Fulltext.php} | 41 +- .../Mage/CatalogSearch/Model/Mysql4/Query.php | 9 +- .../core/Mage/CatalogSearch/Model/Query.php | 14 + .../core/Mage/CatalogSearch/etc/config.xml | 7 + app/code/core/Mage/Centinel/Model/Service.php | 7 +- .../core/Mage/Centinel/Model/State/Jcb.php | 23 +- .../Mage/Centinel/Model/State/Mastercard.php | 33 +- .../core/Mage/Centinel/Model/State/Visa.php | 36 +- .../Mage/Centinel/Model/StateAbstract.php | 24 +- app/code/core/Mage/Centinel/etc/config.xml | 4 +- .../Checkout/Block/Cart/Item/Renderer.php | 64 +- .../Mage/Checkout/Block/Cart/Shipping.php | 7 +- .../core/Mage/Checkout/Block/Cart/Sidebar.php | 2 +- .../Block/Multishipping/Addresses.php | 5 +- .../Mage/Checkout/Block/Onepage/Abstract.php | 6 +- .../Mage/Checkout/Block/Onepage/Billing.php | 59 +- app/code/core/Mage/Checkout/Helper/Data.php | 2 +- app/code/core/Mage/Checkout/Model/Cart.php | 69 +- .../core/Mage/Checkout/Model/Cart/Api.php | 58 + .../core/Mage/Checkout/Model/Cart/Api/V2.php | 36 + .../Model/Mysql4/Agreement/Collection.php | 18 +- app/code/core/Mage/Checkout/Model/Session.php | 100 +- .../Checkout/Model/Type/Multishipping.php | 45 +- .../core/Mage/Checkout/Model/Type/Onepage.php | 186 +- .../Checkout/controllers/CartController.php | 2 + .../controllers/MultishippingController.php | 3 +- .../controllers/OnepageController.php | 7 +- app/code/core/Mage/Checkout/etc/api.xml | 56 + app/code/core/Mage/Checkout/etc/config.xml | 11 + app/code/core/Mage/Checkout/etc/wsdl.xml | 354 + app/code/core/Mage/Cms/Model/Mysql4/Block.php | 20 +- .../Cms/Model/Mysql4/Block/Collection.php | 44 +- .../Mage/Cms/Model/Mysql4/Page/Collection.php | 32 +- .../Mage/Cms/Model/Mysql4/Page/Service.php | 82 + .../core/Mage/Compiler/etc/compilation.xml | 20 +- app/code/core/Mage/Core/Block/Abstract.php | 16 +- .../core/Mage/Core/Block/Html/Calendar.php | 2 +- app/code/core/Mage/Core/Block/Html/Select.php | 15 +- app/code/core/Mage/Core/Block/Template.php | 12 +- .../Mage/Core/Controller/Request/Http.php | 89 +- .../Mage/Core/Controller/Varien/Action.php | 5 + .../Mage/Core/Controller/Varien/Front.php | 13 +- .../Core/Controller/Varien/Router/Admin.php | 11 +- .../Core/Controller/Varien/Router/Default.php | 37 +- .../Controller/Varien/Router/Standard.php | 16 +- app/code/core/Mage/Core/Helper/Data.php | 9 +- app/code/core/Mage/Core/Helper/Js.php | 36 +- app/code/core/Mage/Core/Helper/Url.php | 5 +- .../core/Mage/Core/Helper/Url/Rewrite.php | 97 + app/code/core/Mage/Core/Model/Abstract.php | 14 +- app/code/core/Mage/Core/Model/App.php | 7 +- app/code/core/Mage/Core/Model/Config.php | 14 +- .../core/Mage/Core/Model/Design/Package.php | 15 +- .../Mage/Core/Model/Design/Source/Apply.php | 4 +- .../core/Mage/Core/Model/Email/Template.php | 137 +- app/code/core/Mage/Core/Model/Layout.php | 2 +- .../core/Mage/Core/Model/Mysql4/Abstract.php | 23 + .../Core/Model/Mysql4/Collection/Abstract.php | 59 +- .../core/Mage/Core/Model/Mysql4/Config.php | 3 + .../Mage/Core/Model/Mysql4/Url/Rewrite.php | 51 + .../core/Mage/Core/Model/Session/Abstract.php | 4 +- .../Core/Model/Session/Abstract/Varien.php | 13 +- .../Mage/Core/Model/Session/Abstract/Zend.php | 1 + app/code/core/Mage/Core/Model/Store.php | 56 +- app/code/core/Mage/Core/Model/Template.php | 196 + app/code/core/Mage/Core/Model/Url.php | 21 +- app/code/core/Mage/Core/Model/Url/Rewrite.php | 48 +- app/code/core/Mage/Core/etc/config.xml | 2 +- app/code/core/Mage/Core/etc/system.xml | 25 +- .../mysql4-upgrade-0.8.26-0.8.27.php} | 12 +- .../Block/Address/Renderer/Default.php | 66 +- .../Mage/Customer/Block/Form/Register.php | 57 +- .../Mage/Customer/Block/Widget/Abstract.php | 11 + .../core/Mage/Customer/Block/Widget/Dob.php | 4 +- .../Mage/Customer/Block/Widget/Gender.php | 4 +- .../core/Mage/Customer/Block/Widget/Name.php | 24 +- .../Mage/Customer/Block/Widget/Taxvat.php | 4 +- .../core/Mage/Customer/Helper/Address.php | 78 +- app/code/core/Mage/Customer/Model/Address.php | 25 + .../Mage/Customer/Model/Address/Abstract.php | 9 +- .../Mage/Customer/Model/Address/Config.php | 101 +- .../core/Mage/Customer/Model/Attribute.php | 156 +- .../Mage/Customer/Model/Attribute/Data.php | 85 + .../Model/Attribute/Data/Abstract.php | 513 + .../Customer/Model/Attribute/Data/Boolean.php | 58 + .../Customer/Model/Attribute/Data/Date.php | 137 + .../Customer/Model/Attribute/Data/File.php | 265 + .../Model/Attribute/Data/Hidden.php} | 12 +- .../Customer/Model/Attribute/Data/Image.php | 96 + .../Model/Attribute/Data/Multiline.php | 154 + .../Model/Attribute/Data/Multiselect.php | 96 + .../Model/Attribute/Data/Postcode.php | 53 + .../Customer/Model/Attribute/Data/Select.php | 139 + .../Customer/Model/Attribute/Data/Text.php | 135 + .../Model/Attribute/Data/Textarea.php} | 15 +- .../Model/Convert/Adapter/Customer.php | 14 +- .../core/Mage/Customer/Model/Customer.php | 60 +- .../core/Mage/Customer/Model/Customer/Api.php | 21 + .../Mage/Customer/Model/Customer/Api/V2.php | 46 +- .../Customer/Attribute/Backend/Password.php | 10 +- .../Entity/Address/Attribute/Collection.php | 34 +- .../Mage/Customer/Model/Entity/Attribute.php | 134 +- .../Model/Entity/Attribute/Collection.php | 158 +- .../Model/Entity/Customer/Collection.php | 6 +- .../Customer/Model/Entity/Form/Attribute.php | 59 + .../Entity/Form/Attribute/Collection.php | 225 + .../core/Mage/Customer/Model/Entity/Setup.php | 4 +- app/code/core/Mage/Customer/Model/Form.php | 513 + .../controllers/AccountController.php | 195 +- .../controllers/AddressController.php | 75 +- app/code/core/Mage/Customer/etc/config.xml | 90 +- app/code/core/Mage/Customer/etc/system.xml | 57 + app/code/core/Mage/Customer/etc/wsdl.xml | 7 + ...ql4-data-upgrade-1.4.0.0.11-1.4.0.0.12.php | 43 + ...ysql4-data-upgrade-1.4.0.0.7-1.4.0.0.8.php | 351 + ...ysql4-data-upgrade-1.4.0.0.8-1.4.0.0.9.php | 119 + .../mysql4-upgrade-1.4.0.0.10-1.4.0.0.11.php | 34 + .../mysql4-upgrade-1.4.0.0.12-1.4.0.0.13.php | 50 + .../mysql4-upgrade-1.4.0.0.7-1.4.0.0.8.php | 56 + .../mysql4-upgrade-1.4.0.0.8-1.4.0.0.9.php | 48 + .../mysql4-upgrade-1.4.0.0.9-1.4.0.0.10.php | 32 + app/code/core/Mage/Dataflow/Model/Profile.php | 9 + app/code/core/Mage/Dataflow/etc/config.xml | 9 + app/code/core/Mage/Directory/etc/config.xml | 2 +- .../mysql4-upgrade-0.8.10-0.8.11.php | 219 + .../Product/Edit/Tab/Downloadable/Links.php | 2 +- .../Product/Edit/Tab/Downloadable/Samples.php | 2 +- .../Mage/Downloadable/Model/Mysql4/Sample.php | 11 +- .../Mage/Downloadable/Model/Product/Type.php | 7 + .../controllers/CustomerController.php | 4 + .../core/Mage/Downloadable/etc/config.xml | 1 + .../core/Mage/Downloadable/etc/system.xml | 2 +- app/code/core/Mage/Eav/Model/Config.php | 6 +- .../Mage/Eav/Model/Convert/Adapter/Entity.php | 6 + .../core/Mage/Eav/Model/Entity/Abstract.php | 56 +- .../core/Mage/Eav/Model/Entity/Attribute.php | 19 +- .../Eav/Model/Entity/Attribute/Abstract.php | 12 +- .../Entity/Attribute/Backend/Datetime.php | 5 + .../Mage/Eav/Model/Entity/Attribute/Set.php | 19 + .../Model/Entity/Attribute/Source/Table.php | 32 +- .../Eav/Model/Entity/Collection/Abstract.php | 11 +- .../Model/Mysql4/Entity/Attribute/Option.php | 26 +- .../Eav/Model/Mysql4/Entity/Attribute/Set.php | 16 + .../Mage/GiftMessage/Block/Message/Inline.php | 130 +- .../core/Mage/GiftMessage/Helper/Message.php | 12 +- .../core/Mage/GiftMessage/Model/Observer.php | 24 +- app/code/core/Mage/GiftMessage/etc/config.xml | 18 +- .../core/Mage/GiftRegistry/etc/config.xml | 84 - .../core/Mage/GoogleAnalytics/Block/Ga.php | 189 +- .../core/Mage/GoogleAnalytics/Helper/Data.php | 16 + .../Mage/GoogleAnalytics/Model/Observer.php | 56 +- .../core/Mage/GoogleAnalytics/etc/config.xml | 8 + .../Model/Mysql4/Item/Collection.php | 2 +- .../Mage/GoogleBase/Model/Service/Feed.php | 44 +- .../Mage/GoogleBase/Model/Service/Item.php | 41 +- .../core/Mage/GoogleCheckout/Block/Link.php | 7 +- .../GoogleCheckout/Model/Api/Xml/Callback.php | 348 +- .../GoogleCheckout/Model/Api/Xml/Checkout.php | 8 +- .../Model/Mysql4/Notification.php | 104 + .../GoogleCheckout/Model/Notification.php | 120 + .../Mage/GoogleCheckout/Model/Observer.php | 24 +- .../Mage/GoogleCheckout/Model/Shipping.php | 24 +- .../controllers/RedirectController.php | 38 +- .../core/Mage/GoogleCheckout/etc/config.xml | 4 +- .../core/Mage/GoogleCheckout/etc/system.xml | 13 +- .../mysql4-upgrade-0.7.3-0.7.4.php | 38 + app/code/core/Mage/Index/Model/Process.php | 15 +- app/code/core/Mage/Install/Block/State.php | 30 + .../core/Mage/Install/Model/Installer.php | 7 + .../Mage/Install/Model/Installer/Config.php | 11 +- .../Mage/Install/Model/Installer/Console.php | 2 + .../core/Mage/Install/Model/Installer/Db.php | 5 +- .../Mage/Newsletter/Model/Mysql4/Queue.php | 35 +- .../Model/Mysql4/Queue/Collection.php | 2 +- app/code/core/Mage/Newsletter/Model/Queue.php | 218 +- .../core/Mage/Newsletter/Model/Subscriber.php | 51 +- .../core/Mage/Newsletter/Model/Template.php | 34 +- .../Mage/Newsletter/Model/Template/Filter.php | 2 +- .../controllers/SubscriberController.php | 4 +- app/code/core/Mage/Newsletter/etc/config.xml | 2 +- .../mysql4-upgrade-0.8.2-0.8.3.php | 88 + app/code/core/Mage/Page/Block/Html/Head.php | 33 + .../core/Mage/Page/Block/Html/Welcome.php | 45 + .../core/Mage/Page/Block/Template/Links.php | 70 +- .../Mage/Page/Block/Template/Links/Block.php | 201 + app/code/core/Mage/Page/Helper/Layout.php | 5 + app/code/core/Mage/Page/etc/config.xml | 2 +- app/code/core/Mage/Page/etc/system.xml | 11 + .../core/Mage/Paygate/Model/Authorizenet.php | 3 +- .../Mage/Payment/Block/Form/Container.php | 11 +- app/code/core/Mage/Payment/Block/Info/Cc.php | 12 +- .../Mage/Payment/Model/Billing/Agreement.php | 110 - .../Model/Billing/AgreementAbstract.php | 4 +- app/code/core/Mage/Payment/Model/Config.php | 14 +- .../core/Mage/Payment/Model/Method/Cc.php | 5 +- .../core/Mage/Payment/Model/Method/Free.php | 21 + .../Mage/Payment/Model/Recurring/Profile.php | 63 +- app/code/core/Mage/Payment/etc/config.xml | 13 +- .../Adminhtml/System/Config/ApiWizard.php | 3 + .../Mage/Paypal/Block/Express/Shortcut.php | 5 +- .../Paypal/Controller/Express/Abstract.php | 43 +- app/code/core/Mage/Paypal/Helper/Data.php | 149 - .../core/Mage/Paypal/Model/Api/Abstract.php | 60 +- app/code/core/Mage/Paypal/Model/Api/Nvp.php | 114 +- .../core/Mage/Paypal/Model/Api/Standard.php | 94 +- app/code/core/Mage/Paypal/Model/Cart.php | 467 + app/code/core/Mage/Paypal/Model/Config.php | 6 +- app/code/core/Mage/Paypal/Model/Direct.php | 15 +- app/code/core/Mage/Paypal/Model/Express.php | 12 +- .../Mage/Paypal/Model/Express/Checkout.php | 42 +- app/code/core/Mage/Paypal/Model/Ipn.php | 3 + .../Mage/Paypal/Model/Method/Agreement.php | 14 +- .../core/Mage/Paypal/Model/Payflowpro.php | 74 +- app/code/core/Mage/Paypal/Model/Pro.php | 20 +- .../Mage/Paypal/Model/Report/Settlement.php | 9 +- app/code/core/Mage/Paypal/Model/Standard.php | 23 +- app/code/core/Mage/Paypal/etc/system.xml | 7 +- app/code/core/Mage/PaypalUk/Model/Api/Nvp.php | 31 +- .../core/Mage/ProductAlert/Block/Price.php | 8 +- .../Mage/ProductAlert/Block/Product/View.php | 81 + .../core/Mage/ProductAlert/Block/Stock.php | 7 +- .../Mage/Reports/Block/Product/Abstract.php | 3 +- .../Reports/Model/Mysql4/Order/Collection.php | 6 +- .../Model/Mysql4/Product/Index/Abstract.php | 6 +- .../Product/Index/Collection/Abstract.php | 2 +- .../Model/Mysql4/Product/Sold/Collection.php | 8 +- .../Reports/Model/Mysql4/Quote/Collection.php | 69 +- .../Model/Mysql4/Report/Collection.php | 2 +- app/code/core/Mage/Review/Block/Form.php | 16 +- app/code/core/Mage/Review/Helper/Data.php | 9 + .../Mysql4/Review/Product/Collection.php | 1 + .../Review/controllers/ProductController.php | 7 +- .../core/Mage/Rss/Block/Catalog/Special.php | 134 +- app/code/core/Mage/Rss/etc/config.xml | 3 +- .../Mage/Rule/Model/Condition/Abstract.php | 7 +- app/code/core/Mage/Rule/Model/Rule.php | 8 +- .../Adminhtml/Customer/Edit/Tab/Agreement.php | 4 +- .../Customer/Edit/Tab/Recurring/Profile.php | 112 + .../Recurring/Profile/View/Tab/Orders.php | 2 +- .../Sales/Block/Billing/Agreement/View.php | 8 +- .../Mage/Sales/Block/Billing/Agreements.php | 5 +- .../core/Mage/Sales/Block/Order/Comments.php | 102 + .../Sales/Block/Order/Creditmemo/Items.php | 18 + .../Mage/Sales/Block/Order/Invoice/Items.php | 18 + .../Block/Order/Item/Renderer/Default.php | 4 +- .../Mage/Sales/Block/Order/Print/Shipment.php | 104 +- .../Mage/Sales/Block/Order/Shipment/Items.php | 18 + .../Sales/Block/Recurring/Profile/View.php | 71 +- .../Mage/Sales/Model/Billing/Agreement.php | 3 +- .../Address/Attribute/Frontend/Shipping.php | 12 +- .../Model/Mysql4/Collection/Abstract.php | 3 - .../Mage/Sales/Model/Mysql4/Order/Address.php | 30 + .../Model/Mysql4/Order/Address/Collection.php | 16 + .../Sales/Model/Mysql4/Order/Collection.php | 2 +- .../Order/Comment/Collection/Abstract.php | 68 + .../Order/Creditmemo/Comment/Collection.php | 30 +- .../Model/Mysql4/Order/Grid/Collection.php | 22 + .../Order/Invoice/Comment/Collection.php | 30 +- .../Order/Shipment/Comment/Collection.php | 30 +- .../Address/Attribute/Frontend/Shipping.php | 12 +- .../Model/Mysql4/Quote/Address/Collection.php | 19 + .../Model/Mysql4/Quote/Item/Collection.php | 45 +- .../Mysql4/Quote/Item/Option/Collection.php | 84 +- app/code/core/Mage/Sales/Model/Order.php | 6 +- app/code/core/Mage/Sales/Model/Order/Api.php | 12 + .../core/Mage/Sales/Model/Order/Api/V2.php | 14 +- .../Mage/Sales/Model/Order/Creditmemo.php | 14 +- .../Sales/Model/Order/Creditmemo/Item.php | 18 +- .../Model/Order/Creditmemo/Total/Shipping.php | 27 +- .../Model/Order/Creditmemo/Total/Tax.php | 16 +- .../core/Mage/Sales/Model/Order/Invoice.php | 14 +- app/code/core/Mage/Sales/Model/Order/Item.php | 20 + .../core/Mage/Sales/Model/Order/Payment.php | 46 +- .../Mage/Sales/Model/Order/Pdf/Abstract.php | 22 +- .../Mage/Sales/Model/Order/Pdf/Creditmemo.php | 1 + .../Mage/Sales/Model/Order/Pdf/Invoice.php | 1 + .../Mage/Sales/Model/Order/Pdf/Shipment.php | 3 +- .../core/Mage/Sales/Model/Order/Shipment.php | 33 +- app/code/core/Mage/Sales/Model/Quote.php | 61 +- .../core/Mage/Sales/Model/Quote/Address.php | 88 +- .../Model/Quote/Address/Total/Shipping.php | 15 +- .../Model/Quote/Address/Total/Subtotal.php | 8 +- .../core/Mage/Sales/Model/Quote/Config.php | 3 + app/code/core/Mage/Sales/Model/Quote/Item.php | 92 +- .../Mage/Sales/Model/Quote/Item/Abstract.php | 81 +- .../Mage/Sales/Model/Quote/Item/Option.php | 14 + .../core/Mage/Sales/Model/Quote/Payment.php | 6 +- .../Mage/Sales/Model/Recurring/Profile.php | 6 + .../Sales/controllers/DownloadController.php | 98 +- app/code/core/Mage/Sales/etc/config.xml | 7 +- app/code/core/Mage/Sales/etc/wsdl.xml | 5 + .../mysql4-upgrade-0.9.28-0.9.29.php | 30 +- .../mysql4-upgrade-1.3.99-1.4.0.0.php | 34 + .../mysql4-upgrade-1.4.0.15-1.4.0.16.php | 31 + .../mysql4-upgrade-1.4.0.16-1.4.0.17.php | 43 + .../mysql4-upgrade-1.4.0.17-1.4.0.18.php | 37 + .../mysql4-upgrade-1.4.0.18-1.4.0.19.php | 33 + .../mysql4-upgrade-1.4.0.19-1.4.0.20.php | 31 + .../mysql4-upgrade-1.4.0.20-1.4.0.21.php | 71 + .../SalesRule/Model/Mysql4/Report/Rule.php | 4 +- .../Mysql4/Report/Updatedat/Collection.php | 4 +- .../core/Mage/SalesRule/Model/Mysql4/Rule.php | 60 + .../Model/Mysql4/Rule/Collection.php | 3 +- .../core/Mage/SalesRule/Model/Observer.php | 107 +- .../Mage/SalesRule/Model/Quote/Discount.php | 2 + .../SalesRule/Model/Quote/Freeshipping.php | 11 +- app/code/core/Mage/SalesRule/Model/Rule.php | 40 +- .../Model/Rule/Condition/Product.php | 15 +- .../Rule/Condition/Product/Subselect.php | 2 +- .../core/Mage/SalesRule/Model/Validator.php | 177 +- app/code/core/Mage/SalesRule/etc/config.xml | 19 +- .../mysql4-upgrade-1.4.0.0.4-1.4.0.0.5.php | 67 + .../mysql4-upgrade-1.4.0.0.5-1.4.0.0.6.php | 52 + .../Mage/Shipping/Block/Tracking/Popup.php | 19 +- app/code/core/Mage/Shipping/Helper/Data.php | 12 +- .../Mage/Shipping/Model/Carrier/Abstract.php | 4 + .../Mage/Shipping/Model/Carrier/Tablerate.php | 6 +- app/code/core/Mage/Shipping/Model/Info.php | 9 +- .../Model/Mysql4/Carrier/Tablerate.php | 597 +- .../Mysql4/Carrier/Tablerate/Collection.php | 94 +- .../core/Mage/Shipping/Model/Rate/Request.php | 84 +- .../core/Mage/Shipping/Model/Shipping.php | 1 + .../Tag/Model/Mysql4/Customer/Collection.php | 3 +- .../Tag/Model/Mysql4/Product/Collection.php | 8 +- .../Mage/Tag/Model/Mysql4/Tag/Collection.php | 17 +- .../Mage/Tag/Model/Mysql4/Tag/Relation.php | 13 +- app/code/core/Mage/Tag/Model/Tag.php | 1 + app/code/core/Mage/Tag/Model/Tag/Relation.php | 6 +- .../Mage/Tag/controllers/IndexController.php | 68 +- app/code/core/Mage/Tax/Model/Calculation.php | 41 +- .../Mage/Tax/Model/Mysql4/Calculation.php | 124 +- .../Mysql4/Report/Updatedat/Collection.php | 46 +- app/code/core/Mage/Tax/Model/Observer.php | 18 +- .../Tax/Model/Sales/Total/Quote/Shipping.php | 21 +- .../Tax/Model/Sales/Total/Quote/Subtotal.php | 62 +- .../Mage/Tax/Model/Sales/Total/Quote/Tax.php | 33 +- app/code/core/Mage/Tax/etc/config.xml | 8 + .../Usa/Model/Shipping/Carrier/Abstract.php | 47 + .../Mage/Usa/Model/Shipping/Carrier/Dhl.php | 48 +- .../Mage/Usa/Model/Shipping/Carrier/Fedex.php | 61 +- .../Mage/Usa/Model/Shipping/Carrier/Ups.php | 124 +- .../Mage/Usa/Model/Shipping/Carrier/Usps.php | 355 +- .../Mage/Weee/Model/Total/Invoice/Weee.php | 20 + .../Widget/Block/Adminhtml/Widget/Chooser.php | 7 +- app/code/core/Mage/Wishlist/Block/Links.php | 29 +- .../default/default/layout/catalog.xml | 26 +- .../default/default/layout/dataflow.xml} | 43 +- .../adminhtml/default/default/layout/main.xml | 32 +- .../default/default/layout/newsletter.xml | 19 +- .../default/default/layout/sales.xml | 2 + .../default/default/layout/search.xml} | 18 +- .../bundle/product/edit/bundle/option.phtml | 2 +- .../edit/bundle/option/selection.phtml | 47 +- .../template/catalog/category/edit.phtml | 87 +- .../template/catalog/category/edit/form.phtml | 66 +- .../template/catalog/category/tree.phtml | 5 +- .../catalog/product/attribute/js.phtml | 18 +- .../catalog/product/edit/options/option.phtml | 2 +- .../catalog/product/tab/inventory.phtml | 3 +- .../template/customer/tab/addresses.phtml | 146 +- .../template/dashboard/graph/disabled.phtml} | 9 +- .../default/template/dashboard/index.phtml | 4 + .../default/default/template/login.phtml | 1 - .../template/newsletter/queue/edit.phtml | 48 +- .../template/newsletter/queue/preview.phtml} | 19 +- .../template/newsletter/template/edit.phtml | 11 +- .../template/preview/iframeswitcher.phtml | 88 + .../newsletter/template/preview/store.phtml | 60 + .../template/notification/security.phtml} | 11 +- .../default/template/payment/form/cc.phtml | 45 + .../template/payment/form/ccsave.phtml | 44 + .../paypal/system/config/api_wizard.phtml | 17 +- .../system/config/fieldset/global.phtml | 26 +- .../default/template/report/grid.phtml | 2 +- .../template/sales/order/comments/view.phtml | 9 +- .../sales/order/create/coupons/form.phtml | 4 + .../template/sales/order/create/form.phtml | 2 +- .../sales/order/create/form/address.phtml | 7 +- .../sales/order/create/giftmessage.phtml | 3 + .../template/sales/order/create/totals.phtml | 18 + .../sales/order/creditmemo/create/form.phtml | 4 +- .../sales/order/shipment/create/form.phtml | 3 + .../order/shipment/create/tracking.phtml | 4 +- .../template/sales/order/view/info.phtml | 40 +- .../sales/recurring/profile/view/info.phtml | 3 +- .../system/convert/profile/process.phtml | 205 + .../default/template/widget/grid.phtml | 5 +- .../template/widget/grid/serializer.phtml | 19 + .../default/find/layout/feed.xml} | 26 +- .../default/find/template/head/window.phtml | 42 + .../frontend/base/default/layout/bundle.xml | 12 - .../frontend/base/default/layout/catalog.xml | 22 +- .../frontend/base/default/layout/checkout.xml | 25 +- .../frontend/base/default/layout/cms.xml | 3 +- .../frontend/base/default/layout/customer.xml | 7 +- .../base/default/layout/googlecheckout.xml | 4 - .../base/default/layout/newsletter.xml | 3 +- .../frontend/base/default/layout/page.xml | 12 +- .../frontend/base/default/layout/paypal.xml | 5 +- .../frontend/base/default/layout/paypaluk.xml | 3 +- .../base/default/layout/productalert.xml | 13 +- .../frontend/base/default/layout/review.xml | 3 +- .../frontend/base/default/layout/sales.xml | 7 +- .../layout/sales/recurring_profile.xml | 1 + .../frontend/base/default/layout/tag.xml | 13 +- .../frontend/base/default/layout/wishlist.xml | 5 +- .../catalog/product/view/tierprices.phtml | 2 +- .../catalog/product/view/type/bundle.phtml | 2 + .../view/type/bundle/option/checkbox.phtml | 34 +- .../view/type/bundle/option/multi.phtml | 16 +- .../view/type/bundle/option/radio.phtml | 8 +- .../view/type/bundle/option/select.phtml | 12 +- .../template/catalog/layer/state.phtml | 12 +- .../catalog/product/compare/sidebar.phtml | 4 +- .../template/catalog/product/gallery.phtml | 15 +- .../template/catalog/product/list.phtml | 5 +- .../catalog/product/list/toolbar.phtml | 2 +- .../template/catalog/product/view.phtml | 9 +- .../catalog/product/view/addtocart.phtml | 2 +- .../product/view/options/type/date.phtml | 2 +- .../product/view/options/type/file.phtml | 24 +- .../product/view/options/type/select.phtml | 16 +- .../product/view/options/type/text.phtml | 16 +- .../catalog/product/view/tierprices.phtml | 2 +- .../product/view/type/configurable.phtml | 15 +- .../catalog/product/view/type/default.phtml} | 16 +- .../catalog/product/view/type/grouped.phtml | 17 +- .../view/type/options/configurable.phtml | 10 +- .../catalog/product/view/type/simple.phtml | 16 +- .../catalog/product/view/type/virtual.phtml | 16 +- .../widget/new/column/new_default_list.phtml | 2 +- .../widget/new/column/new_images_list.phtml | 2 +- .../widget/new/column/new_names_list.phtml | 4 +- .../base/default/template/checkout/cart.phtml | 4 +- .../template/checkout/cart/item/default.phtml | 7 +- .../template/checkout/cart/noItems.phtml | 8 +- .../template/checkout/cart/totals.phtml | 2 +- .../checkout/multishipping/link.phtml | 2 +- .../checkout/multishipping/state.phtml | 5 +- .../checkout/multishipping/success.phtml | 44 +- .../template/checkout/onepage/billing.phtml | 2 +- .../template/checkout/onepage/link.phtml | 2 +- .../checkout/onepage/payment/methods.phtml | 1 + .../template/checkout/onepage/progress.phtml | 2 +- .../template/checkout/onepage/review.phtml | 2 +- .../checkout/onepage/review/item.phtml | 3 + .../checkout/onepage/review/totals.phtml | 4 + .../default/template/checkout/success.phtml | 4 +- .../template/checkout/total/default.phtml | 4 +- .../template/customer/form/newsletter.phtml | 13 +- .../template/customer/widget/name.phtml | 3 + .../downloadable/catalog/product/links.phtml | 2 +- .../downloadable/catalog/product/type.phtml | 4 +- .../checkout/cart/item/default.phtml | 2 +- .../email/order/creditmemo/items.phtml | 12 +- .../template/email/order/invoice/items.phtml | 12 +- .../default/template/email/order/items.phtml | 27 +- .../order/items/creditmemo/default.phtml | 10 +- .../email/order/items/invoice/default.phtml | 10 +- .../email/order/items/order/default.phtml | 26 +- .../email/order/items/shipment/default.phtml | 6 +- .../template/email/order/shipment/items.phtml | 10 +- .../template/email/order/shipment/track.phtml | 8 +- .../template/email/productalert/price.phtml | 2 +- .../template/email/productalert/stock.phtml | 2 +- .../default/template/giftmessage/inline.phtml | 8 +- .../template/googlecheckout/link.phtml | 3 +- .../default/template/page/html/head.phtml | 4 +- .../default/template/page/html/pager.phtml | 8 +- .../template/page/template/links.phtml | 6 +- .../template/page/template/linksblock.phtml} | 19 +- .../default/template/payment/form/cc.phtml | 48 +- .../template/payment/form/ccsave.phtml | 49 + .../template/paypal/express/shortcut.phtml | 12 +- .../default/template/productalert/price.phtml | 8 +- .../template/productalert/product/view.phtml} | 11 +- .../default/template/productalert/stock.phtml | 8 +- .../default/template/rating/detailed.phtml | 2 +- .../reports/home_product_compared.phtml | 4 +- .../reports/home_product_viewed.phtml | 2 +- .../template/reports/product_compared.phtml | 2 +- .../template/reports/product_viewed.phtml | 2 +- .../column/compared_default_list.phtml | 2 +- .../column/compared_images_list.phtml | 2 +- .../compared/column/compared_names_list.phtml | 2 +- .../viewed/column/viewed_default_list.phtml | 2 +- .../viewed/column/viewed_images_list.phtml | 2 +- .../viewed/column/viewed_names_list.phtml | 2 +- .../template/review/customer/list.phtml | 2 +- .../base/default/template/review/form.phtml | 196 +- .../review/helper/summary_short.phtml | 2 +- .../template/sales/billing/agreements.phtml | 2 - .../template/sales/order/comments.phtml} | 28 +- .../template/sales/order/creditmemo.phtml | 62 +- .../sales/order/creditmemo/items.phtml | 76 +- .../template/sales/order/invoice.phtml | 62 +- .../template/sales/order/invoice/items.phtml | 68 +- .../template/sales/order/print/shipment.phtml | 47 +- .../template/sales/order/shipment.phtml | 60 +- .../template/sales/order/shipment/items.phtml | 79 +- .../default/template/sales/order/view.phtml | 22 +- .../sales/recurring/profile/view.phtml | 3 +- .../sales/recurring/profile/view/info.phtml | 23 +- .../template/shipping/tracking/popup.phtml | 162 +- .../default/template/tag/customer/view.phtml | 2 +- .../base/default/template/tag/popular.phtml | 2 +- .../template/wishlist/email/items.phtml | 14 +- .../default/template/wishlist/email/rss.phtml | 4 +- .../default/template/wishlist/shared.phtml | 12 +- .../default/template/wishlist/sharing.phtml | 7 +- .../base/default/template/wishlist/view.phtml | 12 +- .../frontend/default/iphone/layout/bundle.xml | 312 - .../default/iphone/layout/catalog.xml | 214 +- .../default/iphone/layout/catalogsearch.xml | 126 - .../default/iphone/layout/checkout.xml | 127 +- .../default/iphone/layout/contacts.xml | 44 - .../default/iphone/layout/customer.xml | 131 +- .../default/iphone/layout/directory.xml | 60 - .../default/iphone/layout/downloadable.xml | 182 - .../default/iphone/layout/giftmessage.xml | 71 - .../default/iphone/layout/newsletter.xml | 69 - .../frontend/default/iphone/layout/page.xml | 60 +- .../default/iphone/layout/productalert.xml | 40 - .../default/iphone/layout/reports.xml | 37 - .../frontend/default/iphone/layout/review.xml | 51 +- .../frontend/default/iphone/layout/rss.xml | 93 - .../frontend/default/iphone/layout/sales.xml | 257 - .../default/iphone/layout/shipping.xml | 51 - .../frontend/default/iphone/layout/tag.xml | 43 +- .../default/iphone/layout/wishlist.xml | 106 - .../default/iphone/locale/en_US/translate.csv | 7 + .../template/catalog/category/view.phtml | 48 - .../iphone/template/catalog/layer/state.phtml | 46 - .../iphone/template/catalog/layer/view.phtml | 62 - .../template/catalog/navigation/left.phtml | 61 - .../template/catalog/navigation/top.phtml | 44 - .../catalog/product/compare/list.phtml | 131 - .../catalog/product/compare/sidebar.phtml | 54 - .../template/catalog/product/gallery.phtml | 52 - .../template/catalog/product/list.phtml | 81 - .../catalog/product/list/crosssell.phtml | 51 - .../catalog/product/list/related.phtml | 99 - .../catalog/product/list/toolbar.phtml | 35 +- .../catalog/product/list/toolbar/pager.phtml | 68 - .../catalog/product/list/upsell.phtml | 48 - .../iphone/template/catalog/product/new.phtml | 65 - .../template/catalog/product/price.phtml | 358 - .../template/catalog/product/send.phtml | 141 - .../template/catalog/product/view.phtml | 121 - .../template/catalog/product/view/addto.phtml | 37 - .../catalog/product/view/addtocart.phtml | 40 - .../catalog/product/view/attributes.phtml | 45 - .../catalog/product/view/bundle.phtml | 205 - .../template/catalog/product/view/media.phtml | 66 - .../catalog/product/view/options.phtml | 180 - .../catalog/product/view/options/js.phtml | 63 - .../product/view/options/type/date.phtml | 90 - .../product/view/options/type/file.phtml | 41 - .../product/view/options/type/select.phtml | 37 - .../product/view/options/type/text.phtml | 39 - .../product/view/options/wrapper.phtml | 36 - .../template/catalog/product/view/price.phtml | 30 - .../catalog/product/view/price_clone.phtml | 28 - .../catalog/product/view/tierprices.phtml | 181 - .../product/view/type/configurable.phtml | 41 - .../catalog/product/view/type/grouped.phtml | 80 - .../view/type/options/configurable.phtml | 46 - .../catalog/product/view/type/simple.phtml | 40 - .../catalog/seo/sitemap/container.phtml | 36 - .../iphone/template/catalog/seo/tree.phtml | 43 - .../catalogsearch/advanced/form.phtml | 90 - .../catalogsearch/advanced/result.phtml | 67 - .../template/catalogsearch/form.mini.phtml | 4 +- .../template/catalogsearch/result.phtml | 56 - .../iphone/template/catalogsearch/term.phtml | 44 - .../iphone/template/checkout/cart.phtml | 133 +- .../template/checkout/cart/coupon.phtml | 66 - .../template/checkout/cart/crosssell.phtml | 56 - .../template/checkout/cart/item/default.phtml | 121 +- .../template/checkout/cart/noItems.phtml | 33 - .../checkout/cart/render/default.phtml | 59 - .../checkout/cart/render/simple.phtml | 59 - .../template/checkout/cart/shipping.phtml | 106 - .../template/checkout/cart/sidebar.phtml | 91 - .../template/checkout/cart/totals.phtml | 42 - .../multishipping/address/select.phtml | 60 - .../checkout/multishipping/addresses.phtml | 80 - .../checkout/multishipping/billing.phtml | 116 - .../checkout/multishipping/item/default.phtml | 47 - .../checkout/multishipping/link.phtml | 27 - .../checkout/multishipping/overview.phtml | 203 - .../checkout/multishipping/shipping.phtml | 139 - .../checkout/multishipping/state.phtml | 44 - .../checkout/multishipping/success.phtml | 54 - .../iphone/template/checkout/onepage.phtml | 62 - .../template/checkout/onepage/billing.phtml | 215 - .../template/checkout/onepage/link.phtml | 27 - .../template/checkout/onepage/login.phtml | 119 - .../template/checkout/onepage/payment.phtml | 77 - .../checkout/onepage/payment/methods.phtml | 53 - .../template/checkout/onepage/progress.phtml | 99 - .../template/checkout/onepage/review.phtml | 48 - .../checkout/onepage/review/info.phtml | 49 - .../checkout/onepage/review/item.phtml | 236 - .../checkout/onepage/review/totals.phtml | 43 - .../template/checkout/onepage/shipping.phtml | 176 - .../checkout/onepage/shipping_method.phtml | 54 - .../onepage/shipping_method/additional.phtml | 29 - .../onepage/shipping_method/available.phtml | 63 - .../iphone/template/checkout/success.phtml | 39 - .../default/iphone/template/cms/content.phtml | 27 - .../iphone/template/cms/content_heading.phtml | 27 - .../iphone/template/cms/default/home.phtml | 1 - .../template/cms/default/no-route.phtml | 1 - .../default/iphone/template/cms/meta.phtml | 32 - .../iphone/template/contacts/form.phtml | 70 - .../iphone/template/core/formkey.phtml | 27 - .../iphone/template/core/messages.phtml | 46 - .../template/customer/account/dashboard.phtml | 37 - .../customer/account/dashboard/address.phtml | 49 - .../customer/account/dashboard/hello.phtml | 30 - .../customer/account/dashboard/info.phtml | 58 - .../account/dashboard/newsletter.phtml | 33 - .../customer/account/dashboard/sidebar.phtml | 26 - .../template/customer/account/link/back.phtml | 29 - .../customer/account/navigation.phtml | 44 - .../iphone/template/customer/address.phtml | 92 - .../template/customer/address/book.phtml | 107 - .../template/customer/address/edit.phtml | 165 - .../iphone/template/customer/balance.phtml | 31 - .../iphone/template/customer/dashboard.phtml | 85 - .../template/customer/form/address.phtml | 126 - .../customer/form/changepassword.phtml | 58 - .../iphone/template/customer/form/edit.phtml | 130 - .../customer/form/forgotpassword.phtml | 41 +- .../iphone/template/customer/form/login.phtml | 70 +- .../template/customer/form/mini.login.phtml | 33 - .../customer/form/mini.newsletter.phtml | 42 - .../template/customer/form/newsletter.phtml | 48 - .../template/customer/form/register.phtml | 190 - .../iphone/template/customer/logout.phtml | 36 - .../iphone/template/customer/order/view.phtml | 89 - .../iphone/template/customer/orders.phtml | 63 - .../iphone/template/customer/widget/dob.phtml | 94 - .../template/customer/widget/gender.phtml | 34 - .../template/customer/widget/name.phtml | 120 - .../template/customer/widget/taxvat.phtml | 39 - .../iphone/template/customer/wishlist.phtml | 60 - .../iphone/template/giftmessage/form.phtml | 81 - .../iphone/template/giftmessage/helper.phtml | 80 - .../iphone/template/giftmessage/inline.phtml | 266 - .../iphone/template/googlecheckout/link.phtml | 36 - .../template/newsletter/subscribe.phtml | 44 - .../iphone/template/page/1column.phtml | 5 +- .../iphone/template/page/2columns-left.phtml | 62 - .../iphone/template/page/2columns-right.phtml | 61 - .../iphone/template/page/3columns.phtml | 62 - .../iphone/template/page/dashboard.phtml | 64 - .../template/page/html/breadcrumbs.phtml | 45 - .../iphone/template/page/html/footer.phtml | 2 +- .../iphone/template/page/html/header.phtml | 8 +- .../iphone/template/page/html/notices.phtml | 44 - .../iphone/template/page/html/pager.phtml | 116 - .../iphone/template/page/html/top.links.phtml | 34 - .../iphone/template/page/html/wrapper.phtml | 45 - .../iphone/template/page/js/calendar.phtml | 94 - .../default/iphone/template/page/print.phtml | 53 - .../iphone/template/page/switch/flags.phtml | 33 - .../template/page/switch/languages.phtml | 45 - .../iphone/template/page/switch/stores.phtml | 48 - .../iphone/template/page/template/links.phtml | 41 - .../iphone/template/payment/form/cc.phtml | 85 - .../iphone/template/payment/form/ccsave.phtml | 84 - .../template/payment/form/checkmo.phtml | 43 - .../template/payment/form/purchaseorder.phtml | 36 - .../template/payment/info/checkmo.phtml | 38 - .../template/payment/info/purchaseorder.phtml | 29 - .../default/iphone/template/poll/active.phtml | 66 - .../default/iphone/template/poll/result.phtml | 50 - .../iphone/template/productalert/price.phtml | 29 - .../iphone/template/productalert/stock.phtml | 29 - .../iphone/template/rating/detailed.phtml | 44 - .../iphone/template/rating/empty.phtml | 27 - .../reports/home_product_compared.phtml | 65 - .../reports/home_product_viewed.phtml | 70 - .../template/reports/product_compared.phtml | 44 - .../template/reports/product_viewed.phtml | 44 - .../template/review/customer/list.phtml | 63 - .../template/review/customer/recent.phtml | 53 - .../template/review/customer/view.phtml | 68 - .../default/iphone/template/review/form.phtml | 119 - .../template/review/helper/summary.phtml | 40 - .../review/helper/summary_short.phtml | 39 - .../default/iphone/template/review/list.phtml | 65 - .../template/review/product/detailed.phtml | 183 - .../default/iphone/template/review/view.phtml | 61 - .../default/iphone/template/rss/list.phtml | 61 - .../default/iphone/template/rss/nofeed.phtml | 1 - .../iphone/template/rss/order/details.phtml | 102 - .../template/sales/order/creditmemo.phtml | 111 - .../iphone/template/sales/order/details.phtml | 107 - .../iphone/template/sales/order/history.phtml | 75 +- .../iphone/template/sales/order/info.phtml | 92 - .../iphone/template/sales/order/invoice.phtml | 107 - .../iphone/template/sales/order/items.phtml | 69 - .../sales/order/items/renderer/default.phtml | 317 - .../iphone/template/sales/order/print.phtml | 84 - .../sales/order/print/creditmemo.phtml | 112 - .../template/sales/order/print/invoice.phtml | 95 - .../template/sales/order/print/shipment.phtml | 117 - .../iphone/template/sales/order/recent.phtml | 67 +- .../template/sales/order/shipment.phtml | 128 - .../iphone/template/sales/order/totals.phtml | 52 - .../template/sales/order/trackinginfo.phtml | 68 - .../iphone/template/sales/order/view.phtml | 98 - .../template/sales/reorder/sidebar.phtml | 72 - .../iphone/template/sendfriend/send.phtml | 142 - .../default/iphone/template/tag/cloud.phtml | 42 - .../iphone/template/tag/customer/edit.phtml | 49 - .../iphone/template/tag/customer/recent.phtml | 48 - .../iphone/template/tag/customer/tags.phtml | 47 - .../iphone/template/tag/customer/view.phtml | 75 - .../default/iphone/template/tag/list.phtml | 32 - .../default/iphone/template/tag/mytags.phtml | 75 - .../default/iphone/template/tag/popular.phtml | 41 - .../iphone/template/tag/product/result.phtml | 66 - .../default/iphone/template/tag/result.phtml | 42 - .../default/iphone/template/tag/search.phtml | 42 - .../template/tax/checkout/discount.phtml | 25 - .../template/tax/checkout/grandtotal.phtml | 58 - .../template/tax/checkout/shipping.phtml | 66 - .../template/tax/checkout/subtotal.phtml | 57 - .../iphone/template/tax/checkout/tax.phtml | 74 - .../iphone/template/tax/order/tax.phtml | 81 - .../template/wishlist/email/items.phtml | 53 - .../iphone/template/wishlist/email/rss.phtml | 31 - .../iphone/template/wishlist/shared.phtml | 76 - .../iphone/template/wishlist/sharing.phtml | 89 - .../iphone/template/wishlist/sidebar.phtml | 66 - .../iphone/template/wishlist/view.phtml | 126 +- .../default/modern/layout/catalog.xml | 22 +- .../default/modern/layout/checkout.xml | 26 +- .../default/modern/layout/customer.xml | 7 +- .../default/modern/layout/newsletter.xml | 3 +- .../frontend/default/modern/layout/page.xml | 18 +- .../frontend/default/modern/layout/review.xml | 3 +- .../frontend/default/modern/layout/sales.xml | 7 +- .../frontend/default/modern/layout/tag.xml | 13 +- .../default/modern/layout/wishlist.xml | 5 +- .../template/catalog/product/list.phtml | 14 +- .../template/catalog/product/view.phtml | 9 +- .../modern/template/checkout/cart.phtml | 4 +- .../default/template/install/begin.phtml | 4 +- .../default/template/install/config.phtml | 11 +- .../default/template/install/state.phtml | 3 + .../core.xml => etc/modules/Find_Feed.xml} | 18 +- app/etc/modules/Mage_All.xml | 5 +- .../modules/Mage_Connect.xml} | 20 +- app/locale/en_US/Find_Feed.csv | 44 + app/locale/en_US/Mage_Adminhtml.csv | 23 +- app/locale/en_US/Mage_Api.csv | 9 +- app/locale/en_US/Mage_Bundle.csv | 1 + app/locale/en_US/Mage_Catalog.csv | 20 +- app/locale/en_US/Mage_CatalogInventory.csv | 1 + app/locale/en_US/Mage_CatalogRule.csv | 2 +- app/locale/en_US/Mage_Checkout.csv | 11 + app/locale/en_US/Mage_Cms.csv | 1 + app/locale/en_US/Mage_Connect.csv | 55 + app/locale/en_US/Mage_Core.csv | 32 +- app/locale/en_US/Mage_Customer.csv | 33 +- app/locale/en_US/Mage_Downloadable.csv | 5 +- app/locale/en_US/Mage_GoogleCheckout.csv | 7 +- app/locale/en_US/Mage_Install.csv | 6 +- app/locale/en_US/Mage_Newsletter.csv | 7 +- app/locale/en_US/Mage_Page.csv | 4 + app/locale/en_US/Mage_Payment.csv | 10 +- app/locale/en_US/Mage_Paypal.csv | 8 +- app/locale/en_US/Mage_PaypalUk.csv | 1 + app/locale/en_US/Mage_Review.csv | 2 + app/locale/en_US/Mage_Sales.csv | 20 +- app/locale/en_US/Mage_SalesRule.csv | 3 +- app/locale/en_US/Mage_Shipping.csv | 6 +- app/locale/en_US/Mage_Tag.csv | 2 + app/locale/en_US/Mage_Wishlist.csv | 1 - .../en_US/template/email/account_new.html | 52 +- .../email/account_new_confirmation.html | 40 +- .../template/email/account_new_confirmed.html | 50 +- .../template/email/admin_password_new.html | 58 +- .../email/newsletter_subscr_confirm.html | 56 +- .../en_US/template/email/password_new.html | 53 +- .../template/email/sales/creditmemo_new.html | 62 +- .../email/sales/creditmemo_new_guest.html | 62 +- .../email/sales/creditmemo_update.html | 59 +- .../email/sales/creditmemo_update_guest.html | 58 +- .../template/email/sales/invoice_new.html | 65 +- .../email/sales/invoice_new_guest.html | 64 +- .../template/email/sales/invoice_update.html | 59 +- .../email/sales/invoice_update_guest.html | 54 +- .../en_US/template/email/sales/order_new.html | 65 +- .../template/email/sales/order_new_guest.html | 60 +- .../template/email/sales/order_update.html | 59 +- .../email/sales/order_update_guest.html | 57 +- .../template/email/sales/shipment_new.html | 66 +- .../email/sales/shipment_new_guest.html | 66 +- .../template/email/sales/shipment_update.html | 59 +- .../email/sales/shipment_update_guest.html | 57 +- .../en_US/template/email/wishlist_share.html | 63 +- downloader/pearlib/pear.ini | 2 + .../.channels/.alias/magento-community.txt | 1 + .../php/.channels/.alias/magento-core.txt | 1 + .../pearlib/php/.channels/.alias/pear.txt | 1 + .../pearlib/php/.channels/.alias/pecl.txt | 1 + downloader/pearlib/php/.channels/__uri.reg | 1 + .../connect.magentocommerce.com_community.reg | 1 + .../connect.magentocommerce.com_core.reg | 1 + .../pearlib/php/.channels/pear.php.net.reg | 1 + .../pearlib/php/.channels/pecl.php.net.reg | 1 + downloader/pearlib/php/.depdb | 1 + downloader/pearlib/php/.depdblock | 0 downloader/pearlib/php/.filemap | 1 + downloader/pearlib/php/.lock | 0 downloader/pearlib/temp/channel.xml | 16 + install.php | 4 +- js/mage/adminhtml/browser.js | 3 +- js/mage/adminhtml/form.js | 7 +- js/mage/adminhtml/grid.js | 4 +- js/mage/adminhtml/product.js | 16 + js/mage/adminhtml/sales.js | 59 +- js/mage/adminhtml/tools.js | 266 +- js/mage/adminhtml/wysiwyg/tiny_mce/setup.js | 27 +- js/mage/translate_inline.css | 10 +- js/mage/translate_inline.js | 22 +- js/prototype/validation.js | 103 +- js/prototype/windows/themes/magento.css | 140 +- .../windows/themes/magento/btn_bg.gif | Bin 0 -> 148 bytes .../themes/magento/button-close-focused.png | Bin 351 -> 0 bytes .../windows/themes/magento/content_bg.gif | Bin 0 -> 283 bytes .../windows/themes/magento/top_bg.gif | Bin 152 -> 154 bytes .../windows/themes/magento/window_close.png | Bin 0 -> 872 bytes js/tiny_mce/classes/Editor.js | 83 +- js/tiny_mce/classes/EditorCommands.js | 20 +- js/tiny_mce/classes/ForceBlocks.js | 131 +- js/tiny_mce/classes/Formatter.js | 95 +- .../classes/adapter/jquery/jquery.tinymce.js | 25 +- js/tiny_mce/classes/dom/DOMUtils.js | 15 +- js/tiny_mce/classes/dom/RangeUtils.js | 28 + js/tiny_mce/classes/dom/Selection.js | 124 +- js/tiny_mce/classes/dom/Sizzle.js | 371 +- js/tiny_mce/classes/dom/TridentSelection.js | 191 +- js/tiny_mce/classes/tinymce.js | 9 + js/tiny_mce/classes/ui/ListBox.js | 2 +- js/tiny_mce/jquery.tinymce.js | 2 +- js/tiny_mce/langs/en.js | 33 +- .../plugins/autoresize/editor_plugin.js | 2 +- .../plugins/autoresize/editor_plugin_src.js | 44 +- .../plugins/contextmenu/editor_plugin.js | 2 +- .../plugins/contextmenu/editor_plugin_src.js | 26 +- js/tiny_mce/plugins/fullpage/editor_plugin.js | 2 +- .../plugins/fullpage/editor_plugin_src.js | 4 + .../plugins/fullscreen/editor_plugin.js | 2 +- .../plugins/fullscreen/editor_plugin_src.js | 9 +- .../plugins/legacyoutput/editor_plugin.js | 2 +- .../plugins/legacyoutput/editor_plugin_src.js | 2 +- js/tiny_mce/plugins/paste/editor_plugin.js | 2 +- .../plugins/paste/editor_plugin_src.js | 25 +- .../plugins/spellchecker/editor_plugin.js | 2 +- .../plugins/spellchecker/editor_plugin_src.js | 124 +- js/tiny_mce/plugins/style/props.htm | 7 +- js/tiny_mce/plugins/table/editor_plugin.js | 2 +- .../plugins/table/editor_plugin_src.js | 17 +- js/tiny_mce/plugins/table/js/cell.js | 2 +- js/tiny_mce/plugins/table/js/row.js | 2 +- js/tiny_mce/plugins/table/js/table.js | 4 +- js/tiny_mce/plugins/template/template.htm | 1 - .../plugins/wordcount/editor_plugin.js | 2 +- .../plugins/wordcount/editor_plugin_src.js | 2 +- js/tiny_mce/themes/advanced/charmap.htm | 1 - .../themes/advanced/editor_template.js | 2 +- .../themes/advanced/editor_template_src.js | 49 +- .../themes/advanced/skins/default/ui.css | 2 +- js/tiny_mce/themes/advanced/skins/o2k7/ui.css | 2 +- js/tiny_mce/themes/advanced/source_editor.htm | 1 - js/tiny_mce/tiny_mce.js | 2 +- js/tiny_mce/tiny_mce_jquery.js | 2 +- js/tiny_mce/tiny_mce_jquery_src.js | 670 +- js/tiny_mce/tiny_mce_prototype.js | 2 +- js/tiny_mce/tiny_mce_prototype_src.js | 1039 +- js/tiny_mce/tiny_mce_src.js | 1039 +- js/varien/js.js | 84 +- js/varien/product.js | 37 +- lib/3Dsecure/CentinelClient.php | 2 +- lib/Mage/Archive.php | 222 + lib/Mage/Archive/Abstract.php | 84 + lib/Mage/Archive/Bz.php | 79 + lib/Mage/Archive/Gz.php | 77 + lib/Mage/Archive/Interface.php | 53 + lib/Mage/Archive/Tar.php | 372 + lib/Mage/Autoload/Simple.php | 52 + lib/Mage/Connect/Channel/Generator.php | 63 + .../Mage/Connect/Channel/Parser.php | 51 +- lib/Mage/Connect/Channel/VO.php | 113 + lib/Mage/Connect/Command.php | 390 + lib/Mage/Connect/Command/Channels.php | 189 + lib/Mage/Connect/Command/Channels_Header.php | 105 + lib/Mage/Connect/Command/Config.php | 211 + lib/Mage/Connect/Command/Config_Header.php | 100 + lib/Mage/Connect/Command/Install.php | 448 + lib/Mage/Connect/Command/Install_Header.php | 237 + lib/Mage/Connect/Command/Package.php | 134 + lib/Mage/Connect/Command/Package_Header.php | 67 + lib/Mage/Connect/Command/Registry.php | 175 + lib/Mage/Connect/Command/Registry_Header.php | 68 + lib/Mage/Connect/Command/Remote.php | 226 + lib/Mage/Connect/Command/Remote_Header.php | 88 + lib/Mage/Connect/Config.php | 265 + lib/Mage/Connect/Converter.php | 337 + lib/Mage/Connect/Frontend.php | 251 + lib/Mage/Connect/Frontend/CLI.php | 441 + lib/Mage/Connect/Ftp.php | 494 + lib/Mage/Connect/Loader.php | 51 + lib/Mage/Connect/Loader/Ftp.php | 121 + lib/Mage/Connect/Package.php | 1296 ++ lib/Mage/Connect/Package/Extension.php | 1 + lib/Mage/Connect/Package/Hotfix.php | 137 + lib/Mage/Connect/Package/Maintainer.php | 0 lib/Mage/Connect/Package/Reader.php | 150 + lib/Mage/Connect/Package/Target.php | 126 + lib/Mage/Connect/Package/VO.php | 96 + lib/Mage/Connect/Package/Writer.php | 177 + lib/Mage/Connect/Packager.php | 662 + lib/Mage/Connect/Repository.php | 0 lib/Mage/Connect/Repository/Abstract.php | 0 lib/Mage/Connect/Repository/Channel.php | 0 .../Connect/Repository/Channel/Abstract.php | 0 .../Connect/Repository/Channel/Commercial.php | 0 .../Connect/Repository/Channel/Community.php | 0 lib/Mage/Connect/Repository/Channel/Core.php | 0 lib/Mage/Connect/Repository/Local.php | 0 lib/Mage/Connect/Rest.php | 364 + lib/Mage/Connect/Singleconfig.php | 865 ++ lib/Mage/Connect/Structures/Graph.php | 248 + lib/Mage/Connect/Structures/Node.php | 257 + lib/Mage/Connect/Validator.php | 417 + lib/Mage/DB/Exception.php | 36 + lib/Mage/DB/Mysqli.php | 532 + lib/Mage/Exception.php | 35 + lib/Mage/HTTP/Client.php | 84 + lib/Mage/HTTP/Client/Curl.php | 499 + lib/Mage/HTTP/Client/Socket.php | 537 + lib/Mage/HTTP/IClient.php | 145 + lib/Mage/System/Args.php | 102 + lib/Mage/System/Dirs.php | 82 + lib/Mage/Xml/Generator.php | 90 + lib/Mage/Xml/Parser.php | 91 + lib/Varien/Cache/Backend/Database.php | 32 +- lib/Varien/Cache/Backend/Eaccelerator.php | 2 +- lib/Varien/Data/Collection.php | 43 +- lib/Varien/Data/Collection/Db.php | 21 +- lib/Varien/Data/Form/Element/Abstract.php | 16 + lib/Varien/Data/Form/Element/Editor.php | 3 +- lib/Varien/Data/Form/Element/Multiline.php | 6 +- lib/Varien/Data/Form/Element/Obscure.php | 12 +- lib/Varien/Data/Form/Filter/Date.php | 109 + lib/Varien/Data/Form/Filter/Escapehtml.php | 58 + lib/Varien/Data/Form/Filter/Interface.php | 52 + lib/Varien/Data/Form/Filter/Striptags.php | 58 + lib/Varien/Db/Adapter/Pdo/Mysql.php | 4 +- lib/Varien/Db/Select.php | 14 +- lib/Varien/Db/test.php | 480 - lib/Varien/Directory/Collection.php | 623 +- lib/Varien/Directory/Factory.php | 57 +- lib/Varien/Directory/IFactory.php | 51 +- lib/Varien/File/Object.php | 410 +- lib/Varien/File/Uploader.php | 5 +- lib/Varien/Object.php | 14 +- lib/Varien/Pear.php | 33 + lib/Varien/Pear/Frontend.php | 32 + lib/Varien/Pear/Package.php | 32 + lib/Varien/Pear/Registry.php | 32 + lib/Varien/Profiler.php | 4 +- lib/Zend/Acl.php | 72 +- lib/Zend/Acl/Assert/Interface.php | 6 +- lib/Zend/Acl/Exception.php | 6 +- lib/Zend/Acl/Resource.php | 16 +- lib/Zend/Acl/Resource/Interface.php | 6 +- lib/Zend/Acl/Role.php | 16 +- lib/Zend/Acl/Role/Interface.php | 6 +- lib/Zend/Acl/Role/Registry.php | 12 +- lib/Zend/Acl/Role/Registry/Exception.php | 6 +- lib/Zend/Amf/Adobe/Auth.php | 14 +- lib/Zend/Amf/Adobe/DbInspector.php | 22 +- lib/Zend/Amf/Adobe/Introspector.php | 16 +- lib/Zend/Amf/Auth/Abstract.php | 8 +- lib/Zend/Amf/Constants.php | 6 +- lib/Zend/Amf/Exception.php | 8 +- lib/Zend/Amf/Parse/Amf0/Deserializer.php | 23 +- lib/Zend/Amf/Parse/Amf0/Serializer.php | 70 +- lib/Zend/Amf/Parse/Amf3/Deserializer.php | 30 +- lib/Zend/Amf/Parse/Amf3/Serializer.php | 85 +- lib/Zend/Amf/Parse/Deserializer.php | 6 +- lib/Zend/Amf/Parse/InputStream.php | 6 +- lib/Zend/Amf/Parse/OutputStream.php | 6 +- lib/Zend/Amf/Parse/Resource/MysqlResult.php | 6 +- lib/Zend/Amf/Parse/Resource/MysqliResult.php | 6 +- lib/Zend/Amf/Parse/Resource/Stream.php | 6 +- lib/Zend/Amf/Parse/Serializer.php | 11 +- lib/Zend/Amf/Parse/TypeLoader.php | 16 +- lib/Zend/Amf/Request.php | 20 +- lib/Zend/Amf/Request/Http.php | 8 +- lib/Zend/Amf/Response.php | 33 +- lib/Zend/Amf/Response/Http.php | 6 +- lib/Zend/Amf/Server.php | 42 +- lib/Zend/Amf/Server/Exception.php | 6 +- lib/Zend/Amf/Util/BinaryStream.php | 64 +- lib/Zend/Amf/Value/ByteArray.php | 6 +- lib/Zend/Amf/Value/MessageBody.php | 6 +- lib/Zend/Amf/Value/MessageHeader.php | 6 +- .../Amf/Value/Messaging/AbstractMessage.php | 6 +- .../Value/Messaging/AcknowledgeMessage.php | 6 +- .../Amf/Value/Messaging/ArrayCollection.php | 6 +- lib/Zend/Amf/Value/Messaging/AsyncMessage.php | 6 +- .../Amf/Value/Messaging/CommandMessage.php | 18 +- lib/Zend/Amf/Value/Messaging/ErrorMessage.php | 8 +- .../Amf/Value/Messaging/RemotingMessage.php | 6 +- lib/Zend/Amf/Value/TraitsInfo.php | 6 +- lib/Zend/Application.php | 16 +- lib/Zend/Application/Bootstrap/Bootstrap.php | 87 +- .../Bootstrap/BootstrapAbstract.php | 15 +- .../Application/Bootstrap/Bootstrapper.php | 6 +- lib/Zend/Application/Bootstrap/Exception.php | 6 +- .../Bootstrap/ResourceBootstrapper.php | 6 +- lib/Zend/Application/Exception.php | 6 +- lib/Zend/Application/Module/Autoloader.php | 13 +- lib/Zend/Application/Module/Bootstrap.php | 51 +- .../Application/Resource/Cachemanager.php | 73 + lib/Zend/Application/Resource/Db.php | 11 +- lib/Zend/Application/Resource/Dojo.php | 76 + lib/Zend/Application/Resource/Exception.php | 11 +- .../Application/Resource/Frontcontroller.php | 31 +- lib/Zend/Application/Resource/Layout.php | 12 +- lib/Zend/Application/Resource/Locale.php | 22 +- lib/Zend/Application/Resource/Log.php | 78 + lib/Zend/Application/Resource/Mail.php | 146 + lib/Zend/Application/Resource/Modules.php | 12 +- lib/Zend/Application/Resource/Multidb.php | 171 + lib/Zend/Application/Resource/Navigation.php | 17 +- lib/Zend/Application/Resource/Resource.php | 6 +- .../Application/Resource/ResourceAbstract.php | 8 +- lib/Zend/Application/Resource/Router.php | 17 +- lib/Zend/Application/Resource/Session.php | 12 +- lib/Zend/Application/Resource/Translate.php | 53 +- lib/Zend/Application/Resource/View.php | 19 +- lib/Zend/Auth.php | 6 +- lib/Zend/Auth/Adapter/DbTable.php | 125 +- lib/Zend/Auth/Adapter/Digest.php | 10 +- lib/Zend/Auth/Adapter/Exception.php | 10 +- lib/Zend/Auth/Adapter/Http.php | 6 +- .../Auth/Adapter/Http/Resolver/Exception.php | 6 +- lib/Zend/Auth/Adapter/Http/Resolver/File.php | 6 +- .../Auth/Adapter/Http/Resolver/Interface.php | 6 +- lib/Zend/Auth/Adapter/InfoCard.php | 6 +- lib/Zend/Auth/Adapter/Interface.php | 6 +- lib/Zend/Auth/Adapter/Ldap.php | 27 +- lib/Zend/Auth/Adapter/OpenId.php | 6 +- lib/Zend/Auth/Exception.php | 6 +- lib/Zend/Auth/Result.php | 6 +- lib/Zend/Auth/Storage/Exception.php | 10 +- lib/Zend/Auth/Storage/Interface.php | 11 +- lib/Zend/Auth/Storage/NonPersistent.php | 11 +- lib/Zend/Auth/Storage/Session.php | 10 +- lib/Zend/Barcode.php | 352 + lib/Zend/Barcode/Exception.php | 63 + lib/Zend/Barcode/Object/Code25.php | 143 + lib/Zend/Barcode/Object/Code25interleaved.php | 179 + lib/Zend/Barcode/Object/Code39.php | 177 + lib/Zend/Barcode/Object/Ean13.php | 224 + lib/Zend/Barcode/Object/Ean2.php | 65 + lib/Zend/Barcode/Object/Ean5.php | 147 + lib/Zend/Barcode/Object/Ean8.php | 174 + lib/Zend/Barcode/Object/Error.php | 100 + lib/Zend/Barcode/Object/Exception.php | 35 + lib/Zend/Barcode/Object/Identcode.php | 95 + lib/Zend/Barcode/Object/Itf14.php | 49 + lib/Zend/Barcode/Object/Leitcode.php | 64 + lib/Zend/Barcode/Object/ObjectAbstract.php | 1281 ++ lib/Zend/Barcode/Object/Planet.php | 62 + lib/Zend/Barcode/Object/Postnet.php | 136 + lib/Zend/Barcode/Object/Royalmail.php | 163 + lib/Zend/Barcode/Object/Upca.php | 171 + lib/Zend/Barcode/Object/Upce.php | 227 + lib/Zend/Barcode/Renderer/Exception.php | 35 + lib/Zend/Barcode/Renderer/Image.php | 470 + lib/Zend/Barcode/Renderer/Pdf.php | 242 + .../Barcode/Renderer/RendererAbstract.php | 540 + lib/Zend/Cache.php | 17 +- lib/Zend/Cache/Backend.php | 20 +- lib/Zend/Cache/Backend/Apc.php | 6 +- lib/Zend/Cache/Backend/BlackHole.php | 250 + lib/Zend/Cache/Backend/ExtendedInterface.php | 6 +- lib/Zend/Cache/Backend/File.php | 21 +- lib/Zend/Cache/Backend/Interface.php | 6 +- lib/Zend/Cache/Backend/Memcached.php | 8 +- lib/Zend/Cache/Backend/Sqlite.php | 6 +- lib/Zend/Cache/Backend/Static.php | 566 + lib/Zend/Cache/Backend/Test.php | 170 +- lib/Zend/Cache/Backend/TwoLevels.php | 64 +- lib/Zend/Cache/Backend/Xcache.php | 6 +- lib/Zend/Cache/Backend/ZendPlatform.php | 6 +- lib/Zend/Cache/Backend/ZendServer.php | 6 +- lib/Zend/Cache/Backend/ZendServer/Disk.php | 6 +- lib/Zend/Cache/Backend/ZendServer/ShMem.php | 6 +- lib/Zend/Cache/Core.php | 136 +- lib/Zend/Cache/Exception.php | 6 +- lib/Zend/Cache/Frontend/Capture.php | 87 + lib/Zend/Cache/Frontend/Class.php | 35 +- lib/Zend/Cache/Frontend/File.php | 8 +- lib/Zend/Cache/Frontend/Function.php | 101 +- lib/Zend/Cache/Frontend/Output.php | 6 +- lib/Zend/Cache/Frontend/Page.php | 6 +- lib/Zend/Cache/Manager.php | 298 + lib/Zend/Captcha/Adapter.php | 152 +- lib/Zend/Captcha/Base.php | 352 +- lib/Zend/Captcha/Dumb.php | 104 +- lib/Zend/Captcha/Exception.php | 11 +- lib/Zend/Captcha/Figlet.php | 170 +- lib/Zend/Captcha/Image.php | 1205 +- lib/Zend/Captcha/ReCaptcha.php | 533 +- lib/Zend/Captcha/Word.php | 769 +- lib/Zend/CodeGenerator/Abstract.php | 6 +- lib/Zend/CodeGenerator/Exception.php | 6 +- lib/Zend/CodeGenerator/Php/Abstract.php | 6 +- lib/Zend/CodeGenerator/Php/Body.php | 6 +- lib/Zend/CodeGenerator/Php/Class.php | 10 +- lib/Zend/CodeGenerator/Php/Docblock.php | 6 +- lib/Zend/CodeGenerator/Php/Docblock/Tag.php | 6 +- .../Php/Docblock/Tag/License.php | 6 +- .../CodeGenerator/Php/Docblock/Tag/Param.php | 6 +- .../CodeGenerator/Php/Docblock/Tag/Return.php | 6 +- lib/Zend/CodeGenerator/Php/Exception.php | 6 +- lib/Zend/CodeGenerator/Php/File.php | 6 +- .../CodeGenerator/Php/Member/Abstract.php | 6 +- .../CodeGenerator/Php/Member/Container.php | 6 +- lib/Zend/CodeGenerator/Php/Method.php | 6 +- lib/Zend/CodeGenerator/Php/Parameter.php | 8 +- .../Php/Parameter/DefaultValue.php | 6 +- lib/Zend/CodeGenerator/Php/Property.php | 6 +- .../Php/Property/DefaultValue.php | 6 +- lib/Zend/Config.php | 36 +- lib/Zend/Config/Exception.php | 6 +- lib/Zend/Config/Ini.php | 47 +- lib/Zend/Config/Writer.php | 6 +- lib/Zend/Config/Writer/Array.php | 97 +- lib/Zend/Config/Writer/FileAbstract.php | 134 + lib/Zend/Config/Writer/Ini.php | 147 +- lib/Zend/Config/Writer/Xml.php | 99 +- lib/Zend/Config/Xml.php | 39 +- lib/Zend/Console/Getopt.php | 19 +- lib/Zend/Console/Getopt/Exception.php | 6 +- lib/Zend/Controller/Action.php | 8 +- lib/Zend/Controller/Action/Exception.php | 6 +- .../Controller/Action/Helper/Abstract.php | 12 +- .../Controller/Action/Helper/ActionStack.php | 6 +- .../Controller/Action/Helper/AjaxContext.php | 6 +- .../Action/Helper/AutoComplete/Abstract.php | 6 +- .../Action/Helper/AutoCompleteDojo.php | 6 +- .../Helper/AutoCompleteScriptaculous.php | 6 +- lib/Zend/Controller/Action/Helper/Cache.php | 279 + .../Action/Helper/ContextSwitch.php | 6 +- .../Action/Helper/FlashMessenger.php | 6 +- lib/Zend/Controller/Action/Helper/Json.php | 6 +- .../Controller/Action/Helper/Redirector.php | 6 +- lib/Zend/Controller/Action/Helper/Url.php | 6 +- .../Controller/Action/Helper/ViewRenderer.php | 18 +- lib/Zend/Controller/Action/HelperBroker.php | 8 +- .../Action/HelperBroker/PriorityStack.php | 6 +- lib/Zend/Controller/Action/Interface.php | 6 +- lib/Zend/Controller/Dispatcher/Abstract.php | 6 +- lib/Zend/Controller/Dispatcher/Exception.php | 6 +- lib/Zend/Controller/Dispatcher/Interface.php | 6 +- lib/Zend/Controller/Dispatcher/Standard.php | 17 +- lib/Zend/Controller/Exception.php | 6 +- lib/Zend/Controller/Front.php | 20 +- lib/Zend/Controller/Plugin/Abstract.php | 6 +- lib/Zend/Controller/Plugin/ActionStack.php | 6 +- lib/Zend/Controller/Plugin/Broker.php | 6 +- lib/Zend/Controller/Plugin/ErrorHandler.php | 44 +- lib/Zend/Controller/Plugin/PutHandler.php | 6 +- lib/Zend/Controller/Request/Abstract.php | 6 +- lib/Zend/Controller/Request/Apache404.php | 4 +- lib/Zend/Controller/Request/Exception.php | 6 +- lib/Zend/Controller/Request/Http.php | 34 +- lib/Zend/Controller/Request/HttpTestCase.php | 4 +- lib/Zend/Controller/Request/Simple.php | 6 +- lib/Zend/Controller/Response/Abstract.php | 45 +- lib/Zend/Controller/Response/Cli.php | 6 +- lib/Zend/Controller/Response/Exception.php | 6 +- lib/Zend/Controller/Response/Http.php | 4 +- lib/Zend/Controller/Response/HttpTestCase.php | 4 +- lib/Zend/Controller/Router/Abstract.php | 6 +- lib/Zend/Controller/Router/Exception.php | 6 +- lib/Zend/Controller/Router/Interface.php | 6 +- lib/Zend/Controller/Router/Rewrite.php | 55 +- lib/Zend/Controller/Router/Route.php | 12 +- lib/Zend/Controller/Router/Route/Abstract.php | 6 +- lib/Zend/Controller/Router/Route/Chain.php | 6 +- lib/Zend/Controller/Router/Route/Hostname.php | 6 +- .../Controller/Router/Route/Interface.php | 6 +- lib/Zend/Controller/Router/Route/Module.php | 6 +- lib/Zend/Controller/Router/Route/Regex.php | 15 +- lib/Zend/Controller/Router/Route/Static.php | 6 +- lib/Zend/Crypt.php | 6 +- lib/Zend/Crypt/DiffieHellman.php | 10 +- lib/Zend/Crypt/DiffieHellman/Exception.php | 6 +- lib/Zend/Crypt/Exception.php | 6 +- lib/Zend/Crypt/Hmac.php | 6 +- lib/Zend/Crypt/Hmac/Exception.php | 6 +- lib/Zend/Crypt/Math.php | 8 +- lib/Zend/Crypt/Math/BigInteger.php | 6 +- lib/Zend/Crypt/Math/BigInteger/Bcmath.php | 10 +- lib/Zend/Crypt/Math/BigInteger/Exception.php | 6 +- lib/Zend/Crypt/Math/BigInteger/Gmp.php | 6 +- lib/Zend/Crypt/Math/BigInteger/Interface.php | 6 +- lib/Zend/Crypt/Math/Exception.php | 6 +- lib/Zend/Crypt/Rsa.php | 25 +- lib/Zend/Crypt/Rsa/Key.php | 6 +- lib/Zend/Crypt/Rsa/Key/Private.php | 6 +- lib/Zend/Crypt/Rsa/Key/Public.php | 6 +- lib/Zend/Currency.php | 380 +- lib/Zend/Currency/CurrencyInterface.php | 39 + lib/Zend/Currency/Exception.php | 6 +- lib/Zend/Date.php | 683 +- lib/Zend/Date/Cities.php | 6 +- lib/Zend/Date/DateObject.php | 33 +- lib/Zend/Date/Exception.php | 10 +- lib/Zend/Db.php | 6 +- lib/Zend/Db/Adapter/Abstract.php | 6 +- lib/Zend/Db/Adapter/Db2.php | 6 +- lib/Zend/Db/Adapter/Db2/Exception.php | 12 +- lib/Zend/Db/Adapter/Exception.php | 19 +- lib/Zend/Db/Adapter/Mysqli.php | 6 +- lib/Zend/Db/Adapter/Mysqli/Exception.php | 6 +- lib/Zend/Db/Adapter/Oracle.php | 6 +- lib/Zend/Db/Adapter/Oracle/Exception.php | 6 +- lib/Zend/Db/Adapter/Pdo/Abstract.php | 10 +- lib/Zend/Db/Adapter/Pdo/Ibm.php | 10 +- lib/Zend/Db/Adapter/Pdo/Ibm/Db2.php | 6 +- lib/Zend/Db/Adapter/Pdo/Ibm/Ids.php | 6 +- lib/Zend/Db/Adapter/Pdo/Mssql.php | 6 +- lib/Zend/Db/Adapter/Pdo/Mysql.php | 6 +- lib/Zend/Db/Adapter/Pdo/Oci.php | 6 +- lib/Zend/Db/Adapter/Pdo/Pgsql.php | 43 +- lib/Zend/Db/Adapter/Pdo/Sqlite.php | 6 +- lib/Zend/Db/Adapter/Sqlsrv.php | 1329 +- lib/Zend/Db/Adapter/Sqlsrv/Exception.php | 126 +- lib/Zend/Db/Exception.php | 6 +- lib/Zend/Db/Expr.php | 6 +- lib/Zend/Db/Profiler.php | 23 +- lib/Zend/Db/Profiler/Exception.php | 6 +- lib/Zend/Db/Profiler/Firebug.php | 10 +- lib/Zend/Db/Profiler/Query.php | 6 +- lib/Zend/Db/Select.php | 38 +- lib/Zend/Db/Select/Exception.php | 6 +- lib/Zend/Db/Statement.php | 6 +- lib/Zend/Db/Statement/Db2.php | 6 +- lib/Zend/Db/Statement/Db2/Exception.php | 6 +- lib/Zend/Db/Statement/Exception.php | 27 +- lib/Zend/Db/Statement/Interface.php | 6 +- lib/Zend/Db/Statement/Mysqli.php | 6 +- lib/Zend/Db/Statement/Mysqli/Exception.php | 6 +- lib/Zend/Db/Statement/Oracle.php | 6 +- lib/Zend/Db/Statement/Oracle/Exception.php | 6 +- lib/Zend/Db/Statement/Pdo.php | 8 +- lib/Zend/Db/Statement/Pdo/Ibm.php | 6 +- lib/Zend/Db/Statement/Pdo/Oci.php | 28 +- lib/Zend/Db/Statement/Sqlsrv.php | 821 +- lib/Zend/Db/Statement/Sqlsrv/Exception.php | 120 +- lib/Zend/Db/Table.php | 17 +- lib/Zend/Db/Table/Abstract.php | 12 +- lib/Zend/Db/Table/Definition.php | 6 +- lib/Zend/Db/Table/Exception.php | 6 +- lib/Zend/Db/Table/Row.php | 6 +- lib/Zend/Db/Table/Row/Abstract.php | 22 +- lib/Zend/Db/Table/Row/Exception.php | 6 +- lib/Zend/Db/Table/Rowset.php | 6 +- lib/Zend/Db/Table/Rowset/Abstract.php | 17 +- lib/Zend/Db/Table/Rowset/Exception.php | 6 +- lib/Zend/Db/Table/Select.php | 6 +- lib/Zend/Db/Table/Select/Exception.php | 6 +- lib/Zend/Debug.php | 6 +- lib/Zend/Dojo.php | 14 +- lib/Zend/Dojo/BuildLayer.php | 12 +- lib/Zend/Dojo/Data.php | 6 +- lib/Zend/Dojo/Exception.php | 6 +- lib/Zend/Dojo/Form.php | 6 +- .../Form/Decorator/AccordionContainer.php | 6 +- .../Dojo/Form/Decorator/AccordionPane.php | 6 +- .../Dojo/Form/Decorator/BorderContainer.php | 6 +- lib/Zend/Dojo/Form/Decorator/ContentPane.php | 6 +- .../Dojo/Form/Decorator/DijitContainer.php | 6 +- lib/Zend/Dojo/Form/Decorator/DijitElement.php | 10 +- lib/Zend/Dojo/Form/Decorator/DijitForm.php | 6 +- .../Dojo/Form/Decorator/SplitContainer.php | 6 +- .../Dojo/Form/Decorator/StackContainer.php | 6 +- lib/Zend/Dojo/Form/Decorator/TabContainer.php | 6 +- lib/Zend/Dojo/Form/DisplayGroup.php | 6 +- lib/Zend/Dojo/Form/Element/Button.php | 6 +- lib/Zend/Dojo/Form/Element/CheckBox.php | 7 +- lib/Zend/Dojo/Form/Element/ComboBox.php | 6 +- .../Dojo/Form/Element/CurrencyTextBox.php | 6 +- lib/Zend/Dojo/Form/Element/DateTextBox.php | 6 +- lib/Zend/Dojo/Form/Element/Dijit.php | 6 +- lib/Zend/Dojo/Form/Element/DijitMulti.php | 11 +- lib/Zend/Dojo/Form/Element/Editor.php | 6 +- .../Dojo/Form/Element/FilteringSelect.php | 6 +- .../Dojo/Form/Element/HorizontalSlider.php | 6 +- lib/Zend/Dojo/Form/Element/NumberSpinner.php | 6 +- lib/Zend/Dojo/Form/Element/NumberTextBox.php | 6 +- .../Dojo/Form/Element/PasswordTextBox.php | 6 +- lib/Zend/Dojo/Form/Element/RadioButton.php | 6 +- lib/Zend/Dojo/Form/Element/SimpleTextarea.php | 6 +- lib/Zend/Dojo/Form/Element/Slider.php | 6 +- lib/Zend/Dojo/Form/Element/SubmitButton.php | 6 +- lib/Zend/Dojo/Form/Element/TextBox.php | 6 +- lib/Zend/Dojo/Form/Element/Textarea.php | 6 +- lib/Zend/Dojo/Form/Element/TimeTextBox.php | 6 +- .../Dojo/Form/Element/ValidationTextBox.php | 6 +- lib/Zend/Dojo/Form/Element/VerticalSlider.php | 6 +- lib/Zend/Dojo/Form/SubForm.php | 6 +- lib/Zend/Dojo/View/Exception.php | 6 +- .../Dojo/View/Helper/AccordionContainer.php | 6 +- lib/Zend/Dojo/View/Helper/AccordionPane.php | 6 +- lib/Zend/Dojo/View/Helper/BorderContainer.php | 6 +- lib/Zend/Dojo/View/Helper/Button.php | 6 +- lib/Zend/Dojo/View/Helper/CheckBox.php | 6 +- lib/Zend/Dojo/View/Helper/ComboBox.php | 6 +- lib/Zend/Dojo/View/Helper/ContentPane.php | 6 +- lib/Zend/Dojo/View/Helper/CurrencyTextBox.php | 6 +- lib/Zend/Dojo/View/Helper/CustomDijit.php | 6 +- lib/Zend/Dojo/View/Helper/DateTextBox.php | 6 +- lib/Zend/Dojo/View/Helper/Dijit.php | 8 +- lib/Zend/Dojo/View/Helper/DijitContainer.php | 6 +- lib/Zend/Dojo/View/Helper/Dojo.php | 8 +- lib/Zend/Dojo/View/Helper/Dojo/Container.php | 103 +- lib/Zend/Dojo/View/Helper/Editor.php | 35 +- lib/Zend/Dojo/View/Helper/FilteringSelect.php | 6 +- lib/Zend/Dojo/View/Helper/Form.php | 6 +- .../Dojo/View/Helper/HorizontalSlider.php | 6 +- lib/Zend/Dojo/View/Helper/NumberSpinner.php | 6 +- lib/Zend/Dojo/View/Helper/NumberTextBox.php | 6 +- lib/Zend/Dojo/View/Helper/PasswordTextBox.php | 6 +- lib/Zend/Dojo/View/Helper/RadioButton.php | 6 +- lib/Zend/Dojo/View/Helper/SimpleTextarea.php | 8 +- lib/Zend/Dojo/View/Helper/Slider.php | 6 +- lib/Zend/Dojo/View/Helper/SplitContainer.php | 6 +- lib/Zend/Dojo/View/Helper/StackContainer.php | 6 +- lib/Zend/Dojo/View/Helper/SubmitButton.php | 6 +- lib/Zend/Dojo/View/Helper/TabContainer.php | 6 +- lib/Zend/Dojo/View/Helper/TextBox.php | 6 +- lib/Zend/Dojo/View/Helper/Textarea.php | 6 +- lib/Zend/Dojo/View/Helper/TimeTextBox.php | 6 +- .../Dojo/View/Helper/ValidationTextBox.php | 6 +- lib/Zend/Dojo/View/Helper/VerticalSlider.php | 6 +- lib/Zend/Dom/Exception.php | 6 +- lib/Zend/Dom/Query.php | 38 +- lib/Zend/Dom/Query/Css2Xpath.php | 110 +- lib/Zend/Dom/Query/Result.php | 6 +- lib/Zend/Exception.php | 82 +- lib/Zend/Feed.php | 6 +- lib/Zend/Feed/Abstract.php | 6 +- lib/Zend/Feed/Atom.php | 6 +- lib/Zend/Feed/Builder.php | 6 +- lib/Zend/Feed/Builder/Entry.php | 6 +- lib/Zend/Feed/Builder/Exception.php | 6 +- lib/Zend/Feed/Builder/Header.php | 6 +- lib/Zend/Feed/Builder/Header/Itunes.php | 6 +- lib/Zend/Feed/Builder/Interface.php | 6 +- lib/Zend/Feed/Element.php | 36 +- lib/Zend/Feed/Entry/Abstract.php | 6 +- lib/Zend/Feed/Entry/Atom.php | 6 +- lib/Zend/Feed/Entry/Rss.php | 6 +- lib/Zend/Feed/Exception.php | 6 +- lib/Zend/Feed/Pubsubhubbub.php | 152 + .../Feed/Pubsubhubbub/CallbackAbstract.php | 307 + .../Feed/Pubsubhubbub/CallbackInterface.php | 68 + lib/Zend/Feed/Pubsubhubbub/Exception.php | 33 + lib/Zend/Feed/Pubsubhubbub/HttpResponse.php | 233 + .../Feed/Pubsubhubbub/Model/ModelAbstract.php | 64 + .../Feed/Pubsubhubbub/Model/Subscription.php | 134 + .../Model/SubscriptionInterface.php | 64 + lib/Zend/Feed/Pubsubhubbub/Publisher.php | 417 + lib/Zend/Feed/Pubsubhubbub/Subscriber.php | 856 ++ .../Feed/Pubsubhubbub/Subscriber/Callback.php | 328 + lib/Zend/Feed/Reader.php | 52 +- lib/Zend/Feed/Reader/Collection.php | 33 + lib/Zend/Feed/Reader/Collection/Author.php | 51 + lib/Zend/Feed/Reader/Collection/Category.php | 57 + .../Reader/Collection/CollectionAbstract.php | 41 + lib/Zend/Feed/Reader/Entry/Atom.php | 49 +- lib/Zend/Feed/Reader/Entry/Rss.php | 152 +- lib/Zend/Feed/Reader/EntryAbstract.php | 19 +- lib/Zend/Feed/Reader/EntryInterface.php | 13 +- lib/Zend/Feed/Reader/Extension/Atom/Entry.php | 273 +- lib/Zend/Feed/Reader/Extension/Atom/Feed.php | 188 +- .../Feed/Reader/Extension/Content/Entry.php | 9 +- .../Extension/CreativeCommons/Entry.php | 6 +- .../Reader/Extension/CreativeCommons/Feed.php | 6 +- .../Reader/Extension/DublinCore/Entry.php | 58 +- .../Feed/Reader/Extension/DublinCore/Feed.php | 64 +- .../Feed/Reader/Extension/EntryAbstract.php | 11 +- .../Feed/Reader/Extension/FeedAbstract.php | 31 +- .../Feed/Reader/Extension/Podcast/Entry.php | 6 +- .../Feed/Reader/Extension/Podcast/Feed.php | 6 +- .../Feed/Reader/Extension/Slash/Entry.php | 6 +- .../Reader/Extension/Syndication/Feed.php | 6 +- .../Feed/Reader/Extension/Thread/Entry.php | 6 +- .../Reader/Extension/WellFormedWeb/Entry.php | 6 +- lib/Zend/Feed/Reader/Feed/Atom.php | 87 +- lib/Zend/Feed/Reader/Feed/Atom/Source.php | 102 + lib/Zend/Feed/Reader/Feed/Rss.php | 281 +- lib/Zend/Feed/Reader/FeedAbstract.php | 62 +- lib/Zend/Feed/Reader/FeedInterface.php | 13 +- lib/Zend/Feed/Reader/FeedSet.php | 6 +- lib/Zend/Feed/Rss.php | 6 +- lib/Zend/Feed/Writer.php | 267 + lib/Zend/Feed/Writer/Deleted.php | 202 + lib/Zend/Feed/Writer/Entry.php | 761 + .../Exception/InvalidMethodException.php | 41 + .../Writer/Extension/Atom/Renderer/Feed.php | 123 + .../Extension/Content/Renderer/Entry.php | 92 + .../Extension/DublinCore/Renderer/Entry.php | 96 + .../Extension/DublinCore/Renderer/Feed.php | 96 + .../Feed/Writer/Extension/ITunes/Entry.php | 242 + .../Feed/Writer/Extension/ITunes/Feed.php | 361 + .../Extension/ITunes/Renderer/Entry.php | 216 + .../Writer/Extension/ITunes/Renderer/Feed.php | 320 + .../Writer/Extension/RendererAbstract.php | 179 + .../Writer/Extension/RendererInterface.php | 59 + .../Writer/Extension/Slash/Renderer/Entry.php | 91 + .../Extension/Threading/Renderer/Entry.php | 145 + .../WellFormedWeb/Renderer/Entry.php | 96 + lib/Zend/Feed/Writer/Feed.php | 281 + lib/Zend/Feed/Writer/Feed/FeedAbstract.php | 841 ++ lib/Zend/Feed/Writer/Renderer/Entry/Atom.php | 444 + .../Writer/Renderer/Entry/Atom/Deleted.php | 121 + lib/Zend/Feed/Writer/Renderer/Entry/Rss.php | 346 + lib/Zend/Feed/Writer/Renderer/Feed/Atom.php | 130 + .../Renderer/Feed/Atom/AtomAbstract.php | 427 + .../Feed/Writer/Renderer/Feed/Atom/Source.php | 110 + lib/Zend/Feed/Writer/Renderer/Feed/Rss.php | 505 + .../Feed/Writer/Renderer/RendererAbstract.php | 250 + .../Writer/Renderer/RendererInterface.php | 111 + lib/Zend/Feed/Writer/Source.php | 33 + lib/Zend/File/Transfer.php | 96 +- lib/Zend/File/Transfer/Adapter/Abstract.php | 178 +- lib/Zend/File/Transfer/Adapter/Http.php | 84 +- lib/Zend/File/Transfer/Exception.php | 6 +- lib/Zend/Filter.php | 63 +- lib/Zend/Filter/Alnum.php | 16 +- lib/Zend/Filter/Alpha.php | 16 +- lib/Zend/Filter/BaseName.php | 6 +- lib/Zend/Filter/Boolean.php | 375 + lib/Zend/Filter/Callback.php | 31 +- lib/Zend/Filter/Compress.php | 197 + lib/Zend/Filter/Compress/Bz2.php | 188 + lib/Zend/Filter/Compress/CompressAbstract.php | 89 + .../Filter/Compress/CompressInterface.php | 54 + lib/Zend/Filter/Compress/Gz.php | 228 + lib/Zend/Filter/Compress/Lzf.php | 91 + lib/Zend/Filter/Compress/Rar.php | 252 + lib/Zend/Filter/Compress/Tar.php | 245 + lib/Zend/Filter/Compress/Zip.php | 355 + lib/Zend/Filter/Decompress.php | 49 + lib/Zend/Filter/Decrypt.php | 6 +- lib/Zend/Filter/Digits.php | 6 +- lib/Zend/Filter/Dir.php | 6 +- lib/Zend/Filter/Encrypt.php | 10 +- lib/Zend/Filter/Encrypt/Interface.php | 6 +- lib/Zend/Filter/Encrypt/Mcrypt.php | 42 +- lib/Zend/Filter/Encrypt/Openssl.php | 40 +- lib/Zend/Filter/Exception.php | 6 +- lib/Zend/Filter/File/Decrypt.php | 6 +- lib/Zend/Filter/File/Encrypt.php | 6 +- lib/Zend/Filter/File/LowerCase.php | 6 +- lib/Zend/Filter/File/Rename.php | 7 +- lib/Zend/Filter/File/UpperCase.php | 6 +- lib/Zend/Filter/HtmlEntities.php | 56 +- lib/Zend/Filter/Inflector.php | 109 +- lib/Zend/Filter/Input.php | 104 +- lib/Zend/Filter/Int.php | 6 +- lib/Zend/Filter/Interface.php | 6 +- lib/Zend/Filter/LocalizedToNormalized.php | 10 +- lib/Zend/Filter/NormalizedToLocalized.php | 10 +- lib/Zend/Filter/Null.php | 183 + lib/Zend/Filter/PregReplace.php | 38 +- lib/Zend/Filter/RealPath.php | 6 +- lib/Zend/Filter/StringToLower.php | 61 +- lib/Zend/Filter/StringToUpper.php | 59 +- lib/Zend/Filter/StringTrim.php | 24 +- lib/Zend/Filter/StripNewlines.php | 6 +- lib/Zend/Filter/StripTags.php | 96 +- lib/Zend/Filter/Word/CamelCaseToDash.php | 6 +- lib/Zend/Filter/Word/CamelCaseToSeparator.php | 10 +- .../Filter/Word/CamelCaseToUnderscore.php | 6 +- lib/Zend/Filter/Word/DashToCamelCase.php | 6 +- lib/Zend/Filter/Word/DashToSeparator.php | 6 +- lib/Zend/Filter/Word/DashToUnderscore.php | 6 +- lib/Zend/Filter/Word/Separator/Abstract.php | 6 +- lib/Zend/Filter/Word/SeparatorToCamelCase.php | 6 +- lib/Zend/Filter/Word/SeparatorToDash.php | 6 +- lib/Zend/Filter/Word/SeparatorToSeparator.php | 6 +- .../Filter/Word/UnderscoreToCamelCase.php | 6 +- lib/Zend/Filter/Word/UnderscoreToDash.php | 6 +- .../Filter/Word/UnderscoreToSeparator.php | 6 +- lib/Zend/Form.php | 459 +- lib/Zend/Form/Decorator/Abstract.php | 8 +- lib/Zend/Form/Decorator/Callback.php | 6 +- lib/Zend/Form/Decorator/Captcha.php | 144 +- lib/Zend/Form/Decorator/Captcha/Word.php | 156 +- lib/Zend/Form/Decorator/Description.php | 6 +- lib/Zend/Form/Decorator/DtDdWrapper.php | 17 +- lib/Zend/Form/Decorator/Errors.php | 6 +- lib/Zend/Form/Decorator/Exception.php | 6 +- lib/Zend/Form/Decorator/Fieldset.php | 16 +- lib/Zend/Form/Decorator/File.php | 8 +- lib/Zend/Form/Decorator/Form.php | 6 +- lib/Zend/Form/Decorator/FormElements.php | 6 +- lib/Zend/Form/Decorator/FormErrors.php | 112 +- lib/Zend/Form/Decorator/HtmlTag.php | 42 +- lib/Zend/Form/Decorator/Image.php | 6 +- lib/Zend/Form/Decorator/Interface.php | 6 +- lib/Zend/Form/Decorator/Label.php | 8 +- .../Form/Decorator/Marker/File/Interface.php | 6 +- lib/Zend/Form/Decorator/PrepareElements.php | 6 +- lib/Zend/Form/Decorator/Tooltip.php | 4 +- lib/Zend/Form/Decorator/ViewHelper.php | 6 +- lib/Zend/Form/Decorator/ViewScript.php | 6 +- lib/Zend/Form/DisplayGroup.php | 22 +- lib/Zend/Form/Element.php | 125 +- lib/Zend/Form/Element/Button.php | 6 +- lib/Zend/Form/Element/Captcha.php | 610 +- lib/Zend/Form/Element/Checkbox.php | 6 +- lib/Zend/Form/Element/Exception.php | 6 +- lib/Zend/Form/Element/File.php | 35 +- lib/Zend/Form/Element/Hash.php | 6 +- lib/Zend/Form/Element/Hidden.php | 6 +- lib/Zend/Form/Element/Image.php | 9 +- lib/Zend/Form/Element/Multi.php | 11 +- lib/Zend/Form/Element/MultiCheckbox.php | 6 +- lib/Zend/Form/Element/Multiselect.php | 6 +- lib/Zend/Form/Element/Password.php | 6 +- lib/Zend/Form/Element/Radio.php | 15 +- lib/Zend/Form/Element/Reset.php | 6 +- lib/Zend/Form/Element/Select.php | 6 +- lib/Zend/Form/Element/Submit.php | 13 +- lib/Zend/Form/Element/Text.php | 6 +- lib/Zend/Form/Element/Textarea.php | 6 +- lib/Zend/Form/Element/Xhtml.php | 6 +- lib/Zend/Form/Exception.php | 6 +- lib/Zend/Form/SubForm.php | 11 +- lib/Zend/Gdata.php | 6 +- lib/Zend/Gdata/App.php | 37 +- lib/Zend/Gdata/App/AuthException.php | 6 +- lib/Zend/Gdata/App/BadMethodCallException.php | 6 +- lib/Zend/Gdata/App/Base.php | 6 +- lib/Zend/Gdata/App/BaseMediaSource.php | 6 +- .../Gdata/App/CaptchaRequiredException.php | 6 +- lib/Zend/Gdata/App/Entry.php | 6 +- lib/Zend/Gdata/App/Exception.php | 6 +- lib/Zend/Gdata/App/Extension.php | 6 +- lib/Zend/Gdata/App/Extension/Author.php | 6 +- lib/Zend/Gdata/App/Extension/Category.php | 6 +- lib/Zend/Gdata/App/Extension/Content.php | 6 +- lib/Zend/Gdata/App/Extension/Contributor.php | 6 +- lib/Zend/Gdata/App/Extension/Control.php | 6 +- lib/Zend/Gdata/App/Extension/Draft.php | 6 +- lib/Zend/Gdata/App/Extension/Edited.php | 6 +- lib/Zend/Gdata/App/Extension/Element.php | 6 +- lib/Zend/Gdata/App/Extension/Email.php | 6 +- lib/Zend/Gdata/App/Extension/Generator.php | 6 +- lib/Zend/Gdata/App/Extension/Icon.php | 6 +- lib/Zend/Gdata/App/Extension/Id.php | 6 +- lib/Zend/Gdata/App/Extension/Link.php | 6 +- lib/Zend/Gdata/App/Extension/Logo.php | 6 +- lib/Zend/Gdata/App/Extension/Name.php | 6 +- lib/Zend/Gdata/App/Extension/Person.php | 6 +- lib/Zend/Gdata/App/Extension/Published.php | 6 +- lib/Zend/Gdata/App/Extension/Rights.php | 6 +- lib/Zend/Gdata/App/Extension/Source.php | 6 +- lib/Zend/Gdata/App/Extension/Subtitle.php | 6 +- lib/Zend/Gdata/App/Extension/Summary.php | 6 +- lib/Zend/Gdata/App/Extension/Text.php | 6 +- lib/Zend/Gdata/App/Extension/Title.php | 6 +- lib/Zend/Gdata/App/Extension/Updated.php | 6 +- lib/Zend/Gdata/App/Extension/Uri.php | 6 +- lib/Zend/Gdata/App/Feed.php | 6 +- lib/Zend/Gdata/App/FeedEntryParent.php | 12 +- lib/Zend/Gdata/App/FeedSourceParent.php | 6 +- lib/Zend/Gdata/App/HttpException.php | 6 +- lib/Zend/Gdata/App/IOException.php | 6 +- .../Gdata/App/InvalidArgumentException.php | 6 +- .../App/LoggingHttpClientAdapterSocket.php | 6 +- lib/Zend/Gdata/App/MediaEntry.php | 6 +- lib/Zend/Gdata/App/MediaFileSource.php | 6 +- lib/Zend/Gdata/App/MediaSource.php | 6 +- lib/Zend/Gdata/App/Util.php | 6 +- lib/Zend/Gdata/App/VersionException.php | 6 +- lib/Zend/Gdata/AuthSub.php | 6 +- lib/Zend/Gdata/Books.php | 6 +- lib/Zend/Gdata/Books/CollectionEntry.php | 6 +- lib/Zend/Gdata/Books/CollectionFeed.php | 6 +- .../Gdata/Books/Extension/AnnotationLink.php | 6 +- .../Gdata/Books/Extension/BooksCategory.php | 6 +- lib/Zend/Gdata/Books/Extension/BooksLink.php | 6 +- .../Gdata/Books/Extension/Embeddability.php | 6 +- lib/Zend/Gdata/Books/Extension/InfoLink.php | 4 +- .../Gdata/Books/Extension/PreviewLink.php | 6 +- lib/Zend/Gdata/Books/Extension/Review.php | 6 +- .../Gdata/Books/Extension/ThumbnailLink.php | 6 +- .../Gdata/Books/Extension/Viewability.php | 6 +- lib/Zend/Gdata/Books/VolumeEntry.php | 6 +- lib/Zend/Gdata/Books/VolumeFeed.php | 6 +- lib/Zend/Gdata/Books/VolumeQuery.php | 6 +- lib/Zend/Gdata/Calendar.php | 6 +- lib/Zend/Gdata/Calendar/EventEntry.php | 6 +- lib/Zend/Gdata/Calendar/EventFeed.php | 6 +- lib/Zend/Gdata/Calendar/EventQuery.php | 72 +- .../Gdata/Calendar/Extension/AccessLevel.php | 6 +- lib/Zend/Gdata/Calendar/Extension/Color.php | 6 +- lib/Zend/Gdata/Calendar/Extension/Hidden.php | 6 +- lib/Zend/Gdata/Calendar/Extension/Link.php | 6 +- .../Gdata/Calendar/Extension/QuickAdd.php | 6 +- .../Gdata/Calendar/Extension/Selected.php | 6 +- .../Extension/SendEventNotifications.php | 6 +- .../Gdata/Calendar/Extension/Timezone.php | 6 +- .../Gdata/Calendar/Extension/WebContent.php | 6 +- lib/Zend/Gdata/Calendar/ListEntry.php | 6 +- lib/Zend/Gdata/Calendar/ListFeed.php | 6 +- lib/Zend/Gdata/ClientLogin.php | 6 +- lib/Zend/Gdata/Docs.php | 57 +- lib/Zend/Gdata/Docs/DocumentListEntry.php | 6 +- lib/Zend/Gdata/Docs/DocumentListFeed.php | 6 +- lib/Zend/Gdata/Docs/Query.php | 6 +- lib/Zend/Gdata/DublinCore.php | 6 +- .../Gdata/DublinCore/Extension/Creator.php | 6 +- lib/Zend/Gdata/DublinCore/Extension/Date.php | 6 +- .../DublinCore/Extension/Description.php | 6 +- .../Gdata/DublinCore/Extension/Format.php | 6 +- .../Gdata/DublinCore/Extension/Identifier.php | 6 +- .../Gdata/DublinCore/Extension/Language.php | 6 +- .../Gdata/DublinCore/Extension/Publisher.php | 6 +- .../Gdata/DublinCore/Extension/Rights.php | 6 +- .../Gdata/DublinCore/Extension/Subject.php | 6 +- lib/Zend/Gdata/DublinCore/Extension/Title.php | 6 +- lib/Zend/Gdata/Entry.php | 6 +- lib/Zend/Gdata/Exif.php | 6 +- lib/Zend/Gdata/Exif/Entry.php | 6 +- lib/Zend/Gdata/Exif/Extension/Distance.php | 6 +- lib/Zend/Gdata/Exif/Extension/Exposure.php | 6 +- lib/Zend/Gdata/Exif/Extension/FStop.php | 6 +- lib/Zend/Gdata/Exif/Extension/Flash.php | 6 +- lib/Zend/Gdata/Exif/Extension/FocalLength.php | 6 +- .../Gdata/Exif/Extension/ImageUniqueId.php | 6 +- lib/Zend/Gdata/Exif/Extension/Iso.php | 6 +- lib/Zend/Gdata/Exif/Extension/Make.php | 6 +- lib/Zend/Gdata/Exif/Extension/Model.php | 6 +- lib/Zend/Gdata/Exif/Extension/Tags.php | 6 +- lib/Zend/Gdata/Exif/Extension/Time.php | 6 +- lib/Zend/Gdata/Exif/Feed.php | 6 +- lib/Zend/Gdata/Extension.php | 6 +- lib/Zend/Gdata/Extension/AttendeeStatus.php | 6 +- lib/Zend/Gdata/Extension/AttendeeType.php | 6 +- lib/Zend/Gdata/Extension/Comments.php | 6 +- lib/Zend/Gdata/Extension/EntryLink.php | 6 +- lib/Zend/Gdata/Extension/EventStatus.php | 6 +- lib/Zend/Gdata/Extension/ExtendedProperty.php | 6 +- lib/Zend/Gdata/Extension/FeedLink.php | 6 +- .../Extension/OpenSearchItemsPerPage.php | 6 +- .../Gdata/Extension/OpenSearchStartIndex.php | 6 +- .../Extension/OpenSearchTotalResults.php | 6 +- lib/Zend/Gdata/Extension/OriginalEvent.php | 6 +- lib/Zend/Gdata/Extension/Rating.php | 6 +- lib/Zend/Gdata/Extension/Recurrence.php | 6 +- .../Gdata/Extension/RecurrenceException.php | 6 +- lib/Zend/Gdata/Extension/Reminder.php | 26 +- lib/Zend/Gdata/Extension/Transparency.php | 6 +- lib/Zend/Gdata/Extension/Visibility.php | 6 +- lib/Zend/Gdata/Extension/When.php | 6 +- lib/Zend/Gdata/Extension/Where.php | 6 +- lib/Zend/Gdata/Extension/Who.php | 6 +- lib/Zend/Gdata/Feed.php | 6 +- lib/Zend/Gdata/Gapps.php | 592 +- lib/Zend/Gdata/Gapps/EmailListEntry.php | 6 +- lib/Zend/Gdata/Gapps/EmailListFeed.php | 6 +- lib/Zend/Gdata/Gapps/EmailListQuery.php | 6 +- .../Gdata/Gapps/EmailListRecipientEntry.php | 6 +- .../Gdata/Gapps/EmailListRecipientFeed.php | 6 +- .../Gdata/Gapps/EmailListRecipientQuery.php | 6 +- lib/Zend/Gdata/Gapps/Error.php | 6 +- lib/Zend/Gdata/Gapps/Extension/EmailList.php | 6 +- lib/Zend/Gdata/Gapps/Extension/Login.php | 6 +- lib/Zend/Gdata/Gapps/Extension/Name.php | 6 +- lib/Zend/Gdata/Gapps/Extension/Nickname.php | 6 +- lib/Zend/Gdata/Gapps/Extension/Property.php | 180 + lib/Zend/Gdata/Gapps/Extension/Quota.php | 6 +- lib/Zend/Gdata/Gapps/GroupEntry.php | 158 + lib/Zend/Gdata/Gapps/GroupFeed.php | 53 + lib/Zend/Gdata/Gapps/GroupQuery.php | 226 + lib/Zend/Gdata/Gapps/MemberEntry.php | 159 + lib/Zend/Gdata/Gapps/MemberFeed.php | 53 + lib/Zend/Gdata/Gapps/MemberQuery.php | 194 + lib/Zend/Gdata/Gapps/NicknameEntry.php | 6 +- lib/Zend/Gdata/Gapps/NicknameFeed.php | 6 +- lib/Zend/Gdata/Gapps/NicknameQuery.php | 6 +- lib/Zend/Gdata/Gapps/OwnerEntry.php | 158 + lib/Zend/Gdata/Gapps/OwnerFeed.php | 53 + lib/Zend/Gdata/Gapps/OwnerQuery.php | 147 + lib/Zend/Gdata/Gapps/Query.php | 6 +- lib/Zend/Gdata/Gapps/ServiceException.php | 6 +- lib/Zend/Gdata/Gapps/UserEntry.php | 6 +- lib/Zend/Gdata/Gapps/UserFeed.php | 6 +- lib/Zend/Gdata/Gapps/UserQuery.php | 6 +- lib/Zend/Gdata/Gbase.php | 6 +- lib/Zend/Gdata/Gbase/Entry.php | 6 +- .../Gdata/Gbase/Extension/BaseAttribute.php | 6 +- lib/Zend/Gdata/Gbase/Feed.php | 6 +- lib/Zend/Gdata/Gbase/ItemEntry.php | 6 +- lib/Zend/Gdata/Gbase/ItemFeed.php | 6 +- lib/Zend/Gdata/Gbase/ItemQuery.php | 6 +- lib/Zend/Gdata/Gbase/Query.php | 6 +- lib/Zend/Gdata/Gbase/SnippetEntry.php | 6 +- lib/Zend/Gdata/Gbase/SnippetFeed.php | 6 +- lib/Zend/Gdata/Gbase/SnippetQuery.php | 6 +- lib/Zend/Gdata/Geo.php | 6 +- lib/Zend/Gdata/Geo/Entry.php | 6 +- lib/Zend/Gdata/Geo/Extension/GeoRssWhere.php | 6 +- lib/Zend/Gdata/Geo/Extension/GmlPoint.php | 6 +- lib/Zend/Gdata/Geo/Extension/GmlPos.php | 6 +- lib/Zend/Gdata/Geo/Feed.php | 6 +- lib/Zend/Gdata/Health.php | 548 +- lib/Zend/Gdata/Health/Extension/Ccr.php | 249 +- lib/Zend/Gdata/Health/ProfileEntry.php | 270 +- lib/Zend/Gdata/Health/ProfileFeed.php | 134 +- lib/Zend/Gdata/Health/ProfileListEntry.php | 200 +- lib/Zend/Gdata/Health/ProfileListFeed.php | 106 +- lib/Zend/Gdata/Health/Query.php | 570 +- lib/Zend/Gdata/HttpAdapterStreamingProxy.php | 6 +- lib/Zend/Gdata/HttpAdapterStreamingSocket.php | 6 +- lib/Zend/Gdata/HttpClient.php | 17 +- lib/Zend/Gdata/Kind/EventEntry.php | 6 +- lib/Zend/Gdata/Media.php | 6 +- lib/Zend/Gdata/Media/Entry.php | 6 +- .../Gdata/Media/Extension/MediaCategory.php | 6 +- .../Gdata/Media/Extension/MediaContent.php | 6 +- .../Gdata/Media/Extension/MediaCopyright.php | 6 +- .../Gdata/Media/Extension/MediaCredit.php | 6 +- .../Media/Extension/MediaDescription.php | 6 +- lib/Zend/Gdata/Media/Extension/MediaGroup.php | 6 +- lib/Zend/Gdata/Media/Extension/MediaHash.php | 6 +- .../Gdata/Media/Extension/MediaKeywords.php | 6 +- .../Gdata/Media/Extension/MediaPlayer.php | 6 +- .../Gdata/Media/Extension/MediaRating.php | 6 +- .../Media/Extension/MediaRestriction.php | 6 +- lib/Zend/Gdata/Media/Extension/MediaText.php | 6 +- .../Gdata/Media/Extension/MediaThumbnail.php | 6 +- lib/Zend/Gdata/Media/Extension/MediaTitle.php | 6 +- lib/Zend/Gdata/Media/Feed.php | 6 +- lib/Zend/Gdata/MediaMimeStream.php | 6 +- lib/Zend/Gdata/MimeBodyString.php | 8 +- lib/Zend/Gdata/MimeFile.php | 8 +- lib/Zend/Gdata/Photos.php | 6 +- lib/Zend/Gdata/Photos/AlbumEntry.php | 6 +- lib/Zend/Gdata/Photos/AlbumFeed.php | 6 +- lib/Zend/Gdata/Photos/AlbumQuery.php | 6 +- lib/Zend/Gdata/Photos/CommentEntry.php | 6 +- lib/Zend/Gdata/Photos/Extension/Access.php | 6 +- lib/Zend/Gdata/Photos/Extension/AlbumId.php | 6 +- lib/Zend/Gdata/Photos/Extension/BytesUsed.php | 6 +- lib/Zend/Gdata/Photos/Extension/Checksum.php | 6 +- lib/Zend/Gdata/Photos/Extension/Client.php | 6 +- .../Gdata/Photos/Extension/CommentCount.php | 6 +- .../Photos/Extension/CommentingEnabled.php | 6 +- lib/Zend/Gdata/Photos/Extension/Height.php | 6 +- lib/Zend/Gdata/Photos/Extension/Id.php | 6 +- lib/Zend/Gdata/Photos/Extension/Location.php | 6 +- .../Photos/Extension/MaxPhotosPerAlbum.php | 6 +- lib/Zend/Gdata/Photos/Extension/Name.php | 6 +- lib/Zend/Gdata/Photos/Extension/Nickname.php | 6 +- lib/Zend/Gdata/Photos/Extension/NumPhotos.php | 6 +- .../Photos/Extension/NumPhotosRemaining.php | 6 +- lib/Zend/Gdata/Photos/Extension/PhotoId.php | 6 +- lib/Zend/Gdata/Photos/Extension/Position.php | 6 +- .../Gdata/Photos/Extension/QuotaCurrent.php | 6 +- .../Gdata/Photos/Extension/QuotaLimit.php | 6 +- lib/Zend/Gdata/Photos/Extension/Rotation.php | 6 +- lib/Zend/Gdata/Photos/Extension/Size.php | 6 +- lib/Zend/Gdata/Photos/Extension/Thumbnail.php | 6 +- lib/Zend/Gdata/Photos/Extension/Timestamp.php | 6 +- lib/Zend/Gdata/Photos/Extension/User.php | 6 +- lib/Zend/Gdata/Photos/Extension/Version.php | 6 +- lib/Zend/Gdata/Photos/Extension/Weight.php | 6 +- lib/Zend/Gdata/Photos/Extension/Width.php | 6 +- lib/Zend/Gdata/Photos/PhotoEntry.php | 6 +- lib/Zend/Gdata/Photos/PhotoFeed.php | 6 +- lib/Zend/Gdata/Photos/PhotoQuery.php | 6 +- lib/Zend/Gdata/Photos/TagEntry.php | 6 +- lib/Zend/Gdata/Photos/UserEntry.php | 6 +- lib/Zend/Gdata/Photos/UserFeed.php | 6 +- lib/Zend/Gdata/Photos/UserQuery.php | 6 +- lib/Zend/Gdata/Query.php | 6 +- lib/Zend/Gdata/Spreadsheets.php | 6 +- lib/Zend/Gdata/Spreadsheets/CellEntry.php | 6 +- lib/Zend/Gdata/Spreadsheets/CellFeed.php | 6 +- lib/Zend/Gdata/Spreadsheets/CellQuery.php | 6 +- lib/Zend/Gdata/Spreadsheets/DocumentQuery.php | 6 +- .../Gdata/Spreadsheets/Extension/Cell.php | 6 +- .../Gdata/Spreadsheets/Extension/ColCount.php | 6 +- .../Gdata/Spreadsheets/Extension/Custom.php | 6 +- .../Gdata/Spreadsheets/Extension/RowCount.php | 6 +- lib/Zend/Gdata/Spreadsheets/ListEntry.php | 6 +- lib/Zend/Gdata/Spreadsheets/ListFeed.php | 6 +- lib/Zend/Gdata/Spreadsheets/ListQuery.php | 6 +- .../Gdata/Spreadsheets/SpreadsheetEntry.php | 6 +- .../Gdata/Spreadsheets/SpreadsheetFeed.php | 6 +- .../Gdata/Spreadsheets/WorksheetEntry.php | 6 +- lib/Zend/Gdata/Spreadsheets/WorksheetFeed.php | 6 +- lib/Zend/Gdata/YouTube.php | 6 +- lib/Zend/Gdata/YouTube/ActivityEntry.php | 6 +- lib/Zend/Gdata/YouTube/ActivityFeed.php | 6 +- lib/Zend/Gdata/YouTube/CommentEntry.php | 6 +- lib/Zend/Gdata/YouTube/CommentFeed.php | 6 +- lib/Zend/Gdata/YouTube/ContactEntry.php | 6 +- lib/Zend/Gdata/YouTube/ContactFeed.php | 6 +- lib/Zend/Gdata/YouTube/Extension/AboutMe.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Age.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Books.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Company.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Control.php | 6 +- .../Gdata/YouTube/Extension/CountHint.php | 6 +- .../Gdata/YouTube/Extension/Description.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Duration.php | 6 +- .../Gdata/YouTube/Extension/FirstName.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Gender.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Hobbies.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Hometown.php | 6 +- lib/Zend/Gdata/YouTube/Extension/LastName.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Link.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Location.php | 6 +- .../Gdata/YouTube/Extension/MediaContent.php | 6 +- .../Gdata/YouTube/Extension/MediaCredit.php | 6 +- .../Gdata/YouTube/Extension/MediaGroup.php | 6 +- .../Gdata/YouTube/Extension/MediaRating.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Movies.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Music.php | 6 +- lib/Zend/Gdata/YouTube/Extension/NoEmbed.php | 6 +- .../Gdata/YouTube/Extension/Occupation.php | 6 +- .../Gdata/YouTube/Extension/PlaylistId.php | 6 +- .../Gdata/YouTube/Extension/PlaylistTitle.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Position.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Private.php | 6 +- .../Gdata/YouTube/Extension/QueryString.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Racy.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Recorded.php | 6 +- .../Gdata/YouTube/Extension/Relationship.php | 6 +- .../Gdata/YouTube/Extension/ReleaseDate.php | 6 +- lib/Zend/Gdata/YouTube/Extension/School.php | 6 +- lib/Zend/Gdata/YouTube/Extension/State.php | 6 +- .../Gdata/YouTube/Extension/Statistics.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Status.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Token.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Uploaded.php | 6 +- lib/Zend/Gdata/YouTube/Extension/Username.php | 6 +- lib/Zend/Gdata/YouTube/Extension/VideoId.php | 6 +- lib/Zend/Gdata/YouTube/InboxEntry.php | 6 +- lib/Zend/Gdata/YouTube/InboxFeed.php | 6 +- lib/Zend/Gdata/YouTube/MediaEntry.php | 6 +- lib/Zend/Gdata/YouTube/PlaylistListEntry.php | 6 +- lib/Zend/Gdata/YouTube/PlaylistListFeed.php | 6 +- lib/Zend/Gdata/YouTube/PlaylistVideoEntry.php | 6 +- lib/Zend/Gdata/YouTube/PlaylistVideoFeed.php | 6 +- lib/Zend/Gdata/YouTube/SubscriptionEntry.php | 6 +- lib/Zend/Gdata/YouTube/SubscriptionFeed.php | 6 +- lib/Zend/Gdata/YouTube/UserProfileEntry.php | 6 +- lib/Zend/Gdata/YouTube/VideoEntry.php | 6 +- lib/Zend/Gdata/YouTube/VideoFeed.php | 6 +- lib/Zend/Gdata/YouTube/VideoQuery.php | 8 +- lib/Zend/Http/Client.php | 187 +- lib/Zend/Http/Client/Adapter/Curl.php | 159 +- lib/Zend/Http/Client/Adapter/Exception.php | 6 +- lib/Zend/Http/Client/Adapter/Interface.php | 6 +- lib/Zend/Http/Client/Adapter/Proxy.php | 31 +- lib/Zend/Http/Client/Adapter/Socket.php | 160 +- lib/Zend/Http/Client/Adapter/Stream.php | 46 + lib/Zend/Http/Client/Adapter/Test.php | 35 +- lib/Zend/Http/Client/Exception.php | 6 +- lib/Zend/Http/Cookie.php | 42 +- lib/Zend/Http/CookieJar.php | 6 +- lib/Zend/Http/Exception.php | 6 +- lib/Zend/Http/Response.php | 37 +- lib/Zend/Http/Response/Stream.php | 235 + lib/Zend/InfoCard.php | 6 +- lib/Zend/InfoCard/Adapter/Default.php | 10 +- lib/Zend/InfoCard/Adapter/Exception.php | 11 +- lib/Zend/InfoCard/Adapter/Interface.php | 11 +- lib/Zend/InfoCard/Cipher.php | 6 +- lib/Zend/InfoCard/Cipher/Exception.php | 6 +- .../InfoCard/Cipher/Pki/Adapter/Abstract.php | 6 +- lib/Zend/InfoCard/Cipher/Pki/Adapter/Rsa.php | 6 +- lib/Zend/InfoCard/Cipher/Pki/Interface.php | 6 +- .../InfoCard/Cipher/Pki/Rsa/Interface.php | 6 +- .../Cipher/Symmetric/Adapter/Abstract.php | 6 +- .../Cipher/Symmetric/Adapter/Aes128cbc.php | 6 +- .../Cipher/Symmetric/Adapter/Aes256cbc.php | 6 +- .../Cipher/Symmetric/Aes128cbc/Interface.php | 6 +- .../Cipher/Symmetric/Aes256cbc/Interface.php | 6 +- .../InfoCard/Cipher/Symmetric/Interface.php | 6 +- lib/Zend/InfoCard/Claims.php | 6 +- lib/Zend/InfoCard/Exception.php | 6 +- lib/Zend/InfoCard/Xml/Assertion.php | 6 +- lib/Zend/InfoCard/Xml/Assertion/Interface.php | 6 +- lib/Zend/InfoCard/Xml/Assertion/Saml.php | 6 +- lib/Zend/InfoCard/Xml/Element.php | 6 +- lib/Zend/InfoCard/Xml/Element/Interface.php | 6 +- lib/Zend/InfoCard/Xml/EncryptedData.php | 6 +- .../InfoCard/Xml/EncryptedData/Abstract.php | 6 +- .../InfoCard/Xml/EncryptedData/XmlEnc.php | 6 +- lib/Zend/InfoCard/Xml/EncryptedKey.php | 6 +- lib/Zend/InfoCard/Xml/Exception.php | 6 +- lib/Zend/InfoCard/Xml/KeyInfo.php | 6 +- lib/Zend/InfoCard/Xml/KeyInfo/Abstract.php | 6 +- lib/Zend/InfoCard/Xml/KeyInfo/Default.php | 6 +- lib/Zend/InfoCard/Xml/KeyInfo/Interface.php | 6 +- lib/Zend/InfoCard/Xml/KeyInfo/XmlDSig.php | 6 +- lib/Zend/InfoCard/Xml/Security.php | 6 +- lib/Zend/InfoCard/Xml/Security/Exception.php | 6 +- lib/Zend/InfoCard/Xml/Security/Transform.php | 6 +- .../Security/Transform/EnvelopedSignature.php | 6 +- .../Xml/Security/Transform/Exception.php | 6 +- .../Xml/Security/Transform/Interface.php | 6 +- .../Xml/Security/Transform/XmlExcC14N.php | 6 +- .../InfoCard/Xml/SecurityTokenReference.php | 6 +- lib/Zend/Json.php | 75 +- lib/Zend/Json/Decoder.php | 16 +- lib/Zend/Json/Encoder.php | 12 +- lib/Zend/Json/Exception.php | 6 +- lib/Zend/Json/Expr.php | 6 +- lib/Zend/Json/Server.php | 40 +- lib/Zend/Json/Server/Cache.php | 6 +- lib/Zend/Json/Server/Error.php | 6 +- lib/Zend/Json/Server/Exception.php | 6 +- lib/Zend/Json/Server/Request.php | 6 +- lib/Zend/Json/Server/Request/Http.php | 6 +- lib/Zend/Json/Server/Response.php | 12 +- lib/Zend/Json/Server/Response/Http.php | 6 +- lib/Zend/Json/Server/Smd.php | 6 +- lib/Zend/Json/Server/Smd/Service.php | 6 +- lib/Zend/Layout.php | 6 +- .../Controller/Action/Helper/Layout.php | 6 +- lib/Zend/Layout/Controller/Plugin/Layout.php | 6 +- lib/Zend/Layout/Exception.php | 6 +- lib/Zend/Ldap.php | 227 +- lib/Zend/Ldap/Attribute.php | 15 +- lib/Zend/Ldap/Collection.php | 86 +- lib/Zend/Ldap/Collection/Iterator/Default.php | 191 +- lib/Zend/Ldap/Converter.php | 6 +- lib/Zend/Ldap/Dn.php | 6 +- lib/Zend/Ldap/Exception.php | 6 +- lib/Zend/Ldap/Filter.php | 6 +- lib/Zend/Ldap/Filter/Abstract.php | 6 +- lib/Zend/Ldap/Filter/And.php | 6 +- lib/Zend/Ldap/Filter/Exception.php | 6 +- lib/Zend/Ldap/Filter/Logical.php | 6 +- lib/Zend/Ldap/Filter/Mask.php | 6 +- lib/Zend/Ldap/Filter/Not.php | 6 +- lib/Zend/Ldap/Filter/Or.php | 6 +- lib/Zend/Ldap/Filter/String.php | 6 +- lib/Zend/Ldap/Ldif/Encoder.php | 8 +- lib/Zend/Ldap/Node.php | 6 +- lib/Zend/Ldap/Node/Abstract.php | 6 +- lib/Zend/Ldap/Node/ChildrenIterator.php | 6 +- lib/Zend/Ldap/Node/Collection.php | 6 +- lib/Zend/Ldap/Node/RootDse.php | 6 +- .../Ldap/Node/RootDse/ActiveDirectory.php | 6 +- lib/Zend/Ldap/Node/RootDse/OpenLdap.php | 6 +- lib/Zend/Ldap/Node/RootDse/eDirectory.php | 6 +- lib/Zend/Ldap/Node/Schema.php | 6 +- lib/Zend/Ldap/Node/Schema/ActiveDirectory.php | 6 +- .../Schema/AttributeType/ActiveDirectory.php | 6 +- .../Node/Schema/AttributeType/Interface.php | 6 +- .../Node/Schema/AttributeType/OpenLdap.php | 6 +- lib/Zend/Ldap/Node/Schema/Item.php | 6 +- .../Schema/ObjectClass/ActiveDirectory.php | 6 +- .../Node/Schema/ObjectClass/Interface.php | 6 +- .../Ldap/Node/Schema/ObjectClass/OpenLdap.php | 6 +- lib/Zend/Ldap/Node/Schema/OpenLdap.php | 6 +- lib/Zend/Loader.php | 79 +- lib/Zend/Loader/Autoloader.php | 16 +- lib/Zend/Loader/Autoloader/Interface.php | 6 +- lib/Zend/Loader/Autoloader/Resource.php | 6 +- lib/Zend/Loader/Exception.php | 6 +- lib/Zend/Loader/PluginLoader.php | 16 +- lib/Zend/Loader/PluginLoader/Exception.php | 6 +- lib/Zend/Loader/PluginLoader/Interface.php | 6 +- lib/Zend/Locale.php | 157 +- lib/Zend/Locale/Data.php | 6 +- lib/Zend/Locale/Data/Translation.php | 309 +- lib/Zend/Locale/Data/aa.xml | 441 +- lib/Zend/Locale/Data/aa_DJ.xml | 51 +- lib/Zend/Locale/Data/aa_ER.xml | 21 +- lib/Zend/Locale/Data/aa_ER_SAAHO.xml | 77 +- lib/Zend/Locale/Data/aa_ET.xml | 19 +- lib/Zend/Locale/Data/af.xml | 1643 ++- lib/Zend/Locale/Data/af_NA.xml | 149 +- lib/Zend/Locale/Data/af_ZA.xml | 19 +- lib/Zend/Locale/Data/ak.xml | 379 +- lib/Zend/Locale/Data/ak_GH.xml | 19 +- lib/Zend/Locale/Data/am.xml | 2818 ++-- lib/Zend/Locale/Data/am_ET.xml | 19 +- lib/Zend/Locale/Data/ar.xml | 6236 ++++---- lib/Zend/Locale/Data/ar_AE.xml | 29 +- lib/Zend/Locale/Data/ar_BH.xml | 29 +- lib/Zend/Locale/Data/ar_DZ.xml | 87 +- lib/Zend/Locale/Data/ar_EG.xml | 19 +- lib/Zend/Locale/Data/ar_IQ.xml | 29 +- lib/Zend/Locale/Data/ar_JO.xml | 131 +- lib/Zend/Locale/Data/ar_KW.xml | 29 +- lib/Zend/Locale/Data/ar_LB.xml | 133 +- lib/Zend/Locale/Data/ar_LY.xml | 29 +- lib/Zend/Locale/Data/ar_MA.xml | 93 +- lib/Zend/Locale/Data/ar_OM.xml | 29 +- lib/Zend/Locale/Data/ar_QA.xml | 99 +- lib/Zend/Locale/Data/ar_SA.xml | 99 +- lib/Zend/Locale/Data/ar_SD.xml | 29 +- lib/Zend/Locale/Data/ar_SY.xml | 163 +- lib/Zend/Locale/Data/ar_TN.xml | 149 +- lib/Zend/Locale/Data/ar_YE.xml | 99 +- lib/Zend/Locale/Data/as.xml | 548 +- lib/Zend/Locale/Data/as_IN.xml | 19 +- lib/Zend/Locale/Data/az.xml | 5431 ++++--- lib/Zend/Locale/Data/az_AZ.xml | 21 +- lib/Zend/Locale/Data/az_Cyrl.xml | 169 +- lib/Zend/Locale/Data/az_Cyrl_AZ.xml | 21 +- lib/Zend/Locale/Data/az_Latn.xml | 19 +- lib/Zend/Locale/Data/az_Latn_AZ.xml | 21 +- lib/Zend/Locale/Data/be.xml | 2181 ++- lib/Zend/Locale/Data/be_BY.xml | 19 +- lib/Zend/Locale/Data/bg.xml | 7926 +++++----- lib/Zend/Locale/Data/bg_BG.xml | 19 +- lib/Zend/Locale/Data/bn.xml | 5668 ++++---- lib/Zend/Locale/Data/bn_BD.xml | 19 +- lib/Zend/Locale/Data/bn_IN.xml | 71 +- lib/Zend/Locale/Data/bo.xml | 881 +- lib/Zend/Locale/Data/bo_CN.xml | 19 +- lib/Zend/Locale/Data/bo_IN.xml | 19 +- lib/Zend/Locale/Data/bs.xml | 659 +- lib/Zend/Locale/Data/bs_BA.xml | 19 +- lib/Zend/Locale/Data/byn.xml | 1003 +- lib/Zend/Locale/Data/byn_ER.xml | 19 +- lib/Zend/Locale/Data/ca.xml | 6505 +++++---- lib/Zend/Locale/Data/ca_ES.xml | 19 +- lib/Zend/Locale/Data/cch.xml | 377 +- lib/Zend/Locale/Data/cch_NG.xml | 19 +- lib/Zend/Locale/Data/characters.xml | 971 +- lib/Zend/Locale/Data/cop.xml | 395 +- lib/Zend/Locale/Data/cs.xml | 4879 ++++--- lib/Zend/Locale/Data/cs_CZ.xml | 19 +- lib/Zend/Locale/Data/cy.xml | 1565 +- lib/Zend/Locale/Data/cy_GB.xml | 19 +- lib/Zend/Locale/Data/da.xml | 6259 ++++---- lib/Zend/Locale/Data/da_DK.xml | 19 +- lib/Zend/Locale/Data/de.xml | 5898 ++++---- lib/Zend/Locale/Data/de_AT.xml | 139 +- lib/Zend/Locale/Data/de_BE.xml | 229 +- lib/Zend/Locale/Data/de_CH.xml | 125 +- lib/Zend/Locale/Data/de_DE.xml | 19 +- lib/Zend/Locale/Data/de_LI.xml | 45 +- lib/Zend/Locale/Data/de_LU.xml | 37 +- lib/Zend/Locale/Data/dv.xml | 451 +- lib/Zend/Locale/Data/dv_MV.xml | 19 +- lib/Zend/Locale/Data/dz.xml | 813 +- lib/Zend/Locale/Data/dz_BT.xml | 19 +- lib/Zend/Locale/Data/ee.xml | 385 +- lib/Zend/Locale/Data/ee_GH.xml | 19 +- lib/Zend/Locale/Data/ee_TG.xml | 19 +- lib/Zend/Locale/Data/el.xml | 8248 ++++++----- lib/Zend/Locale/Data/el_CY.xml | 39 +- lib/Zend/Locale/Data/el_GR.xml | 19 +- lib/Zend/Locale/Data/el_POLYTON.xml | 1083 +- lib/Zend/Locale/Data/en.xml | 8202 +++++------ lib/Zend/Locale/Data/en_AS.xml | 19 +- lib/Zend/Locale/Data/en_AU.xml | 320 +- lib/Zend/Locale/Data/en_BE.xml | 316 +- lib/Zend/Locale/Data/en_BW.xml | 260 +- lib/Zend/Locale/Data/en_BZ.xml | 320 +- lib/Zend/Locale/Data/en_CA.xml | 253 +- lib/Zend/Locale/Data/en_Dsrt.xml | 2048 +-- lib/Zend/Locale/Data/en_Dsrt_US.xml | 21 +- lib/Zend/Locale/Data/en_GB.xml | 338 +- lib/Zend/Locale/Data/en_GU.xml | 19 +- lib/Zend/Locale/Data/en_HK.xml | 109 +- lib/Zend/Locale/Data/en_IE.xml | 306 +- lib/Zend/Locale/Data/en_IN.xml | 290 +- lib/Zend/Locale/Data/en_JM.xml | 53 +- lib/Zend/Locale/Data/en_MH.xml | 19 +- lib/Zend/Locale/Data/en_MP.xml | 19 +- lib/Zend/Locale/Data/en_MT.xml | 308 +- lib/Zend/Locale/Data/en_NA.xml | 53 +- lib/Zend/Locale/Data/en_NZ.xml | 314 +- lib/Zend/Locale/Data/en_PH.xml | 33 +- lib/Zend/Locale/Data/en_PK.xml | 306 +- lib/Zend/Locale/Data/en_SG.xml | 95 +- lib/Zend/Locale/Data/en_Shaw.xml | 371 +- lib/Zend/Locale/Data/en_TT.xml | 53 +- lib/Zend/Locale/Data/en_UM.xml | 19 +- lib/Zend/Locale/Data/en_US.xml | 19 +- lib/Zend/Locale/Data/en_US_POSIX.xml | 89 +- lib/Zend/Locale/Data/en_VI.xml | 19 +- lib/Zend/Locale/Data/en_ZA.xml | 304 +- lib/Zend/Locale/Data/en_ZW.xml | 289 +- lib/Zend/Locale/Data/eo.xml | 1264 +- lib/Zend/Locale/Data/es.xml | 7429 +++++----- lib/Zend/Locale/Data/es_AR.xml | 258 +- lib/Zend/Locale/Data/es_BO.xml | 19 +- lib/Zend/Locale/Data/es_CL.xml | 319 +- lib/Zend/Locale/Data/es_CO.xml | 255 +- lib/Zend/Locale/Data/es_CR.xml | 19 +- lib/Zend/Locale/Data/es_DO.xml | 31 +- lib/Zend/Locale/Data/es_EC.xml | 245 +- lib/Zend/Locale/Data/es_ES.xml | 19 +- lib/Zend/Locale/Data/es_GT.xml | 228 +- lib/Zend/Locale/Data/es_HN.xml | 228 +- lib/Zend/Locale/Data/es_MX.xml | 41 +- lib/Zend/Locale/Data/es_NI.xml | 31 +- lib/Zend/Locale/Data/es_PA.xml | 219 +- lib/Zend/Locale/Data/es_PE.xml | 222 +- lib/Zend/Locale/Data/es_PR.xml | 229 +- lib/Zend/Locale/Data/es_PY.xml | 37 +- lib/Zend/Locale/Data/es_SV.xml | 31 +- lib/Zend/Locale/Data/es_US.xml | 294 +- lib/Zend/Locale/Data/es_UY.xml | 47 +- lib/Zend/Locale/Data/es_VE.xml | 37 +- lib/Zend/Locale/Data/et.xml | 3967 +++--- lib/Zend/Locale/Data/et_EE.xml | 19 +- lib/Zend/Locale/Data/eu.xml | 2008 ++- lib/Zend/Locale/Data/eu_ES.xml | 19 +- lib/Zend/Locale/Data/fa.xml | 6618 ++++----- lib/Zend/Locale/Data/fa_AF.xml | 609 +- lib/Zend/Locale/Data/fa_IR.xml | 19 +- lib/Zend/Locale/Data/fi.xml | 7658 +++++----- lib/Zend/Locale/Data/fi_FI.xml | 19 +- lib/Zend/Locale/Data/fil.xml | 2019 ++- lib/Zend/Locale/Data/fil_PH.xml | 19 +- lib/Zend/Locale/Data/fo.xml | 1589 ++- lib/Zend/Locale/Data/fo_FO.xml | 19 +- lib/Zend/Locale/Data/fr.xml | 10918 +++++++------- lib/Zend/Locale/Data/fr_BE.xml | 206 +- lib/Zend/Locale/Data/fr_CA.xml | 303 +- lib/Zend/Locale/Data/fr_CH.xml | 248 +- lib/Zend/Locale/Data/fr_FR.xml | 19 +- lib/Zend/Locale/Data/fr_LU.xml | 45 +- lib/Zend/Locale/Data/fr_MC.xml | 19 +- lib/Zend/Locale/Data/fr_SN.xml | 19 +- lib/Zend/Locale/Data/fur.xml | 2446 ++-- lib/Zend/Locale/Data/fur_IT.xml | 19 +- lib/Zend/Locale/Data/ga.xml | 3005 ++-- lib/Zend/Locale/Data/ga_IE.xml | 19 +- lib/Zend/Locale/Data/gaa.xml | 387 +- lib/Zend/Locale/Data/gaa_GH.xml | 19 +- lib/Zend/Locale/Data/gez.xml | 1007 +- lib/Zend/Locale/Data/gez_ER.xml | 19 +- lib/Zend/Locale/Data/gez_ET.xml | 19 +- lib/Zend/Locale/Data/gl.xml | 2722 ++-- lib/Zend/Locale/Data/gl_ES.xml | 19 +- lib/Zend/Locale/Data/gsw.xml | 5838 ++++---- lib/Zend/Locale/Data/gsw_CH.xml | 19 +- lib/Zend/Locale/Data/gu.xml | 2320 +-- lib/Zend/Locale/Data/gu_IN.xml | 19 +- lib/Zend/Locale/Data/gv.xml | 400 +- lib/Zend/Locale/Data/gv_GB.xml | 19 +- lib/Zend/Locale/Data/ha.xml | 741 +- lib/Zend/Locale/Data/ha_Arab.xml | 189 +- lib/Zend/Locale/Data/ha_Arab_NG.xml | 21 +- lib/Zend/Locale/Data/ha_Arab_SD.xml | 21 +- lib/Zend/Locale/Data/ha_GH.xml | 21 +- lib/Zend/Locale/Data/ha_Latn.xml | 19 +- lib/Zend/Locale/Data/ha_Latn_GH.xml | 21 +- lib/Zend/Locale/Data/ha_Latn_NE.xml | 21 +- lib/Zend/Locale/Data/ha_Latn_NG.xml | 21 +- lib/Zend/Locale/Data/ha_NE.xml | 21 +- lib/Zend/Locale/Data/ha_NG.xml | 21 +- lib/Zend/Locale/Data/ha_SD.xml | 21 +- lib/Zend/Locale/Data/haw.xml | 436 +- lib/Zend/Locale/Data/haw_US.xml | 19 +- lib/Zend/Locale/Data/he.xml | 5515 ++++--- lib/Zend/Locale/Data/he_IL.xml | 19 +- lib/Zend/Locale/Data/hi.xml | 6687 +++++---- lib/Zend/Locale/Data/hi_IN.xml | 19 +- lib/Zend/Locale/Data/hr.xml | 7408 +++++----- lib/Zend/Locale/Data/hr_HR.xml | 19 +- lib/Zend/Locale/Data/hu.xml | 7491 +++++----- lib/Zend/Locale/Data/hu_HU.xml | 19 +- lib/Zend/Locale/Data/hy.xml | 1186 +- lib/Zend/Locale/Data/hy_AM.xml | 19 +- lib/Zend/Locale/Data/hy_AM_REVISED.xml | 79 +- lib/Zend/Locale/Data/ia.xml | 1105 +- lib/Zend/Locale/Data/id.xml | 2668 ++-- lib/Zend/Locale/Data/id_ID.xml | 19 +- lib/Zend/Locale/Data/ig.xml | 382 +- lib/Zend/Locale/Data/ig_NG.xml | 19 +- lib/Zend/Locale/Data/ii.xml | 508 +- lib/Zend/Locale/Data/ii_CN.xml | 19 +- lib/Zend/Locale/Data/in.xml | 19 +- lib/Zend/Locale/Data/is.xml | 4359 +++--- lib/Zend/Locale/Data/is_IS.xml | 19 +- lib/Zend/Locale/Data/it.xml | 6010 ++++---- lib/Zend/Locale/Data/it_CH.xml | 232 +- lib/Zend/Locale/Data/it_IT.xml | 19 +- lib/Zend/Locale/Data/iu.xml | 363 +- lib/Zend/Locale/Data/iw.xml | 19 +- lib/Zend/Locale/Data/ja.xml | 7597 +++++----- lib/Zend/Locale/Data/ja_JP.xml | 19 +- lib/Zend/Locale/Data/ka.xml | 4314 +++--- lib/Zend/Locale/Data/ka_GE.xml | 19 +- lib/Zend/Locale/Data/kaj.xml | 377 +- lib/Zend/Locale/Data/kaj_NG.xml | 19 +- lib/Zend/Locale/Data/kam.xml | 375 +- lib/Zend/Locale/Data/kam_KE.xml | 19 +- lib/Zend/Locale/Data/kcg.xml | 377 +- lib/Zend/Locale/Data/kcg_NG.xml | 19 +- lib/Zend/Locale/Data/kfo.xml | 377 +- lib/Zend/Locale/Data/kfo_CI.xml | 19 +- lib/Zend/Locale/Data/kk.xml | 776 +- lib/Zend/Locale/Data/kk_Cyrl.xml | 19 +- lib/Zend/Locale/Data/kk_Cyrl_KZ.xml | 21 +- lib/Zend/Locale/Data/kk_KZ.xml | 21 +- lib/Zend/Locale/Data/kl.xml | 414 +- lib/Zend/Locale/Data/kl_GL.xml | 19 +- lib/Zend/Locale/Data/km.xml | 1335 +- lib/Zend/Locale/Data/km_KH.xml | 19 +- lib/Zend/Locale/Data/kn.xml | 2314 +-- lib/Zend/Locale/Data/kn_IN.xml | 19 +- lib/Zend/Locale/Data/ko.xml | 7701 +++++----- lib/Zend/Locale/Data/ko_KR.xml | 19 +- lib/Zend/Locale/Data/kok.xml | 726 +- lib/Zend/Locale/Data/kok_IN.xml | 19 +- lib/Zend/Locale/Data/kpe.xml | 367 +- lib/Zend/Locale/Data/kpe_GN.xml | 33 +- lib/Zend/Locale/Data/kpe_LR.xml | 19 +- lib/Zend/Locale/Data/ku.xml | 317 +- lib/Zend/Locale/Data/ku_Arab.xml | 19 +- lib/Zend/Locale/Data/ku_Arab_IQ.xml | 21 +- lib/Zend/Locale/Data/ku_Arab_IR.xml | 21 +- lib/Zend/Locale/Data/ku_Arab_SY.xml | 21 +- lib/Zend/Locale/Data/ku_IQ.xml | 21 +- lib/Zend/Locale/Data/ku_IR.xml | 21 +- lib/Zend/Locale/Data/ku_Latn.xml | 378 +- lib/Zend/Locale/Data/ku_Latn_TR.xml | 21 +- lib/Zend/Locale/Data/ku_SY.xml | 21 +- lib/Zend/Locale/Data/ku_TR.xml | 21 +- lib/Zend/Locale/Data/kw.xml | 400 +- lib/Zend/Locale/Data/kw_GB.xml | 19 +- lib/Zend/Locale/Data/ky.xml | 551 +- lib/Zend/Locale/Data/ky_KG.xml | 19 +- lib/Zend/Locale/Data/likelySubtags.xml | 925 +- lib/Zend/Locale/Data/ln.xml | 971 +- lib/Zend/Locale/Data/ln_CD.xml | 19 +- lib/Zend/Locale/Data/ln_CG.xml | 19 +- lib/Zend/Locale/Data/lo.xml | 1247 +- lib/Zend/Locale/Data/lo_LA.xml | 19 +- lib/Zend/Locale/Data/lt.xml | 6655 +++++---- lib/Zend/Locale/Data/lt_LT.xml | 19 +- lib/Zend/Locale/Data/lv.xml | 5973 ++++---- lib/Zend/Locale/Data/lv_LV.xml | 19 +- lib/Zend/Locale/Data/metazoneInfo.xml | 2807 ++-- lib/Zend/Locale/Data/mk.xml | 4643 +++--- lib/Zend/Locale/Data/mk_MK.xml | 19 +- lib/Zend/Locale/Data/ml.xml | 8847 ++++++------ lib/Zend/Locale/Data/ml_IN.xml | 19 +- lib/Zend/Locale/Data/mn.xml | 631 +- lib/Zend/Locale/Data/mn_CN.xml | 21 +- lib/Zend/Locale/Data/mn_Cyrl.xml | 19 +- lib/Zend/Locale/Data/mn_Cyrl_MN.xml | 21 +- lib/Zend/Locale/Data/mn_MN.xml | 21 +- lib/Zend/Locale/Data/mn_Mong.xml | 33 +- lib/Zend/Locale/Data/mn_Mong_CN.xml | 21 +- lib/Zend/Locale/Data/mo.xml | 19 +- lib/Zend/Locale/Data/mr.xml | 2382 ++-- lib/Zend/Locale/Data/mr_IN.xml | 19 +- lib/Zend/Locale/Data/ms.xml | 1114 +- lib/Zend/Locale/Data/ms_BN.xml | 268 +- lib/Zend/Locale/Data/ms_MY.xml | 19 +- lib/Zend/Locale/Data/mt.xml | 2281 ++- lib/Zend/Locale/Data/mt_MT.xml | 19 +- lib/Zend/Locale/Data/my.xml | 3161 ++-- lib/Zend/Locale/Data/my_MM.xml | 19 +- lib/Zend/Locale/Data/nb.xml | 6163 ++++---- lib/Zend/Locale/Data/nb_NO.xml | 19 +- lib/Zend/Locale/Data/nds.xml | 2297 ++- lib/Zend/Locale/Data/nds_DE.xml | 19 +- lib/Zend/Locale/Data/ne.xml | 2766 ++-- lib/Zend/Locale/Data/ne_IN.xml | 19 +- lib/Zend/Locale/Data/ne_NP.xml | 19 +- lib/Zend/Locale/Data/nl.xml | 7595 +++++----- lib/Zend/Locale/Data/nl_BE.xml | 160 +- lib/Zend/Locale/Data/nl_NL.xml | 19 +- lib/Zend/Locale/Data/nn.xml | 5649 ++++---- lib/Zend/Locale/Data/nn_NO.xml | 19 +- lib/Zend/Locale/Data/no.xml | 19 +- lib/Zend/Locale/Data/nr.xml | 453 +- lib/Zend/Locale/Data/nr_ZA.xml | 19 +- lib/Zend/Locale/Data/nso.xml | 457 +- lib/Zend/Locale/Data/nso_ZA.xml | 19 +- lib/Zend/Locale/Data/numberingSystems.xml | 83 +- lib/Zend/Locale/Data/ny.xml | 377 +- lib/Zend/Locale/Data/ny_MW.xml | 19 +- lib/Zend/Locale/Data/oc.xml | 559 +- lib/Zend/Locale/Data/oc_FR.xml | 19 +- lib/Zend/Locale/Data/om.xml | 655 +- lib/Zend/Locale/Data/om_ET.xml | 19 +- lib/Zend/Locale/Data/om_KE.xml | 19 +- lib/Zend/Locale/Data/or.xml | 2283 ++- lib/Zend/Locale/Data/or_IN.xml | 19 +- lib/Zend/Locale/Data/pa.xml | 619 +- lib/Zend/Locale/Data/pa_Arab.xml | 267 +- lib/Zend/Locale/Data/pa_Arab_PK.xml | 21 +- lib/Zend/Locale/Data/pa_Guru.xml | 19 +- lib/Zend/Locale/Data/pa_Guru_IN.xml | 21 +- lib/Zend/Locale/Data/pa_IN.xml | 21 +- lib/Zend/Locale/Data/pa_PK.xml | 21 +- lib/Zend/Locale/Data/pl.xml | 6191 ++++---- lib/Zend/Locale/Data/pl_PL.xml | 19 +- lib/Zend/Locale/Data/postalCodeData.xml | 331 +- lib/Zend/Locale/Data/ps.xml | 833 +- lib/Zend/Locale/Data/ps_AF.xml | 19 +- lib/Zend/Locale/Data/pt.xml | 8675 ++++++----- lib/Zend/Locale/Data/pt_BR.xml | 19 +- lib/Zend/Locale/Data/pt_PT.xml | 3732 +++-- lib/Zend/Locale/Data/ro.xml | 4957 ++++--- lib/Zend/Locale/Data/ro_MD.xml | 19 +- lib/Zend/Locale/Data/ro_RO.xml | 19 +- lib/Zend/Locale/Data/root.xml | 6386 +++++---- lib/Zend/Locale/Data/ru.xml | 7899 +++++----- lib/Zend/Locale/Data/ru_RU.xml | 19 +- lib/Zend/Locale/Data/ru_UA.xml | 232 +- lib/Zend/Locale/Data/rw.xml | 611 +- lib/Zend/Locale/Data/rw_RW.xml | 19 +- lib/Zend/Locale/Data/sa.xml | 300 +- lib/Zend/Locale/Data/sa_IN.xml | 19 +- lib/Zend/Locale/Data/se.xml | 1481 +- lib/Zend/Locale/Data/se_FI.xml | 493 +- lib/Zend/Locale/Data/se_NO.xml | 19 +- lib/Zend/Locale/Data/sh.xml | 19 +- lib/Zend/Locale/Data/sh_BA.xml | 21 +- lib/Zend/Locale/Data/sh_CS.xml | 21 +- lib/Zend/Locale/Data/sh_YU.xml | 21 +- lib/Zend/Locale/Data/si.xml | 483 +- lib/Zend/Locale/Data/si_LK.xml | 19 +- lib/Zend/Locale/Data/sid.xml | 496 +- lib/Zend/Locale/Data/sid_ET.xml | 19 +- lib/Zend/Locale/Data/sk.xml | 3800 +++-- lib/Zend/Locale/Data/sk_SK.xml | 19 +- lib/Zend/Locale/Data/sl.xml | 5087 ++++--- lib/Zend/Locale/Data/sl_SI.xml | 19 +- lib/Zend/Locale/Data/so.xml | 1119 +- lib/Zend/Locale/Data/so_DJ.xml | 19 +- lib/Zend/Locale/Data/so_ET.xml | 19 +- lib/Zend/Locale/Data/so_KE.xml | 19 +- lib/Zend/Locale/Data/so_SO.xml | 19 +- lib/Zend/Locale/Data/sq.xml | 1312 +- lib/Zend/Locale/Data/sq_AL.xml | 19 +- lib/Zend/Locale/Data/sr.xml | 11898 ++++++++-------- lib/Zend/Locale/Data/sr_BA.xml | 21 +- lib/Zend/Locale/Data/sr_CS.xml | 21 +- lib/Zend/Locale/Data/sr_Cyrl.xml | 19 +- lib/Zend/Locale/Data/sr_Cyrl_BA.xml | 206 +- lib/Zend/Locale/Data/sr_Cyrl_CS.xml | 23 +- lib/Zend/Locale/Data/sr_Cyrl_ME.xml | 21 +- lib/Zend/Locale/Data/sr_Cyrl_RS.xml | 21 +- lib/Zend/Locale/Data/sr_Cyrl_YU.xml | 23 +- lib/Zend/Locale/Data/sr_Latn.xml | 10868 +++++++------- lib/Zend/Locale/Data/sr_Latn_BA.xml | 21 +- lib/Zend/Locale/Data/sr_Latn_CS.xml | 23 +- lib/Zend/Locale/Data/sr_Latn_ME.xml | 116 +- lib/Zend/Locale/Data/sr_Latn_RS.xml | 21 +- lib/Zend/Locale/Data/sr_Latn_YU.xml | 23 +- lib/Zend/Locale/Data/sr_ME.xml | 21 +- lib/Zend/Locale/Data/sr_RS.xml | 21 +- lib/Zend/Locale/Data/sr_YU.xml | 21 +- lib/Zend/Locale/Data/ss.xml | 461 +- lib/Zend/Locale/Data/ss_SZ.xml | 21 +- lib/Zend/Locale/Data/ss_ZA.xml | 19 +- lib/Zend/Locale/Data/st.xml | 641 +- lib/Zend/Locale/Data/st_LS.xml | 33 +- lib/Zend/Locale/Data/st_ZA.xml | 19 +- lib/Zend/Locale/Data/supplementalData.xml | 10723 +++++++------- lib/Zend/Locale/Data/sv.xml | 9445 ++++++------ lib/Zend/Locale/Data/sv_FI.xml | 95 +- lib/Zend/Locale/Data/sv_SE.xml | 19 +- lib/Zend/Locale/Data/sw.xml | 799 +- lib/Zend/Locale/Data/sw_KE.xml | 37 +- lib/Zend/Locale/Data/sw_TZ.xml | 19 +- lib/Zend/Locale/Data/syr.xml | 257 +- lib/Zend/Locale/Data/syr_SY.xml | 19 +- lib/Zend/Locale/Data/ta.xml | 2380 ++-- lib/Zend/Locale/Data/ta_IN.xml | 19 +- lib/Zend/Locale/Data/te.xml | 2308 +-- lib/Zend/Locale/Data/te_IN.xml | 19 +- lib/Zend/Locale/Data/telephoneCodeData.xml | 1493 +- lib/Zend/Locale/Data/tg.xml | 441 +- lib/Zend/Locale/Data/tg_Cyrl.xml | 19 +- lib/Zend/Locale/Data/tg_Cyrl_TJ.xml | 21 +- lib/Zend/Locale/Data/tg_TJ.xml | 21 +- lib/Zend/Locale/Data/th.xml | 8875 ++++++------ lib/Zend/Locale/Data/th_TH.xml | 19 +- lib/Zend/Locale/Data/ti.xml | 651 +- lib/Zend/Locale/Data/ti_ER.xml | 247 +- lib/Zend/Locale/Data/ti_ET.xml | 19 +- lib/Zend/Locale/Data/tig.xml | 1001 +- lib/Zend/Locale/Data/tig_ER.xml | 19 +- lib/Zend/Locale/Data/tl.xml | 19 +- lib/Zend/Locale/Data/tn.xml | 615 +- lib/Zend/Locale/Data/tn_ZA.xml | 19 +- lib/Zend/Locale/Data/to.xml | 1222 +- lib/Zend/Locale/Data/to_TO.xml | 19 +- lib/Zend/Locale/Data/tr.xml | 7545 +++++----- lib/Zend/Locale/Data/tr_TR.xml | 19 +- lib/Zend/Locale/Data/trv.xml | 1122 +- lib/Zend/Locale/Data/trv_TW.xml | 19 +- lib/Zend/Locale/Data/ts.xml | 345 +- lib/Zend/Locale/Data/ts_ZA.xml | 19 +- lib/Zend/Locale/Data/tt.xml | 208 +- lib/Zend/Locale/Data/tt_RU.xml | 19 +- lib/Zend/Locale/Data/ug.xml | 71 +- lib/Zend/Locale/Data/ug_Arab.xml | 19 +- lib/Zend/Locale/Data/ug_Arab_CN.xml | 21 +- lib/Zend/Locale/Data/ug_CN.xml | 21 +- lib/Zend/Locale/Data/uk.xml | 7627 +++++----- lib/Zend/Locale/Data/uk_UA.xml | 19 +- lib/Zend/Locale/Data/ur.xml | 2040 +-- lib/Zend/Locale/Data/ur_IN.xml | 65 +- lib/Zend/Locale/Data/ur_PK.xml | 19 +- lib/Zend/Locale/Data/uz.xml | 469 +- lib/Zend/Locale/Data/uz_AF.xml | 21 +- lib/Zend/Locale/Data/uz_Arab.xml | 333 +- lib/Zend/Locale/Data/uz_Arab_AF.xml | 21 +- lib/Zend/Locale/Data/uz_Cyrl.xml | 19 +- lib/Zend/Locale/Data/uz_Cyrl_UZ.xml | 21 +- lib/Zend/Locale/Data/uz_Latn.xml | 341 +- lib/Zend/Locale/Data/uz_Latn_UZ.xml | 21 +- lib/Zend/Locale/Data/uz_UZ.xml | 21 +- lib/Zend/Locale/Data/ve.xml | 387 +- lib/Zend/Locale/Data/ve_ZA.xml | 19 +- lib/Zend/Locale/Data/vi.xml | 2112 ++- lib/Zend/Locale/Data/vi_VN.xml | 19 +- lib/Zend/Locale/Data/wal.xml | 697 +- lib/Zend/Locale/Data/wal_ET.xml | 19 +- lib/Zend/Locale/Data/wo.xml | 73 +- lib/Zend/Locale/Data/wo_Latn.xml | 19 +- lib/Zend/Locale/Data/wo_Latn_SN.xml | 21 +- lib/Zend/Locale/Data/wo_SN.xml | 19 +- lib/Zend/Locale/Data/xh.xml | 521 +- lib/Zend/Locale/Data/xh_ZA.xml | 19 +- lib/Zend/Locale/Data/yo.xml | 459 +- lib/Zend/Locale/Data/yo_NG.xml | 19 +- lib/Zend/Locale/Data/zh.xml | 8686 ++++++----- lib/Zend/Locale/Data/zh_CN.xml | 21 +- lib/Zend/Locale/Data/zh_HK.xml | 21 +- lib/Zend/Locale/Data/zh_Hans.xml | 19 +- lib/Zend/Locale/Data/zh_Hans_CN.xml | 21 +- lib/Zend/Locale/Data/zh_Hans_HK.xml | 35 +- lib/Zend/Locale/Data/zh_Hans_MO.xml | 21 +- lib/Zend/Locale/Data/zh_Hans_SG.xml | 175 +- lib/Zend/Locale/Data/zh_Hant.xml | 7448 +++++----- lib/Zend/Locale/Data/zh_Hant_HK.xml | 381 +- lib/Zend/Locale/Data/zh_Hant_MO.xml | 233 +- lib/Zend/Locale/Data/zh_Hant_TW.xml | 21 +- lib/Zend/Locale/Data/zh_MO.xml | 21 +- lib/Zend/Locale/Data/zh_SG.xml | 21 +- lib/Zend/Locale/Data/zh_TW.xml | 21 +- lib/Zend/Locale/Data/zu.xml | 657 +- lib/Zend/Locale/Data/zu_ZA.xml | 19 +- lib/Zend/Locale/Exception.php | 6 +- lib/Zend/Locale/Format.php | 151 +- lib/Zend/Locale/Math.php | 57 +- lib/Zend/Locale/Math/Exception.php | 6 +- lib/Zend/Locale/Math/PhpMath.php | 6 +- lib/Zend/Log.php | 234 +- lib/Zend/Log/Exception.php | 8 +- lib/Zend/Log/FactoryInterface.php | 38 + lib/Zend/Log/Filter/Abstract.php | 60 + lib/Zend/Log/Filter/Interface.php | 9 +- lib/Zend/Log/Filter/Message.php | 34 +- lib/Zend/Log/Filter/Priority.php | 45 +- lib/Zend/Log/Filter/Suppress.php | 21 +- lib/Zend/Log/Formatter/Firebug.php | 6 +- lib/Zend/Log/Formatter/Interface.php | 8 +- lib/Zend/Log/Formatter/Simple.php | 8 +- lib/Zend/Log/Formatter/Xml.php | 45 +- lib/Zend/Log/Writer/Abstract.php | 42 +- lib/Zend/Log/Writer/Db.php | 40 +- lib/Zend/Log/Writer/Firebug.php | 20 +- lib/Zend/Log/Writer/Mail.php | 20 +- lib/Zend/Log/Writer/Mock.php | 22 +- lib/Zend/Log/Writer/Null.php | 23 +- lib/Zend/Log/Writer/Stream.php | 43 +- lib/Zend/Log/Writer/Syslog.php | 95 +- lib/Zend/Log/Writer/ZendMonitor.php | 111 + lib/Zend/Mail.php | 260 +- lib/Zend/Mail/Exception.php | 6 +- lib/Zend/Mail/Message.php | 6 +- lib/Zend/Mail/Message/File.php | 6 +- lib/Zend/Mail/Message/Interface.php | 6 +- lib/Zend/Mail/Part.php | 6 +- lib/Zend/Mail/Part/File.php | 6 +- lib/Zend/Mail/Part/Interface.php | 6 +- lib/Zend/Mail/Protocol/Abstract.php | 70 +- lib/Zend/Mail/Protocol/Exception.php | 6 +- lib/Zend/Mail/Protocol/Imap.php | 6 +- lib/Zend/Mail/Protocol/Pop3.php | 6 +- lib/Zend/Mail/Protocol/Smtp.php | 6 +- lib/Zend/Mail/Protocol/Smtp/Auth/Crammd5.php | 8 +- lib/Zend/Mail/Protocol/Smtp/Auth/Login.php | 6 +- lib/Zend/Mail/Protocol/Smtp/Auth/Plain.php | 8 +- lib/Zend/Mail/Storage.php | 6 +- lib/Zend/Mail/Storage/Abstract.php | 6 +- lib/Zend/Mail/Storage/Exception.php | 6 +- lib/Zend/Mail/Storage/Folder.php | 6 +- lib/Zend/Mail/Storage/Folder/Interface.php | 6 +- lib/Zend/Mail/Storage/Folder/Maildir.php | 10 +- lib/Zend/Mail/Storage/Folder/Mbox.php | 10 +- lib/Zend/Mail/Storage/Imap.php | 8 +- lib/Zend/Mail/Storage/Maildir.php | 6 +- lib/Zend/Mail/Storage/Mbox.php | 6 +- lib/Zend/Mail/Storage/Pop3.php | 6 +- lib/Zend/Mail/Storage/Writable/Interface.php | 6 +- lib/Zend/Mail/Storage/Writable/Maildir.php | 8 +- lib/Zend/Mail/Transport/Abstract.php | 6 +- lib/Zend/Mail/Transport/Exception.php | 6 +- lib/Zend/Mail/Transport/Sendmail.php | 63 +- lib/Zend/Mail/Transport/Smtp.php | 10 +- lib/Zend/Markup.php | 134 + lib/Zend/Markup/Exception.php | 38 + lib/Zend/Markup/Parser/Bbcode.php | 504 + lib/Zend/Markup/Parser/Exception.php | 40 + lib/Zend/Markup/Parser/ParserInterface.php | 67 + lib/Zend/Markup/Parser/Textile.php | 570 + lib/Zend/Markup/Renderer/Exception.php | 40 + lib/Zend/Markup/Renderer/Html.php | 528 + lib/Zend/Markup/Renderer/Html/Code.php | 53 + .../Markup/Renderer/Html/HtmlAbstract.php | 69 + lib/Zend/Markup/Renderer/Html/Img.php | 84 + lib/Zend/Markup/Renderer/Html/List.php | 103 + lib/Zend/Markup/Renderer/Html/Url.php | 77 + lib/Zend/Markup/Renderer/RendererAbstract.php | 702 + .../Renderer/TokenConverterInterface.php | 44 + lib/Zend/Markup/Token.php | 306 + lib/Zend/Markup/TokenList.php | 124 + lib/Zend/Measure/Abstract.php | 54 +- lib/Zend/Measure/Acceleration.php | 6 +- lib/Zend/Measure/Angle.php | 6 +- lib/Zend/Measure/Area.php | 6 +- lib/Zend/Measure/Binary.php | 6 +- lib/Zend/Measure/Capacitance.php | 6 +- lib/Zend/Measure/Cooking/Volume.php | 6 +- lib/Zend/Measure/Cooking/Weight.php | 6 +- lib/Zend/Measure/Current.php | 6 +- lib/Zend/Measure/Density.php | 6 +- lib/Zend/Measure/Energy.php | 6 +- lib/Zend/Measure/Exception.php | 6 +- lib/Zend/Measure/Flow/Mass.php | 6 +- lib/Zend/Measure/Flow/Mole.php | 6 +- lib/Zend/Measure/Flow/Volume.php | 6 +- lib/Zend/Measure/Force.php | 6 +- lib/Zend/Measure/Frequency.php | 6 +- lib/Zend/Measure/Illumination.php | 6 +- lib/Zend/Measure/Length.php | 6 +- lib/Zend/Measure/Lightness.php | 6 +- lib/Zend/Measure/Number.php | 10 +- lib/Zend/Measure/Power.php | 6 +- lib/Zend/Measure/Pressure.php | 6 +- lib/Zend/Measure/Speed.php | 6 +- lib/Zend/Measure/Temperature.php | 6 +- lib/Zend/Measure/Time.php | 6 +- lib/Zend/Measure/Torque.php | 6 +- lib/Zend/Measure/Viscosity/Dynamic.php | 6 +- lib/Zend/Measure/Viscosity/Kinematic.php | 6 +- lib/Zend/Measure/Volume.php | 6 +- lib/Zend/Measure/Weight.php | 6 +- lib/Zend/Memory.php | 21 +- lib/Zend/Memory/AccessController.php | 7 +- lib/Zend/Memory/Container.php | 7 +- lib/Zend/Memory/Container/Interface.php | 7 +- lib/Zend/Memory/Container/Locked.php | 7 +- lib/Zend/Memory/Container/Movable.php | 7 +- lib/Zend/Memory/Exception.php | 7 +- lib/Zend/Memory/Manager.php | 7 +- lib/Zend/Memory/Value.php | 7 +- lib/Zend/Mime.php | 6 +- lib/Zend/Mime/Decode.php | 6 +- lib/Zend/Mime/Exception.php | 6 +- lib/Zend/Mime/Message.php | 6 +- lib/Zend/Mime/Part.php | 6 +- lib/Zend/Navigation.php | 6 +- lib/Zend/Navigation/Container.php | 6 +- lib/Zend/Navigation/Exception.php | 6 +- lib/Zend/Navigation/Page.php | 6 +- lib/Zend/Navigation/Page/Mvc.php | 6 +- lib/Zend/Navigation/Page/Uri.php | 6 +- lib/Zend/Oauth.php | 89 + lib/Zend/Oauth/Client.php | 336 + lib/Zend/Oauth/Config.php | 658 + lib/Zend/Oauth/Config/ConfigInterface.php | 75 + lib/Zend/Oauth/Consumer.php | 273 + lib/Zend/Oauth/Exception.php | 32 + lib/Zend/Oauth/Http.php | 266 + lib/Zend/Oauth/Http/AccessToken.php | 189 + lib/Zend/Oauth/Http/RequestToken.php | 162 + lib/Zend/Oauth/Http/UserAuthorization.php | 78 + lib/Zend/Oauth/Http/Utility.php | 217 + lib/Zend/Oauth/Signature/Hmac.php | 54 + lib/Zend/Oauth/Signature/Plaintext.php | 49 + lib/Zend/Oauth/Signature/Rsa.php | 65 + .../Oauth/Signature/SignatureAbstract.php | 183 + lib/Zend/Oauth/Token.php | 285 + lib/Zend/Oauth/Token/Access.php | 99 + lib/Zend/Oauth/Token/AuthorizedRequest.php | 102 + lib/Zend/Oauth/Token/Request.php | 50 + lib/Zend/OpenId.php | 14 +- lib/Zend/OpenId/Consumer.php | 6 +- lib/Zend/OpenId/Consumer/Storage.php | 6 +- lib/Zend/OpenId/Consumer/Storage/File.php | 311 +- lib/Zend/OpenId/Exception.php | 6 +- lib/Zend/OpenId/Extension.php | 6 +- lib/Zend/OpenId/Extension/Sreg.php | 6 +- lib/Zend/OpenId/Provider.php | 6 +- lib/Zend/OpenId/Provider/Storage.php | 6 +- lib/Zend/OpenId/Provider/Storage/File.php | 257 +- lib/Zend/OpenId/Provider/User.php | 6 +- lib/Zend/OpenId/Provider/User/Session.php | 6 +- lib/Zend/Paginator.php | 28 +- lib/Zend/Paginator/Adapter/Array.php | 6 +- lib/Zend/Paginator/Adapter/DbSelect.php | 6 +- lib/Zend/Paginator/Adapter/DbTableSelect.php | 6 +- lib/Zend/Paginator/Adapter/Interface.php | 6 +- lib/Zend/Paginator/Adapter/Iterator.php | 15 +- lib/Zend/Paginator/Adapter/Null.php | 15 +- lib/Zend/Paginator/AdapterAggregate.php | 12 +- lib/Zend/Paginator/Exception.php | 6 +- lib/Zend/Paginator/ScrollingStyle/All.php | 6 +- lib/Zend/Paginator/ScrollingStyle/Elastic.php | 6 +- .../Paginator/ScrollingStyle/Interface.php | 6 +- lib/Zend/Paginator/ScrollingStyle/Jumping.php | 6 +- lib/Zend/Paginator/ScrollingStyle/Sliding.php | 6 +- .../Paginator/SerializableLimitIterator.php | 141 + lib/Zend/Pdf.php | 8 +- lib/Zend/Pdf/Action.php | 44 +- lib/Zend/Pdf/Action/GoTo.php | 8 +- lib/Zend/Pdf/Action/GoTo3DView.php | 6 +- lib/Zend/Pdf/Action/GoToE.php | 6 +- lib/Zend/Pdf/Action/GoToR.php | 6 +- lib/Zend/Pdf/Action/Hide.php | 6 +- lib/Zend/Pdf/Action/ImportData.php | 6 +- lib/Zend/Pdf/Action/JavaScript.php | 6 +- lib/Zend/Pdf/Action/Launch.php | 6 +- lib/Zend/Pdf/Action/Movie.php | 6 +- lib/Zend/Pdf/Action/Named.php | 6 +- lib/Zend/Pdf/Action/Rendition.php | 6 +- lib/Zend/Pdf/Action/ResetForm.php | 6 +- lib/Zend/Pdf/Action/SetOCGState.php | 6 +- lib/Zend/Pdf/Action/Sound.php | 6 +- lib/Zend/Pdf/Action/SubmitForm.php | 6 +- lib/Zend/Pdf/Action/Thread.php | 6 +- lib/Zend/Pdf/Action/Trans.php | 6 +- lib/Zend/Pdf/Action/URI.php | 136 +- lib/Zend/Pdf/Action/Unknown.php | 6 +- lib/Zend/Pdf/Annotation.php | 7 +- lib/Zend/Pdf/Annotation/FileAttachment.php | 6 +- lib/Zend/Pdf/Annotation/Link.php | 6 +- lib/Zend/Pdf/Annotation/Markup.php | 141 + lib/Zend/Pdf/Annotation/Text.php | 6 +- lib/Zend/Pdf/Cmap.php | 6 +- lib/Zend/Pdf/Cmap/ByteEncoding.php | 6 +- lib/Zend/Pdf/Cmap/ByteEncoding/Static.php | 6 +- lib/Zend/Pdf/Cmap/SegmentToDelta.php | 6 +- lib/Zend/Pdf/Cmap/TrimmedTable.php | 6 +- lib/Zend/Pdf/Color.php | 6 +- lib/Zend/Pdf/Color/Cmyk.php | 6 +- lib/Zend/Pdf/Color/GrayScale.php | 6 +- lib/Zend/Pdf/Color/Html.php | 6 +- lib/Zend/Pdf/Color/Rgb.php | 6 +- lib/Zend/Pdf/Destination.php | 6 +- lib/Zend/Pdf/Destination/Explicit.php | 6 +- lib/Zend/Pdf/Destination/Fit.php | 6 +- lib/Zend/Pdf/Destination/FitBoundingBox.php | 6 +- .../FitBoundingBoxHorizontally.php | 6 +- .../Destination/FitBoundingBoxVertically.php | 6 +- lib/Zend/Pdf/Destination/FitHorizontally.php | 6 +- lib/Zend/Pdf/Destination/FitRectangle.php | 6 +- lib/Zend/Pdf/Destination/FitVertically.php | 6 +- lib/Zend/Pdf/Destination/Named.php | 6 +- lib/Zend/Pdf/Destination/Unknown.php | 6 +- lib/Zend/Pdf/Destination/Zoom.php | 6 +- lib/Zend/Pdf/Element.php | 6 +- lib/Zend/Pdf/Element/Array.php | 6 +- lib/Zend/Pdf/Element/Boolean.php | 6 +- lib/Zend/Pdf/Element/Dictionary.php | 6 +- lib/Zend/Pdf/Element/Name.php | 6 +- lib/Zend/Pdf/Element/Null.php | 6 +- lib/Zend/Pdf/Element/Numeric.php | 6 +- lib/Zend/Pdf/Element/Object.php | 6 +- lib/Zend/Pdf/Element/Object/Stream.php | 18 +- lib/Zend/Pdf/Element/Reference.php | 6 +- lib/Zend/Pdf/Element/Reference/Context.php | 6 +- lib/Zend/Pdf/Element/Reference/Table.php | 6 +- lib/Zend/Pdf/Element/Stream.php | 6 +- lib/Zend/Pdf/Element/String.php | 8 +- lib/Zend/Pdf/Element/String/Binary.php | 6 +- lib/Zend/Pdf/ElementFactory.php | 6 +- lib/Zend/Pdf/ElementFactory/Interface.php | 6 +- lib/Zend/Pdf/ElementFactory/Proxy.php | 6 +- lib/Zend/Pdf/Exception.php | 6 +- lib/Zend/Pdf/FileParser.php | 6 +- lib/Zend/Pdf/FileParser/Font.php | 6 +- lib/Zend/Pdf/FileParser/Font/OpenType.php | 13 +- .../Pdf/FileParser/Font/OpenType/TrueType.php | 6 +- lib/Zend/Pdf/FileParser/Image.php | 6 +- lib/Zend/Pdf/FileParser/Image/Png.php | 12 +- lib/Zend/Pdf/FileParserDataSource.php | 6 +- lib/Zend/Pdf/FileParserDataSource/File.php | 6 +- lib/Zend/Pdf/FileParserDataSource/String.php | 6 +- lib/Zend/Pdf/Filter/Ascii85.php | 133 +- lib/Zend/Pdf/Filter/AsciiHex.php | 6 +- lib/Zend/Pdf/Filter/Compression.php | 6 +- lib/Zend/Pdf/Filter/Compression/Flate.php | 6 +- lib/Zend/Pdf/Filter/Compression/Lzw.php | 6 +- lib/Zend/Pdf/Filter/Interface.php | 6 +- lib/Zend/Pdf/Filter/RunLength.php | 124 + lib/Zend/Pdf/Font.php | 14 +- lib/Zend/Pdf/Image.php | 6 +- lib/Zend/Pdf/NameTree.php | 6 +- lib/Zend/Pdf/Outline.php | 6 +- lib/Zend/Pdf/Outline/Created.php | 6 +- lib/Zend/Pdf/Outline/Loaded.php | 8 +- lib/Zend/Pdf/Page.php | 153 +- lib/Zend/Pdf/Parser.php | 8 +- .../RecursivelyIteratableObjectsContainer.php | 6 +- lib/Zend/Pdf/Resource.php | 6 +- lib/Zend/Pdf/Resource/Font.php | 6 +- lib/Zend/Pdf/Resource/Font/CidFont.php | 6 +- .../Pdf/Resource/Font/CidFont/TrueType.php | 6 +- lib/Zend/Pdf/Resource/Font/Extracted.php | 33 +- lib/Zend/Pdf/Resource/Font/FontDescriptor.php | 6 +- lib/Zend/Pdf/Resource/Font/Simple.php | 6 +- lib/Zend/Pdf/Resource/Font/Simple/Parsed.php | 6 +- .../Resource/Font/Simple/Parsed/TrueType.php | 6 +- .../Pdf/Resource/Font/Simple/Standard.php | 6 +- .../Resource/Font/Simple/Standard/Courier.php | 6 +- .../Font/Simple/Standard/CourierBold.php | 6 +- .../Simple/Standard/CourierBoldOblique.php | 6 +- .../Font/Simple/Standard/CourierOblique.php | 6 +- .../Font/Simple/Standard/Helvetica.php | 6 +- .../Font/Simple/Standard/HelveticaBold.php | 6 +- .../Simple/Standard/HelveticaBoldOblique.php | 6 +- .../Font/Simple/Standard/HelveticaOblique.php | 6 +- .../Resource/Font/Simple/Standard/Symbol.php | 6 +- .../Font/Simple/Standard/TimesBold.php | 6 +- .../Font/Simple/Standard/TimesBoldItalic.php | 6 +- .../Font/Simple/Standard/TimesItalic.php | 6 +- .../Font/Simple/Standard/TimesRoman.php | 6 +- .../Font/Simple/Standard/ZapfDingbats.php | 6 +- lib/Zend/Pdf/Resource/Font/Type0.php | 6 +- lib/Zend/Pdf/Resource/Image.php | 6 +- lib/Zend/Pdf/Resource/Image/Jpeg.php | 6 +- lib/Zend/Pdf/Resource/Image/Png.php | 8 +- lib/Zend/Pdf/Resource/Image/Tiff.php | 6 +- lib/Zend/Pdf/Resource/ImageFactory.php | 6 +- lib/Zend/Pdf/StringParser.php | 15 +- lib/Zend/Pdf/Style.php | 6 +- lib/Zend/Pdf/Target.php | 6 +- lib/Zend/Pdf/Trailer.php | 6 +- lib/Zend/Pdf/Trailer/Generator.php | 6 +- lib/Zend/Pdf/Trailer/Keeper.php | 8 +- lib/Zend/Pdf/UpdateInfoContainer.php | 6 +- lib/Zend/ProgressBar.php | 6 +- lib/Zend/ProgressBar/Adapter.php | 6 +- lib/Zend/ProgressBar/Adapter/Console.php | 6 +- lib/Zend/ProgressBar/Adapter/Exception.php | 6 +- lib/Zend/ProgressBar/Adapter/JsPull.php | 6 +- lib/Zend/ProgressBar/Adapter/JsPush.php | 6 +- lib/Zend/ProgressBar/Exception.php | 6 +- lib/Zend/Queue.php | 6 +- lib/Zend/Queue/Adapter/Activemq.php | 6 +- lib/Zend/Queue/Adapter/AdapterAbstract.php | 6 +- lib/Zend/Queue/Adapter/AdapterInterface.php | 6 +- lib/Zend/Queue/Adapter/Array.php | 7 +- lib/Zend/Queue/Adapter/Db.php | 16 +- lib/Zend/Queue/Adapter/Db/Message.php | 6 +- lib/Zend/Queue/Adapter/Db/Queue.php | 6 +- .../Db/{queue_sqlite.php => queue_sqlite.sql} | 0 lib/Zend/Queue/Adapter/Memcacheq.php | 6 +- lib/Zend/Queue/Adapter/Null.php | 6 +- lib/Zend/Queue/Adapter/PlatformJobQueue.php | 6 +- lib/Zend/Queue/Exception.php | 6 +- lib/Zend/Queue/Message.php | 6 +- lib/Zend/Queue/Message/Iterator.php | 6 +- lib/Zend/Queue/Message/PlatformJob.php | 6 +- lib/Zend/Queue/Stomp/Client.php | 6 +- lib/Zend/Queue/Stomp/Client/Connection.php | 8 +- .../Stomp/Client/ConnectionInterface.php | 8 +- lib/Zend/Queue/Stomp/Frame.php | 6 +- lib/Zend/Queue/Stomp/FrameInterface.php | 6 +- lib/Zend/Reflection/Class.php | 6 +- lib/Zend/Reflection/Docblock.php | 6 +- lib/Zend/Reflection/Docblock/Tag.php | 6 +- lib/Zend/Reflection/Docblock/Tag/Param.php | 6 +- lib/Zend/Reflection/Docblock/Tag/Return.php | 6 +- lib/Zend/Reflection/Exception.php | 6 +- lib/Zend/Reflection/Extension.php | 6 +- lib/Zend/Reflection/File.php | 9 +- lib/Zend/Reflection/Function.php | 6 +- lib/Zend/Reflection/Method.php | 6 +- lib/Zend/Reflection/Parameter.php | 6 +- lib/Zend/Reflection/Property.php | 6 +- lib/Zend/Registry.php | 6 +- lib/Zend/Rest/Client.php | 6 +- lib/Zend/Rest/Client/Exception.php | 6 +- lib/Zend/Rest/Client/Result.php | 31 +- lib/Zend/Rest/Client/Result/Exception.php | 6 +- lib/Zend/Rest/Controller.php | 8 +- lib/Zend/Rest/Exception.php | 6 +- lib/Zend/Rest/Route.php | 60 +- lib/Zend/Rest/Server.php | 16 +- lib/Zend/Rest/Server/Exception.php | 6 +- lib/Zend/Search/Exception.php | 6 +- lib/Zend/Search/Lucene.php | 63 +- lib/Zend/Search/Lucene/Analysis/Analyzer.php | 6 +- .../Lucene/Analysis/Analyzer/Common.php | 6 +- .../Lucene/Analysis/Analyzer/Common/Text.php | 6 +- .../Analyzer/Common/Text/CaseInsensitive.php | 6 +- .../Analysis/Analyzer/Common/TextNum.php | 6 +- .../Common/TextNum/CaseInsensitive.php | 6 +- .../Lucene/Analysis/Analyzer/Common/Utf8.php | 6 +- .../Analyzer/Common/Utf8/CaseInsensitive.php | 6 +- .../Analysis/Analyzer/Common/Utf8Num.php | 6 +- .../Common/Utf8Num/CaseInsensitive.php | 6 +- lib/Zend/Search/Lucene/Analysis/Token.php | 6 +- .../Search/Lucene/Analysis/TokenFilter.php | 6 +- .../Lucene/Analysis/TokenFilter/LowerCase.php | 6 +- .../Analysis/TokenFilter/LowerCaseUtf8.php | 6 +- .../Analysis/TokenFilter/ShortWords.php | 6 +- .../Lucene/Analysis/TokenFilter/StopWords.php | 6 +- lib/Zend/Search/Lucene/Document.php | 6 +- lib/Zend/Search/Lucene/Document/Docx.php | 15 +- lib/Zend/Search/Lucene/Document/Exception.php | 6 +- lib/Zend/Search/Lucene/Document/Html.php | 33 +- lib/Zend/Search/Lucene/Document/OpenXml.php | 10 +- lib/Zend/Search/Lucene/Document/Pptx.php | 15 +- lib/Zend/Search/Lucene/Document/Xlsx.php | 15 +- lib/Zend/Search/Lucene/Exception.php | 6 +- lib/Zend/Search/Lucene/FSM.php | 6 +- lib/Zend/Search/Lucene/FSMAction.php | 6 +- lib/Zend/Search/Lucene/Field.php | 6 +- .../Search/Lucene/Index/DictionaryLoader.php | 6 +- lib/Zend/Search/Lucene/Index/DocsFilter.php | 6 +- lib/Zend/Search/Lucene/Index/FieldInfo.php | 6 +- lib/Zend/Search/Lucene/Index/SegmentInfo.php | 22 +- .../Search/Lucene/Index/SegmentMerger.php | 6 +- .../Search/Lucene/Index/SegmentWriter.php | 6 +- .../Index/SegmentWriter/DocumentWriter.php | 30 +- .../Index/SegmentWriter/StreamWriter.php | 6 +- lib/Zend/Search/Lucene/Index/Term.php | 6 +- lib/Zend/Search/Lucene/Index/TermInfo.php | 6 +- .../Lucene/Index/TermsPriorityQueue.php | 6 +- .../Lucene/Index/TermsStream/Interface.php | 6 +- lib/Zend/Search/Lucene/Index/Writer.php | 13 +- lib/Zend/Search/Lucene/Interface.php | 6 +- lib/Zend/Search/Lucene/LockManager.php | 6 +- lib/Zend/Search/Lucene/MultiSearcher.php | 17 +- lib/Zend/Search/Lucene/PriorityQueue.php | 6 +- lib/Zend/Search/Lucene/Proxy.php | 6 +- .../Search/BooleanExpressionRecognizer.php | 6 +- .../Lucene/Search/Highlighter/Default.php | 6 +- .../Lucene/Search/Highlighter/Interface.php | 6 +- lib/Zend/Search/Lucene/Search/Query.php | 6 +- .../Search/Lucene/Search/Query/Boolean.php | 6 +- lib/Zend/Search/Lucene/Search/Query/Empty.php | 6 +- lib/Zend/Search/Lucene/Search/Query/Fuzzy.php | 6 +- .../Lucene/Search/Query/Insignificant.php | 6 +- .../Search/Lucene/Search/Query/MultiTerm.php | 6 +- .../Search/Lucene/Search/Query/Phrase.php | 6 +- .../Lucene/Search/Query/Preprocessing.php | 6 +- .../Search/Query/Preprocessing/Fuzzy.php | 6 +- .../Search/Query/Preprocessing/Phrase.php | 6 +- .../Search/Query/Preprocessing/Term.php | 6 +- lib/Zend/Search/Lucene/Search/Query/Range.php | 6 +- lib/Zend/Search/Lucene/Search/Query/Term.php | 6 +- .../Search/Lucene/Search/Query/Wildcard.php | 6 +- lib/Zend/Search/Lucene/Search/QueryEntry.php | 6 +- .../Lucene/Search/QueryEntry/Phrase.php | 6 +- .../Lucene/Search/QueryEntry/Subquery.php | 6 +- .../Search/Lucene/Search/QueryEntry/Term.php | 6 +- lib/Zend/Search/Lucene/Search/QueryHit.php | 6 +- lib/Zend/Search/Lucene/Search/QueryLexer.php | 6 +- lib/Zend/Search/Lucene/Search/QueryParser.php | 24 +- .../Lucene/Search/QueryParserContext.php | 8 +- .../Lucene/Search/QueryParserException.php | 6 +- lib/Zend/Search/Lucene/Search/QueryToken.php | 6 +- lib/Zend/Search/Lucene/Search/Similarity.php | 6 +- .../Lucene/Search/Similarity/Default.php | 6 +- lib/Zend/Search/Lucene/Search/Weight.php | 6 +- .../Search/Lucene/Search/Weight/Boolean.php | 6 +- .../Search/Lucene/Search/Weight/Empty.php | 6 +- .../Search/Lucene/Search/Weight/MultiTerm.php | 6 +- .../Search/Lucene/Search/Weight/Phrase.php | 6 +- lib/Zend/Search/Lucene/Search/Weight/Term.php | 6 +- lib/Zend/Search/Lucene/Storage/Directory.php | 6 +- .../Lucene/Storage/Directory/Filesystem.php | 6 +- lib/Zend/Search/Lucene/Storage/File.php | 6 +- .../Search/Lucene/Storage/File/Filesystem.php | 6 +- .../Search/Lucene/Storage/File/Memory.php | 6 +- .../Lucene/TermStreamsPriorityQueue.php | 6 +- lib/Zend/Serializer.php | 188 + .../Serializer/Adapter/AdapterAbstract.php | 112 + .../Serializer/Adapter/AdapterInterface.php | 92 + lib/Zend/Serializer/Adapter/Amf0.php | 88 + lib/Zend/Serializer/Adapter/Amf3.php | 87 + lib/Zend/Serializer/Adapter/Igbinary.php | 98 + lib/Zend/Serializer/Adapter/Json.php | 93 + lib/Zend/Serializer/Adapter/PhpCode.php | 67 + lib/Zend/Serializer/Adapter/PhpSerialize.php | 94 + lib/Zend/Serializer/Adapter/PythonPickle.php | 1494 ++ lib/Zend/Serializer/Adapter/Wddx.php | 118 + lib/Zend/Serializer/Exception.php | 33 + lib/Zend/Server/Abstract.php | 6 +- lib/Zend/Server/Cache.php | 6 +- lib/Zend/Server/Definition.php | 6 +- lib/Zend/Server/Exception.php | 4 +- lib/Zend/Server/Interface.php | 6 +- lib/Zend/Server/Method/Callback.php | 6 +- lib/Zend/Server/Method/Definition.php | 6 +- lib/Zend/Server/Method/Parameter.php | 6 +- lib/Zend/Server/Method/Prototype.php | 6 +- lib/Zend/Server/Reflection.php | 6 +- lib/Zend/Server/Reflection/Class.php | 6 +- lib/Zend/Server/Reflection/Exception.php | 6 +- lib/Zend/Server/Reflection/Function.php | 6 +- .../Server/Reflection/Function/Abstract.php | 10 +- lib/Zend/Server/Reflection/Method.php | 6 +- lib/Zend/Server/Reflection/Node.php | 6 +- lib/Zend/Server/Reflection/Parameter.php | 6 +- lib/Zend/Server/Reflection/Prototype.php | 6 +- lib/Zend/Server/Reflection/ReturnValue.php | 6 +- lib/Zend/Service/Abstract.php | 6 +- lib/Zend/Service/Akismet.php | 6 +- lib/Zend/Service/Amazon.php | 6 +- lib/Zend/Service/Amazon/Abstract.php | 66 +- lib/Zend/Service/Amazon/Accessories.php | 6 +- lib/Zend/Service/Amazon/CustomerReview.php | 6 +- lib/Zend/Service/Amazon/Ec2.php | 6 +- lib/Zend/Service/Amazon/Ec2/Abstract.php | 87 +- .../Service/Amazon/Ec2/Availabilityzones.php | 9 +- lib/Zend/Service/Amazon/Ec2/CloudWatch.php | 9 +- lib/Zend/Service/Amazon/Ec2/Ebs.php | 12 +- lib/Zend/Service/Amazon/Ec2/Elasticip.php | 9 +- lib/Zend/Service/Amazon/Ec2/Exception.php | 9 +- lib/Zend/Service/Amazon/Ec2/Image.php | 9 +- lib/Zend/Service/Amazon/Ec2/Instance.php | 11 +- .../Service/Amazon/Ec2/Instance/Reserved.php | 9 +- .../Service/Amazon/Ec2/Instance/Windows.php | 13 +- lib/Zend/Service/Amazon/Ec2/Keypair.php | 9 +- lib/Zend/Service/Amazon/Ec2/Region.php | 10 +- lib/Zend/Service/Amazon/Ec2/Response.php | 9 +- .../Service/Amazon/Ec2/Securitygroups.php | 9 +- lib/Zend/Service/Amazon/EditorialReview.php | 6 +- lib/Zend/Service/Amazon/Exception.php | 6 +- lib/Zend/Service/Amazon/Image.php | 6 +- lib/Zend/Service/Amazon/Item.php | 21 +- lib/Zend/Service/Amazon/ListmaniaList.php | 6 +- lib/Zend/Service/Amazon/Offer.php | 24 +- lib/Zend/Service/Amazon/OfferSet.php | 10 +- lib/Zend/Service/Amazon/Query.php | 6 +- lib/Zend/Service/Amazon/ResultSet.php | 6 +- lib/Zend/Service/Amazon/S3.php | 112 +- lib/Zend/Service/Amazon/S3/Exception.php | 6 +- lib/Zend/Service/Amazon/S3/Stream.php | 23 +- lib/Zend/Service/Amazon/SimilarProduct.php | 6 +- lib/Zend/Service/Amazon/Sqs.php | 22 +- lib/Zend/Service/Amazon/Sqs/Exception.php | 6 +- lib/Zend/Service/Audioscrobbler.php | 6 +- lib/Zend/Service/Delicious.php | 6 +- lib/Zend/Service/Delicious/Exception.php | 6 +- lib/Zend/Service/Delicious/Post.php | 6 +- lib/Zend/Service/Delicious/PostList.php | 6 +- lib/Zend/Service/Delicious/SimplePost.php | 6 +- .../DeveloperGarden/BaseUserService.php | 399 + .../BaseUserService/AccountBalance.php | 62 + .../DeveloperGarden/Client/ClientAbstract.php | 430 + .../DeveloperGarden/Client/Exception.php | 38 + .../Service/DeveloperGarden/Client/Soap.php | 340 + .../DeveloperGarden/ConferenceCall.php | 872 ++ .../ConferenceCall/ConferenceAccount.php | 62 + .../ConferenceCall/ConferenceDetail.php | 129 + .../ConferenceCall/ConferenceSchedule.php | 262 + .../ConferenceCall/Exception.php | 38 + .../ConferenceCall/Participant.php | 84 + .../ConferenceCall/ParticipantDetail.php | 195 + .../ConferenceCall/ParticipantStatus.php | 103 + .../Service/DeveloperGarden/Credential.php | 186 + .../Service/DeveloperGarden/Exception.php | 38 + .../Service/DeveloperGarden/IpLocation.php | 120 + .../DeveloperGarden/IpLocation/IpAddress.php | 130 + .../Service/DeveloperGarden/LocalSearch.php | 105 + .../DeveloperGarden/LocalSearch/Exception.php | 38 + .../LocalSearch/SearchParameters.php | 536 + .../BaseUserService/ChangeQuotaPool.php | 103 + .../BaseUserService/GetAccountBalance.php | 72 + .../BaseUserService/GetQuotaInformation.php | 72 + ...ddConferenceTemplateParticipantRequest.php | 91 + .../CommitConferenceRequest.php | 69 + .../CreateConferenceRequest.php | 136 + .../CreateConferenceTemplateRequest.php | 113 + .../GetConferenceListRequest.php | 104 + .../GetConferenceStatusRequest.php | 106 + .../GetConferenceTemplateListRequest.php | 69 + ...etConferenceTemplateParticipantRequest.php | 90 + .../GetConferenceTemplateRequest.php | 69 + .../GetParticipantStatusRequest.php | 90 + .../GetRunningConferenceRequest.php | 69 + .../ConferenceCall/NewParticipantRequest.php | 91 + .../RemoveConferenceRequest.php | 69 + ...veConferenceTemplateParticipantRequest.php | 90 + .../RemoveConferenceTemplateRequest.php | 69 + .../RemoveParticipantRequest.php | 90 + .../UpdateConferenceRequest.php | 158 + ...teConferenceTemplateParticipantRequest.php | 113 + .../UpdateConferenceTemplateRequest.php | 113 + .../UpdateParticipantRequest.php | 138 + .../DeveloperGarden/Request/Exception.php | 39 + .../Request/IpLocation/LocateIPRequest.php | 114 + .../LocalSearch/LocalSearchRequest.php | 113 + .../Request/RequestAbstract.php | 72 + .../Request/SendSms/SendFlashSMS.php | 46 + .../Request/SendSms/SendSMS.php | 46 + .../Request/SendSms/SendSmsAbstract.php | 281 + .../SmsValidation/GetValidatedNumbers.php | 39 + .../Request/SmsValidation/Invalidate.php | 80 + .../SmsValidation/SendValidationKeyword.php | 39 + .../Request/SmsValidation/Validate.php | 110 + .../Request/VoiceButler/CallStatus.php | 100 + .../Request/VoiceButler/NewCall.php | 238 + .../Request/VoiceButler/NewCallSequenced.php | 92 + .../Request/VoiceButler/TearDownCall.php | 78 + .../VoiceButler/VoiceButlerAbstract.php | 39 + .../DeveloperGarden/Response/BaseType.php | 140 + .../ChangeQuotaPoolResponse.php | 39 + .../GetAccountBalanceResponse.php | 39 + .../GetQuotaInformationResponse.php | 90 + ...dConferenceTemplateParticipantResponse.php | 45 + ...ferenceTemplateParticipantResponseType.php | 55 + .../ConferenceCall/CCSResponseType.php | 39 + .../CommitConferenceResponse.php | 46 + .../ConferenceCall/ConferenceCallAbstract.php | 75 + .../CreateConferenceResponse.php | 45 + .../CreateConferenceResponseType.php | 55 + .../CreateConferenceTemplateResponse.php | 45 + .../CreateConferenceTemplateResponseType.php | 55 + .../GetConferenceListResponse.php | 45 + .../GetConferenceListResponseType.php | 55 + .../GetConferenceStatusResponse.php | 45 + .../GetConferenceStatusResponseType.php | 148 + .../GetConferenceTemplateListResponse.php | 45 + .../GetConferenceTemplateListResponseType.php | 55 + ...tConferenceTemplateParticipantResponse.php | 45 + ...ferenceTemplateParticipantResponseType.php | 55 + .../GetConferenceTemplateResponse.php | 45 + .../GetConferenceTemplateResponseType.php | 97 + .../GetParticipantStatusResponse.php | 45 + .../GetParticipantStatusResponseType.php | 55 + .../GetRunningConferenceResponse.php | 45 + .../GetRunningConferenceResponseType.php | 55 + .../ConferenceCall/NewParticipantResponse.php | 45 + .../NewParticipantResponseType.php | 55 + .../RemoveConferenceResponse.php | 46 + ...eConferenceTemplateParticipantResponse.php | 46 + .../RemoveConferenceTemplateResponse.php | 46 + .../RemoveParticipantResponse.php | 46 + .../UpdateConferenceResponse.php | 46 + ...eConferenceTemplateParticipantResponse.php | 46 + .../UpdateConferenceTemplateResponse.php | 46 + .../UpdateParticipantResponse.php | 46 + .../DeveloperGarden/Response/Exception.php | 39 + .../Response/IpLocation/CityType.php | 77 + .../IpLocation/GeoCoordinatesType.php | 66 + .../IpLocation/IPAddressLocationType.php | 141 + .../Response/IpLocation/LocateIPResponse.php | 98 + .../IpLocation/LocateIPResponseType.php | 46 + .../Response/IpLocation/RegionType.php | 80 + .../LocalSearch/LocalSearchResponse.php | 89 + .../LocalSearch/LocalSearchResponseType.php | 44 + .../Response/ResponseAbstract.php | 111 + .../SecurityTokenServer/Exception.php | 39 + .../SecurityTokenServer/GetTokensResponse.php | 94 + .../SecurityTokenServer}/Interface.php | 30 +- .../SecurityTokenResponse.php | 116 + .../Response/SendSms/SendFlashSMSResponse.php | 39 + .../Response/SendSms/SendSMSResponse.php | 39 + .../Response/SendSms/SendSmsAbstract.php | 119 + .../GetValidatedNumbersResponse.php | 55 + .../SmsValidation/InvalidateResponse.php | 39 + .../SendValidationKeywordResponse.php | 39 + .../SmsValidation/ValidateResponse.php | 39 + .../SmsValidation/ValidatedNumber.php | 64 + .../VoiceButler/CallStatus2Response.php | 88 + .../VoiceButler/CallStatusResponse.php | 154 + .../Response/VoiceButler/NewCallResponse.php | 60 + .../VoiceButler/NewCallSequencedResponse.php | 39 + .../VoiceButler/TearDownCallResponse.php | 50 + .../VoiceButler/VoiceButlerAbstract.php | 128 + .../DeveloperGarden/SecurityTokenServer.php | 127 + .../SecurityTokenServer/Cache.php | 207 + lib/Zend/Service/DeveloperGarden/SendSms.php | 156 + .../Service/DeveloperGarden/SmsValidation.php | 193 + .../Service/DeveloperGarden/VoiceCall.php | 226 + .../DeveloperGarden/Wsdl/IPLocation.wsdl | 84 + .../DeveloperGarden/Wsdl/IPLocation.xsd | 69 + .../Wsdl/ODGBaseUserService.wsdl | 104 + .../Wsdl/ODGBaseUserService.xsd | 72 + .../DeveloperGarden/Wsdl/SmsService.wsdl | 122 + .../Wsdl/SmsValidationUserService.wsdl | 169 + .../DeveloperGarden/Wsdl/TokenService.wsdl | 353 + .../Wsdl/VoiceButlerService.wsdl | 164 + .../Wsdl/VoiceButlerService.xsd | 264 + .../Service/DeveloperGarden/Wsdl/ccsPort.wsdl | 463 + .../Service/DeveloperGarden/Wsdl/ccsPort.xsd | 736 + .../DeveloperGarden/Wsdl/localsearch.wsdl | 83 + .../DeveloperGarden/Wsdl/localsearch.xsd | 31 + lib/Zend/Service/Exception.php | 6 +- lib/Zend/Service/Flickr.php | 16 +- lib/Zend/Service/Flickr/Image.php | 6 +- lib/Zend/Service/Flickr/Result.php | 6 +- lib/Zend/Service/Flickr/ResultSet.php | 8 +- lib/Zend/Service/LiveDocx.php | 415 + lib/Zend/Service/LiveDocx/Exception.php | 39 + lib/Zend/Service/LiveDocx/MailMerge.php | 978 ++ lib/Zend/Service/Nirvanix.php | 6 +- lib/Zend/Service/Nirvanix/Exception.php | 6 +- lib/Zend/Service/Nirvanix/Namespace/Base.php | 6 +- lib/Zend/Service/Nirvanix/Namespace/Imfs.php | 6 +- lib/Zend/Service/Nirvanix/Response.php | 6 +- lib/Zend/Service/ReCaptcha.php | 6 +- lib/Zend/Service/ReCaptcha/Exception.php | 6 +- lib/Zend/Service/ReCaptcha/MailHide.php | 69 +- .../Service/ReCaptcha/MailHide/Exception.php | 12 +- lib/Zend/Service/ReCaptcha/Response.php | 6 +- lib/Zend/Service/Simpy.php | 14 +- lib/Zend/Service/Simpy/Link.php | 6 +- lib/Zend/Service/Simpy/LinkQuery.php | 6 +- lib/Zend/Service/Simpy/LinkSet.php | 6 +- lib/Zend/Service/Simpy/Note.php | 6 +- lib/Zend/Service/Simpy/NoteSet.php | 6 +- lib/Zend/Service/Simpy/Tag.php | 6 +- lib/Zend/Service/Simpy/TagSet.php | 6 +- lib/Zend/Service/Simpy/Watchlist.php | 6 +- lib/Zend/Service/Simpy/WatchlistFilter.php | 6 +- lib/Zend/Service/Simpy/WatchlistFilterSet.php | 6 +- lib/Zend/Service/Simpy/WatchlistSet.php | 6 +- lib/Zend/Service/SlideShare.php | 12 +- lib/Zend/Service/SlideShare/Exception.php | 6 +- lib/Zend/Service/SlideShare/SlideShow.php | 6 +- lib/Zend/Service/StrikeIron.php | 8 +- lib/Zend/Service/StrikeIron/Base.php | 8 +- lib/Zend/Service/StrikeIron/Decorator.php | 6 +- lib/Zend/Service/StrikeIron/Exception.php | 6 +- .../Service/StrikeIron/SalesUseTaxBasic.php | 6 +- .../StrikeIron/USAddressVerification.php | 6 +- lib/Zend/Service/StrikeIron/ZipCodeInfo.php | 6 +- lib/Zend/Service/Technorati.php | 2056 +-- lib/Zend/Service/Technorati/Author.php | 484 +- .../Service/Technorati/BlogInfoResult.php | 322 +- lib/Zend/Service/Technorati/CosmosResult.php | 304 +- .../Service/Technorati/CosmosResultSet.php | 352 +- .../Service/Technorati/DailyCountsResult.php | 6 +- .../Technorati/DailyCountsResultSet.php | 6 +- lib/Zend/Service/Technorati/Exception.php | 78 +- lib/Zend/Service/Technorati/GetInfoResult.php | 206 +- lib/Zend/Service/Technorati/KeyInfoResult.php | 236 +- lib/Zend/Service/Technorati/Result.php | 242 +- lib/Zend/Service/Technorati/ResultSet.php | 579 +- lib/Zend/Service/Technorati/SearchResult.php | 6 +- .../Service/Technorati/SearchResultSet.php | 6 +- lib/Zend/Service/Technorati/TagResult.php | 6 +- lib/Zend/Service/Technorati/TagResultSet.php | 6 +- lib/Zend/Service/Technorati/TagsResult.php | 186 +- lib/Zend/Service/Technorati/TagsResultSet.php | 6 +- lib/Zend/Service/Technorati/Utils.php | 272 +- lib/Zend/Service/Technorati/Weblog.php | 972 +- lib/Zend/Service/Twitter.php | 286 +- lib/Zend/Service/Twitter/Exception.php | 6 +- lib/Zend/Service/Twitter/Search.php | 29 +- .../Credentials/CredentialsAbstract.php | 244 + .../WindowsAzure/Credentials/Exception.php | 35 + .../Credentials/SharedAccessSignature.php | 307 + .../WindowsAzure/Credentials/SharedKey.php | 187 + .../Credentials/SharedKeyLite.php | 166 + .../Diagnostics/ConfigurationDataSources.php | 91 + ...figurationDiagnosticInfrastructureLogs.php | 67 + .../Diagnostics/ConfigurationDirectories.php | 90 + .../Diagnostics/ConfigurationInstance.php | 220 + .../Diagnostics/ConfigurationLogs.php | 67 + .../ConfigurationObjectBaseAbstract.php | 71 + .../ConfigurationPerformanceCounters.php | 89 + .../ConfigurationWindowsEventLog.php | 91 + .../DirectoryConfigurationSubscription.php | 62 + .../WindowsAzure/Diagnostics/Exception.php | 38 + .../WindowsAzure/Diagnostics/LogLevel.php | 39 + .../WindowsAzure/Diagnostics/Manager.php | 191 + .../PerformanceCounterSubscription.php | 59 + lib/Zend/Service/WindowsAzure/Exception.php | 35 + .../WindowsAzure/RetryPolicy/Exception.php | 36 + .../WindowsAzure/RetryPolicy/NoRetry.php | 58 + .../WindowsAzure/RetryPolicy/RetryN.php | 92 + .../RetryPolicy/RetryPolicyAbstract.php | 77 + .../Service/WindowsAzure/SessionHandler.php | 217 + lib/Zend/Service/WindowsAzure/Storage.php | 563 + .../Service/WindowsAzure/Storage/Batch.php | 248 + .../Storage/BatchStorageAbstract.php | 197 + .../Service/WindowsAzure/Storage/Blob.php | 2001 +++ .../WindowsAzure/Storage/Blob/Stream.php | 565 + .../WindowsAzure/Storage/BlobContainer.php | 99 + .../WindowsAzure/Storage/BlobInstance.php | 132 + .../Storage/DynamicTableEntity.php | 200 + .../WindowsAzure/Storage/LeaseInstance.php | 65 + .../Storage/PageRegionInstance.php | 59 + .../Service/WindowsAzure/Storage/Queue.php | 555 + .../WindowsAzure/Storage/QueueInstance.php | 61 + .../WindowsAzure/Storage/QueueMessage.php | 74 + .../WindowsAzure/Storage/SignedIdentifier.php | 65 + .../Storage/StorageEntityAbstract.php | 73 + .../Service/WindowsAzure/Storage/Table.php | 857 ++ .../WindowsAzure/Storage/TableEntity.php | 323 + .../WindowsAzure/Storage/TableEntityQuery.php | 350 + .../WindowsAzure/Storage/TableInstance.php | 65 + lib/Zend/Service/Yahoo.php | 12 +- lib/Zend/Service/Yahoo/Image.php | 6 +- lib/Zend/Service/Yahoo/ImageResult.php | 6 +- lib/Zend/Service/Yahoo/ImageResultSet.php | 6 +- lib/Zend/Service/Yahoo/InlinkDataResult.php | 6 +- .../Service/Yahoo/InlinkDataResultSet.php | 6 +- lib/Zend/Service/Yahoo/LocalResult.php | 6 +- lib/Zend/Service/Yahoo/LocalResultSet.php | 6 +- lib/Zend/Service/Yahoo/NewsResult.php | 6 +- lib/Zend/Service/Yahoo/NewsResultSet.php | 6 +- lib/Zend/Service/Yahoo/PageDataResult.php | 6 +- lib/Zend/Service/Yahoo/PageDataResultSet.php | 6 +- lib/Zend/Service/Yahoo/Result.php | 6 +- lib/Zend/Service/Yahoo/ResultSet.php | 6 +- lib/Zend/Service/Yahoo/VideoResult.php | 6 +- lib/Zend/Service/Yahoo/VideoResultSet.php | 6 +- lib/Zend/Service/Yahoo/WebResult.php | 6 +- lib/Zend/Service/Yahoo/WebResultSet.php | 6 +- lib/Zend/Session.php | 25 +- lib/Zend/Session/Abstract.php | 6 +- lib/Zend/Session/Exception.php | 6 +- lib/Zend/Session/Namespace.php | 11 +- lib/Zend/Session/SaveHandler/DbTable.php | 6 +- lib/Zend/Session/SaveHandler/Exception.php | 6 +- lib/Zend/Session/SaveHandler/Interface.php | 6 +- lib/Zend/Session/Validator/Abstract.php | 6 +- lib/Zend/Session/Validator/HttpUserAgent.php | 6 +- lib/Zend/Session/Validator/Interface.php | 6 +- lib/Zend/Soap/AutoDiscover.php | 43 +- lib/Zend/Soap/AutoDiscover/Exception.php | 7 +- lib/Zend/Soap/Client.php | 53 +- lib/Zend/Soap/Client/Common.php | 4 +- lib/Zend/Soap/Client/DotNet.php | 4 +- lib/Zend/Soap/Client/Exception.php | 6 +- lib/Zend/Soap/Client/Local.php | 4 +- lib/Zend/Soap/Server.php | 30 +- lib/Zend/Soap/Server/Exception.php | 6 +- lib/Zend/Soap/Wsdl.php | 11 +- lib/Zend/Soap/Wsdl/Exception.php | 16 +- lib/Zend/Soap/Wsdl/Strategy/Abstract.php | 9 +- lib/Zend/Soap/Wsdl/Strategy/AnyType.php | 16 +- .../Soap/Wsdl/Strategy/ArrayOfTypeComplex.php | 20 +- .../Wsdl/Strategy/ArrayOfTypeSequence.php | 16 +- lib/Zend/Soap/Wsdl/Strategy/Composite.php | 16 +- .../Soap/Wsdl/Strategy/DefaultComplexType.php | 16 +- lib/Zend/Soap/Wsdl/Strategy/Interface.php | 14 +- lib/Zend/Tag/Cloud.php | 6 +- lib/Zend/Tag/Cloud/Decorator/Cloud.php | 6 +- lib/Zend/Tag/Cloud/Decorator/Exception.php | 6 +- lib/Zend/Tag/Cloud/Decorator/HtmlCloud.php | 36 +- lib/Zend/Tag/Cloud/Decorator/HtmlTag.php | 40 +- lib/Zend/Tag/Cloud/Decorator/Tag.php | 6 +- lib/Zend/Tag/Cloud/Exception.php | 6 +- lib/Zend/Tag/Exception.php | 6 +- lib/Zend/Tag/Item.php | 6 +- lib/Zend/Tag/ItemList.php | 6 +- lib/Zend/Tag/Taggable.php | 6 +- lib/Zend/Test/DbAdapter.php | 28 +- lib/Zend/Test/DbStatement.php | 11 +- lib/Zend/Test/PHPUnit/Constraint/DomQuery.php | 16 +- .../Test/PHPUnit/Constraint/Exception.php | 10 +- lib/Zend/Test/PHPUnit/Constraint/Redirect.php | 12 +- .../PHPUnit/Constraint/ResponseHeader.php | 12 +- lib/Zend/Test/PHPUnit/ControllerTestCase.php | 33 +- lib/Zend/Test/PHPUnit/DatabaseTestCase.php | 6 +- lib/Zend/Test/PHPUnit/Db/Connection.php | 6 +- lib/Zend/Test/PHPUnit/Db/DataSet/DbRowset.php | 9 +- lib/Zend/Test/PHPUnit/Db/DataSet/DbTable.php | 10 +- .../PHPUnit/Db/DataSet/DbTableDataSet.php | 6 +- .../Test/PHPUnit/Db/DataSet/QueryDataSet.php | 14 +- .../Test/PHPUnit/Db/DataSet/QueryTable.php | 13 +- lib/Zend/Test/PHPUnit/Db/Exception.php | 7 +- lib/Zend/Test/PHPUnit/Db/Metadata/Generic.php | 9 +- .../Test/PHPUnit/Db/Operation/DeleteAll.php | 18 +- lib/Zend/Test/PHPUnit/Db/Operation/Insert.php | 18 +- .../Test/PHPUnit/Db/Operation/Truncate.php | 18 +- lib/Zend/Test/PHPUnit/Db/SimpleTester.php | 6 +- lib/Zend/Text/Exception.php | 6 +- lib/Zend/Text/Figlet.php | 6 +- lib/Zend/Text/Figlet/Exception.php | 6 +- lib/Zend/Text/Figlet/zend-framework.flf | 1506 +- lib/Zend/Text/MultiByte.php | 76 +- lib/Zend/Text/Table.php | 6 +- lib/Zend/Text/Table/Column.php | 6 +- lib/Zend/Text/Table/Decorator/Ascii.php | 6 +- lib/Zend/Text/Table/Decorator/Interface.php | 6 +- lib/Zend/Text/Table/Decorator/Unicode.php | 6 +- lib/Zend/Text/Table/Exception.php | 6 +- lib/Zend/Text/Table/Row.php | 6 +- lib/Zend/TimeSync.php | 6 +- lib/Zend/TimeSync/Exception.php | 6 +- lib/Zend/TimeSync/Ntp.php | 125 +- lib/Zend/TimeSync/Protocol.php | 6 +- lib/Zend/TimeSync/Sntp.php | 6 +- lib/Zend/Tool/Framework/Action/Base.php | 6 +- lib/Zend/Tool/Framework/Action/Exception.php | 6 +- lib/Zend/Tool/Framework/Action/Interface.php | 6 +- lib/Zend/Tool/Framework/Action/Repository.php | 9 +- lib/Zend/Tool/Framework/Client/Abstract.php | 66 +- lib/Zend/Tool/Framework/Client/Config.php | 161 +- lib/Zend/Tool/Framework/Client/Console.php | 103 +- .../Client/Console/ArgumentParser.php | 70 +- .../Framework/Client/Console/HelpSystem.php | 45 +- .../Framework/Client/Console/Manifest.php | 6 +- .../Console/ResponseDecorator/AlignCenter.php | 66 + .../Console/ResponseDecorator/Blockize.php | 69 + .../Console/ResponseDecorator/Colorizer.php | 6 +- .../Console/ResponseDecorator/Indention.php | 56 + lib/Zend/Tool/Framework/Client/Exception.php | 6 +- .../Client/Interactive/InputHandler.php | 6 +- .../Client/Interactive/InputInterface.php | 6 +- .../Client/Interactive/InputRequest.php | 6 +- .../Client/Interactive/InputResponse.php | 6 +- .../Client/Interactive/OutputInterface.php | 6 +- lib/Zend/Tool/Framework/Client/Manifest.php | 206 + lib/Zend/Tool/Framework/Client/Request.php | 6 +- lib/Zend/Tool/Framework/Client/Response.php | 10 +- .../Response/ContentDecorator/Interface.php | 6 +- .../Response/ContentDecorator/Separator.php | 6 +- lib/Zend/Tool/Framework/Client/Storage.php | 6 +- .../Client/Storage/AdapterInterface.php | 6 +- .../Framework/Client/Storage/Directory.php | 6 +- lib/Zend/Tool/Framework/Exception.php | 6 +- lib/Zend/Tool/Framework/Loader/Abstract.php | 24 +- .../Tool/Framework/Loader/BasicLoader.php | 157 + .../Framework/Loader/IncludePathLoader.php | 9 +- .../RecursiveFilterIterator.php | 6 +- lib/Zend/Tool/Framework/Loader/Interface.php | 42 + .../Framework/Manifest/ActionManifestable.php | 6 +- .../Tool/Framework/Manifest/Exception.php | 6 +- .../Tool/Framework/Manifest/Indexable.php | 6 +- .../Tool/Framework/Manifest/Interface.php | 6 +- .../Manifest/MetadataManifestable.php | 6 +- .../Manifest/ProviderManifestable.php | 6 +- .../Tool/Framework/Manifest/Repository.php | 21 +- .../Tool/Framework/Metadata/Attributable.php | 32 + lib/Zend/Tool/Framework/Metadata/Basic.php | 14 +- lib/Zend/Tool/Framework/Metadata/Dynamic.php | 81 +- .../Tool/Framework/Metadata/Interface.php | 8 +- lib/Zend/Tool/Framework/Metadata/Tool.php | 6 +- lib/Zend/Tool/Framework/Provider/Abstract.php | 6 +- .../Provider/DocblockManifestable.php | 6 +- .../Tool/Framework/Provider/Exception.php | 6 +- .../Tool/Framework/Provider/Interactable.php | 6 +- .../Tool/Framework/Provider/Interface.php | 6 +- .../Tool/Framework/Provider/Pretendable.php | 6 +- .../Tool/Framework/Provider/Repository.php | 6 +- .../Tool/Framework/Provider/Signature.php | 11 +- lib/Zend/Tool/Framework/Registry.php | 10 +- .../Framework/Registry/EnabledInterface.php | 6 +- .../Tool/Framework/Registry/Exception.php | 6 +- .../Tool/Framework/Registry/Interface.php | 8 +- .../Tool/Framework/System/Action/Create.php | 6 +- .../Tool/Framework/System/Action/Delete.php | 6 +- lib/Zend/Tool/Framework/System/Manifest.php | 8 +- .../Tool/Framework/System/Provider/Config.php | 311 + .../Framework/System/Provider/Manifest.php | 6 +- .../Framework/System/Provider/Phpinfo.php | 6 +- .../Framework/System/Provider/Version.php | 8 +- .../Tool/Project/Context/Content/Engine.php | 6 +- .../Context/Content/Engine/CodeGenerator.php | 6 +- .../Project/Context/Content/Engine/Phtml.php | 6 +- lib/Zend/Tool/Project/Context/Exception.php | 6 +- .../Project/Context/Filesystem/Abstract.php | 6 +- .../Project/Context/Filesystem/Directory.php | 18 +- .../Tool/Project/Context/Filesystem/File.php | 74 +- lib/Zend/Tool/Project/Context/Interface.php | 6 +- lib/Zend/Tool/Project/Context/Repository.php | 14 +- .../Tool/Project/Context/System/Interface.php | 6 +- .../Context/System/NotOverwritable.php | 6 +- .../Context/System/ProjectDirectory.php | 6 +- .../Context/System/ProjectProfileFile.php | 10 +- .../System/ProjectProvidersDirectory.php | 6 +- .../Context/System/TopLevelRestrictable.php | 6 +- .../Project/Context/Zf/AbstractClassFile.php | 78 + .../Tool/Project/Context/Zf/ActionMethod.php | 6 +- .../Tool/Project/Context/Zf/ApisDirectory.php | 6 +- .../Context/Zf/ApplicationConfigFile.php | 183 +- .../Context/Zf/ApplicationDirectory.php | 40 +- .../Tool/Project/Context/Zf/BootstrapFile.php | 68 +- .../Project/Context/Zf/CacheDirectory.php | 6 +- .../Tool/Project/Context/Zf/ConfigFile.php | 6 +- .../Project/Context/Zf/ConfigsDirectory.php | 6 +- .../Project/Context/Zf/ControllerFile.php | 83 +- .../Context/Zf/ControllersDirectory.php | 6 +- .../Tool/Project/Context/Zf/DataDirectory.php | 6 +- .../Project/Context/Zf/DbTableDirectory.php | 6 +- .../Tool/Project/Context/Zf/DbTableFile.php | 64 +- .../Tool/Project/Context/Zf/DocsDirectory.php | 61 + lib/Zend/Tool/Project/Context/Zf/FormFile.php | 74 +- .../Project/Context/Zf/FormsDirectory.php | 6 +- .../Tool/Project/Context/Zf/HtaccessFile.php | 7 +- .../Project/Context/Zf/LayoutScriptFile.php | 109 + .../Context/Zf/LayoutScriptsDirectory.php | 57 + .../Project/Context/Zf/LayoutsDirectory.php | 6 +- .../Project/Context/Zf/LibraryDirectory.php | 6 +- .../Project/Context/Zf/LocalesDirectory.php | 6 +- .../Tool/Project/Context/Zf/LogsDirectory.php | 6 +- .../Tool/Project/Context/Zf/ModelFile.php | 68 +- .../Project/Context/Zf/ModelsDirectory.php | 6 +- .../Project/Context/Zf/ModuleDirectory.php | 6 +- .../Project/Context/Zf/ModulesDirectory.php | 8 +- .../Context/Zf/ProjectProviderFile.php | 6 +- .../Project/Context/Zf/PublicDirectory.php | 6 +- .../Context/Zf/PublicImagesDirectory.php | 6 +- .../Project/Context/Zf/PublicIndexFile.php | 6 +- .../Context/Zf/PublicScriptsDirectory.php | 6 +- .../Context/Zf/PublicStylesheetsDirectory.php | 6 +- .../Context/Zf/SearchIndexesDirectory.php | 6 +- .../Project/Context/Zf/SessionsDirectory.php | 6 +- .../Project/Context/Zf/TemporaryDirectory.php | 6 +- .../Zf/TestApplicationBootstrapFile.php | 6 +- .../Zf/TestApplicationControllerDirectory.php | 6 +- .../Zf/TestApplicationControllerFile.php | 6 +- .../Context/Zf/TestApplicationDirectory.php | 6 +- .../Context/Zf/TestLibraryBootstrapFile.php | 6 +- .../Context/Zf/TestLibraryDirectory.php | 6 +- .../Project/Context/Zf/TestLibraryFile.php | 6 +- .../Zf/TestLibraryNamespaceDirectory.php | 6 +- .../Context/Zf/TestPHPUnitConfigFile.php | 6 +- .../Project/Context/Zf/TestsDirectory.php | 6 +- .../Project/Context/Zf/UploadsDirectory.php | 6 +- .../Zf/ViewControllerScriptsDirectory.php | 16 +- .../Context/Zf/ViewFiltersDirectory.php | 6 +- .../Context/Zf/ViewHelpersDirectory.php | 6 +- .../Project/Context/Zf/ViewScriptFile.php | 20 +- .../Context/Zf/ViewScriptsDirectory.php | 6 +- .../Project/Context/Zf/ViewsDirectory.php | 6 +- .../Context/Zf/ZfStandardLibraryDirectory.php | 12 +- lib/Zend/Tool/Project/Exception.php | 6 +- lib/Zend/Tool/Project/Profile.php | 13 +- lib/Zend/Tool/Project/Profile/Exception.php | 6 +- .../Project/Profile/FileParser/Interface.php | 6 +- .../Tool/Project/Profile/FileParser/Xml.php | 27 +- .../Profile/Iterator/ContextFilter.php | 18 +- .../Iterator/EnabledResourceFilter.php | 6 +- lib/Zend/Tool/Project/Profile/Resource.php | 6 +- .../Project/Profile/Resource/Container.php | 22 +- .../Profile/Resource/SearchConstraints.php | 6 +- lib/Zend/Tool/Project/Provider/Abstract.php | 9 +- lib/Zend/Tool/Project/Provider/Action.php | 74 +- .../Tool/Project/Provider/Application.php | 87 + lib/Zend/Tool/Project/Provider/Controller.php | 87 +- lib/Zend/Tool/Project/Provider/DbAdapter.php | 139 + lib/Zend/Tool/Project/Provider/DbTable.php | 220 + lib/Zend/Tool/Project/Provider/Exception.php | 6 +- lib/Zend/Tool/Project/Provider/Form.php | 128 +- lib/Zend/Tool/Project/Provider/Layout.php | 109 + lib/Zend/Tool/Project/Provider/Manifest.php | 77 +- lib/Zend/Tool/Project/Provider/Model.php | 142 +- lib/Zend/Tool/Project/Provider/Module.php | 13 +- lib/Zend/Tool/Project/Provider/Profile.php | 6 +- lib/Zend/Tool/Project/Provider/Project.php | 193 +- .../Tool/Project/Provider/ProjectProvider.php | 6 +- lib/Zend/Tool/Project/Provider/Test.php | 6 +- lib/Zend/Tool/Project/Provider/View.php | 10 +- lib/Zend/Translate.php | 107 +- lib/Zend/Translate/Adapter.php | 399 +- lib/Zend/Translate/Adapter/Array.php | 19 +- lib/Zend/Translate/Adapter/Csv.php | 35 +- lib/Zend/Translate/Adapter/Gettext.php | 23 +- lib/Zend/Translate/Adapter/Ini.php | 19 +- lib/Zend/Translate/Adapter/Qt.php | 21 +- lib/Zend/Translate/Adapter/Tbx.php | 20 +- lib/Zend/Translate/Adapter/Tmx.php | 104 +- lib/Zend/Translate/Adapter/Xliff.php | 61 +- lib/Zend/Translate/Adapter/XmlTm.php | 21 +- lib/Zend/Translate/Exception.php | 6 +- lib/Zend/Translate/Plural.php | 57 +- lib/Zend/Uri.php | 71 +- lib/Zend/Uri/Exception.php | 6 +- lib/Zend/Uri/Http.php | 49 +- lib/Zend/Validate.php | 82 +- lib/Zend/Validate/Abstract.php | 36 +- lib/Zend/Validate/Alnum.php | 28 +- lib/Zend/Validate/Alpha.php | 26 +- lib/Zend/Validate/Barcode.php | 193 +- lib/Zend/Validate/Barcode/AdapterAbstract.php | 315 + .../Validate/Barcode/AdapterInterface.php | 68 + lib/Zend/Validate/Barcode/Code25.php | 64 + .../Validate/Barcode/Code25interleaved.php | 64 + lib/Zend/Validate/Barcode/Code39.php | 100 + lib/Zend/Validate/Barcode/Code39ext.php | 58 + lib/Zend/Validate/Barcode/Code93.php | 120 + lib/Zend/Validate/Barcode/Code93ext.php | 58 + lib/Zend/Validate/Barcode/Ean12.php | 52 + lib/Zend/Validate/Barcode/Ean13.php | 88 +- lib/Zend/Validate/Barcode/Ean14.php | 52 + lib/Zend/Validate/Barcode/Ean18.php | 52 + lib/Zend/Validate/Barcode/Ean2.php | 58 + lib/Zend/Validate/Barcode/Ean5.php | 58 + lib/Zend/Validate/Barcode/Ean8.php | 69 + lib/Zend/Validate/Barcode/Gtin12.php | 52 + lib/Zend/Validate/Barcode/Gtin13.php | 52 + lib/Zend/Validate/Barcode/Gtin14.php | 52 + lib/Zend/Validate/Barcode/Identcode.php | 52 + lib/Zend/Validate/Barcode/Intelligentmail.php | 58 + lib/Zend/Validate/Barcode/Issn.php | 119 + lib/Zend/Validate/Barcode/Itf14.php | 52 + lib/Zend/Validate/Barcode/Leitcode.php | 52 + lib/Zend/Validate/Barcode/Planet.php | 52 + lib/Zend/Validate/Barcode/Postnet.php | 52 + lib/Zend/Validate/Barcode/Royalmail.php | 121 + lib/Zend/Validate/Barcode/Sscc.php | 52 + lib/Zend/Validate/Barcode/UpcA.php | 103 - lib/Zend/Validate/Barcode/Upca.php | 52 + lib/Zend/Validate/Barcode/Upce.php | 69 + lib/Zend/Validate/Between.php | 50 +- lib/Zend/Validate/Callback.php | 174 + lib/Zend/Validate/Ccnum.php | 15 +- lib/Zend/Validate/CreditCard.php | 317 + lib/Zend/Validate/Date.php | 53 +- lib/Zend/Validate/Db/Abstract.php | 194 +- lib/Zend/Validate/Db/NoRecordExists.php | 7 +- lib/Zend/Validate/Db/RecordExists.php | 8 +- lib/Zend/Validate/Digits.php | 14 +- lib/Zend/Validate/EmailAddress.php | 498 +- lib/Zend/Validate/Exception.php | 9 +- lib/Zend/Validate/File/Count.php | 33 +- lib/Zend/Validate/File/Crc32.php | 12 +- lib/Zend/Validate/File/ExcludeExtension.php | 10 +- lib/Zend/Validate/File/ExcludeMimeType.php | 8 +- lib/Zend/Validate/File/Exists.php | 8 +- lib/Zend/Validate/File/Extension.php | 12 +- lib/Zend/Validate/File/FilesSize.php | 25 +- lib/Zend/Validate/File/Hash.php | 14 +- lib/Zend/Validate/File/ImageSize.php | 10 +- lib/Zend/Validate/File/IsCompressed.php | 115 +- lib/Zend/Validate/File/IsImage.php | 143 +- lib/Zend/Validate/File/Md5.php | 14 +- lib/Zend/Validate/File/MimeType.php | 92 +- lib/Zend/Validate/File/NotExists.php | 8 +- lib/Zend/Validate/File/Sha1.php | 12 +- lib/Zend/Validate/File/Size.php | 13 +- lib/Zend/Validate/File/Upload.php | 27 +- lib/Zend/Validate/File/WordCount.php | 8 +- lib/Zend/Validate/Float.php | 58 +- lib/Zend/Validate/GreaterThan.php | 26 +- lib/Zend/Validate/Hex.php | 11 +- lib/Zend/Validate/Hostname.php | 202 +- lib/Zend/Validate/Hostname/Biz.php | 6 +- lib/Zend/Validate/Hostname/Cn.php | 6 +- lib/Zend/Validate/Hostname/Com.php | 6 +- lib/Zend/Validate/Hostname/Jp.php | 6 +- lib/Zend/Validate/Iban.php | 45 +- lib/Zend/Validate/Identical.php | 63 +- lib/Zend/Validate/InArray.php | 106 +- lib/Zend/Validate/Int.php | 38 +- lib/Zend/Validate/Interface.php | 23 +- lib/Zend/Validate/Ip.php | 139 +- lib/Zend/Validate/Isbn.php | 279 + lib/Zend/Validate/LessThan.php | 25 +- lib/Zend/Validate/NotEmpty.php | 234 +- lib/Zend/Validate/PostCode.php | 210 + lib/Zend/Validate/Regex.php | 45 +- lib/Zend/Validate/Sitemap/Changefreq.php | 18 +- lib/Zend/Validate/Sitemap/Lastmod.php | 27 +- lib/Zend/Validate/Sitemap/Loc.php | 24 +- lib/Zend/Validate/Sitemap/Priority.php | 25 +- lib/Zend/Validate/StringLength.php | 44 +- lib/Zend/Version.php | 8 +- lib/Zend/View.php | 6 +- lib/Zend/View/Abstract.php | 104 +- lib/Zend/View/Exception.php | 10 +- lib/Zend/View/Helper/Abstract.php | 6 +- lib/Zend/View/Helper/Action.php | 14 +- lib/Zend/View/Helper/BaseUrl.php | 6 +- lib/Zend/View/Helper/Currency.php | 119 + lib/Zend/View/Helper/Cycle.php | 6 +- lib/Zend/View/Helper/DeclareVars.php | 6 +- lib/Zend/View/Helper/Doctype.php | 22 +- lib/Zend/View/Helper/Fieldset.php | 6 +- lib/Zend/View/Helper/Form.php | 6 +- lib/Zend/View/Helper/FormButton.php | 8 +- lib/Zend/View/Helper/FormCheckbox.php | 12 +- lib/Zend/View/Helper/FormElement.php | 76 +- lib/Zend/View/Helper/FormErrors.php | 6 +- lib/Zend/View/Helper/FormFile.php | 6 +- lib/Zend/View/Helper/FormHidden.php | 6 +- lib/Zend/View/Helper/FormImage.php | 6 +- lib/Zend/View/Helper/FormLabel.php | 8 +- lib/Zend/View/Helper/FormMultiCheckbox.php | 6 +- lib/Zend/View/Helper/FormNote.php | 6 +- lib/Zend/View/Helper/FormPassword.php | 6 +- lib/Zend/View/Helper/FormRadio.php | 6 +- lib/Zend/View/Helper/FormReset.php | 6 +- lib/Zend/View/Helper/FormSelect.php | 6 +- lib/Zend/View/Helper/FormSubmit.php | 6 +- lib/Zend/View/Helper/FormText.php | 6 +- lib/Zend/View/Helper/FormTextarea.php | 6 +- lib/Zend/View/Helper/HeadLink.php | 30 +- lib/Zend/View/Helper/HeadMeta.php | 89 +- lib/Zend/View/Helper/HeadScript.php | 40 +- lib/Zend/View/Helper/HeadStyle.php | 38 +- lib/Zend/View/Helper/HeadTitle.php | 52 +- lib/Zend/View/Helper/HtmlElement.php | 6 +- lib/Zend/View/Helper/HtmlFlash.php | 6 +- lib/Zend/View/Helper/HtmlList.php | 10 +- lib/Zend/View/Helper/HtmlObject.php | 6 +- lib/Zend/View/Helper/HtmlPage.php | 6 +- lib/Zend/View/Helper/HtmlQuicktime.php | 6 +- lib/Zend/View/Helper/InlineScript.php | 6 +- lib/Zend/View/Helper/Interface.php | 6 +- lib/Zend/View/Helper/Json.php | 6 +- lib/Zend/View/Helper/Layout.php | 6 +- lib/Zend/View/Helper/Navigation.php | 10 +- .../View/Helper/Navigation/Breadcrumbs.php | 24 +- lib/Zend/View/Helper/Navigation/Helper.php | 6 +- .../View/Helper/Navigation/HelperAbstract.php | 20 +- lib/Zend/View/Helper/Navigation/Links.php | 14 +- lib/Zend/View/Helper/Navigation/Menu.php | 24 +- lib/Zend/View/Helper/Navigation/Sitemap.php | 27 +- lib/Zend/View/Helper/PaginationControl.php | 28 +- lib/Zend/View/Helper/Partial.php | 10 +- lib/Zend/View/Helper/Partial/Exception.php | 6 +- lib/Zend/View/Helper/PartialLoop.php | 10 +- lib/Zend/View/Helper/Placeholder.php | 6 +- .../View/Helper/Placeholder/Container.php | 6 +- .../Helper/Placeholder/Container/Abstract.php | 10 +- .../Placeholder/Container/Exception.php | 6 +- .../Placeholder/Container/Standalone.php | 19 +- lib/Zend/View/Helper/Placeholder/Registry.php | 10 +- .../Helper/Placeholder/Registry/Exception.php | 6 +- lib/Zend/View/Helper/RenderToPlaceholder.php | 6 +- lib/Zend/View/Helper/ServerUrl.php | 6 +- lib/Zend/View/Helper/Translate.php | 38 +- lib/Zend/View/Helper/Url.php | 6 +- lib/Zend/View/Interface.php | 8 +- lib/Zend/View/Stream.php | 6 +- lib/Zend/Wildfire/Channel/HttpHeaders.php | 23 +- lib/Zend/Wildfire/Channel/Interface.php | 6 +- lib/Zend/Wildfire/Exception.php | 6 +- lib/Zend/Wildfire/Plugin/FirePhp.php | 6 +- lib/Zend/Wildfire/Plugin/FirePhp/Message.php | 6 +- .../Wildfire/Plugin/FirePhp/TableMessage.php | 6 +- lib/Zend/Wildfire/Plugin/Interface.php | 6 +- lib/Zend/Wildfire/Protocol/JsonStream.php | 6 +- lib/Zend/XmlRpc/Client.php | 18 +- lib/Zend/XmlRpc/Client/Exception.php | 6 +- lib/Zend/XmlRpc/Client/FaultException.php | 6 +- lib/Zend/XmlRpc/Client/HttpException.php | 6 +- .../XmlRpc/Client/IntrospectException.php | 6 +- .../XmlRpc/Client/ServerIntrospection.php | 11 +- lib/Zend/XmlRpc/Client/ServerProxy.php | 6 +- lib/Zend/XmlRpc/Exception.php | 6 +- lib/Zend/XmlRpc/Fault.php | 29 +- lib/Zend/XmlRpc/Generator/DomDocument.php | 101 + .../XmlRpc/Generator/GeneratorAbstract.php | 150 + lib/Zend/XmlRpc/Generator/XmlWriter.php | 92 + lib/Zend/XmlRpc/Request.php | 33 +- lib/Zend/XmlRpc/Request/Http.php | 6 +- lib/Zend/XmlRpc/Request/Stdin.php | 6 +- lib/Zend/XmlRpc/Response.php | 35 +- lib/Zend/XmlRpc/Response/Http.php | 6 +- lib/Zend/XmlRpc/Server.php | 59 +- lib/Zend/XmlRpc/Server/Cache.php | 6 +- lib/Zend/XmlRpc/Server/Exception.php | 6 +- lib/Zend/XmlRpc/Server/Fault.php | 6 +- lib/Zend/XmlRpc/Server/System.php | 6 +- lib/Zend/XmlRpc/Value.php | 190 +- lib/Zend/XmlRpc/Value/Array.php | 37 +- lib/Zend/XmlRpc/Value/Base64.php | 33 +- lib/Zend/XmlRpc/Value/BigInteger.php | 4 +- lib/Zend/XmlRpc/Value/Boolean.php | 29 +- lib/Zend/XmlRpc/Value/Collection.php | 6 +- lib/Zend/XmlRpc/Value/DateTime.php | 40 +- lib/Zend/XmlRpc/Value/Double.php | 10 +- lib/Zend/XmlRpc/Value/Exception.php | 6 +- lib/Zend/XmlRpc/Value/Integer.php | 6 +- lib/Zend/XmlRpc/Value/Nil.php | 6 +- lib/Zend/XmlRpc/Value/Scalar.php | 30 +- lib/Zend/XmlRpc/Value/String.php | 14 +- lib/Zend/XmlRpc/Value/Struct.php | 44 +- lib/Zend/replace_recursive.php | 2 +- skin/adminhtml/default/default/boxes.css | 19 +- skin/adminhtml/default/default/reset.css | 2 +- skin/frontend/base/default/js/bundle.js | 6 +- skin/frontend/base/default/js/opcheckout.js | 1 + skin/frontend/default/blank/css/styles-ie.css | 4 +- skin/frontend/default/blank/css/styles.css | 30 +- .../default/blank/images/pager_arrow_left.gif | Bin 0 -> 155 bytes .../blank/images/pager_arrow_right.gif | Bin 0 -> 155 bytes skin/frontend/default/blue/css/styles-ie.css | 4 +- skin/frontend/default/blue/css/styles.css | 44 +- .../default/blue/images/pager_arrow_left.gif | Bin 0 -> 155 bytes .../default/blue/images/pager_arrow_right.gif | Bin 0 -> 155 bytes .../default/default/css/styles-ie.css | 4 +- skin/frontend/default/default/css/styles.css | 44 +- .../default/images/pager_arrow_left.gif | Bin 0 -> 155 bytes .../default/images/pager_arrow_right.gif | Bin 0 -> 155 bytes skin/frontend/default/iphone/css/clears.css | 71 - skin/frontend/default/iphone/css/iphone.css | 795 +- .../default/iphone/images/header-bg.gif | Bin 166 -> 144 bytes skin/frontend/default/iphone/images/logo.gif | Bin 2760 -> 2493 bytes skin/frontend/default/iphone/js/opcheckout.js | 1 + .../frontend/default/modern/css/styles-ie.css | 4 +- skin/frontend/default/modern/css/styles.css | 49 +- .../modern/images/pager_arrow_left.gif | Bin 0 -> 158 bytes .../modern/images/pager_arrow_right.gif | Bin 0 -> 158 bytes 4009 files changed, 371705 insertions(+), 279885 deletions(-) create mode 100644 app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes.php create mode 100644 app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes/Edit/Form.php create mode 100644 app/code/community/Find/Feed/Block/Adminhtml/List/Codes.php create mode 100644 app/code/community/Find/Feed/Block/Adminhtml/List/Codes/Grid.php create mode 100644 app/code/community/Find/Feed/Block/Adminhtml/List/Items.php create mode 100644 app/code/community/Find/Feed/Block/Adminhtml/List/Items/Grid.php create mode 100755 app/code/community/Find/Feed/Helper/Data.php create mode 100644 app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Frequency.php create mode 100644 app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Hours.php create mode 100644 app/code/community/Find/Feed/Model/Codes.php create mode 100755 app/code/community/Find/Feed/Model/Import.php rename app/{design/frontend/default/iphone/template/core/link.phtml => code/community/Find/Feed/Model/Mysql4/Codes.php} (52%) create mode 100644 app/code/community/Find/Feed/Model/Mysql4/Codes/Collection.php rename app/{design/frontend/default/iphone/template/page/template/container.phtml => code/community/Find/Feed/Model/Mysql4/Setup.php} (57%) mode change 100644 => 100755 create mode 100644 app/code/community/Find/Feed/Model/Observer.php create mode 100644 app/code/community/Find/Feed/controllers/Adminhtml/Codes/GridController.php create mode 100644 app/code/community/Find/Feed/controllers/Adminhtml/Items/GridController.php create mode 100644 app/code/community/Find/Feed/etc/adminhtml.xml create mode 100755 app/code/community/Find/Feed/etc/config.xml create mode 100755 app/code/community/Find/Feed/etc/system.xml create mode 100755 app/code/community/Find/Feed/sql/find_feed_setup/mysql4-install-0.0.1.php create mode 100644 app/code/community/Find/Feed/sql/find_feed_setup/mysql4-upgrade-0.0.1-0.0.2.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Catalog/Category/Helper/Pricestep.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Customer/Form/Element/Boolean.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Customer/Form/Element/File.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Customer/Form/Element/Image.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Newsletter/Queue/Preview.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Newsletter/Template/Preview/Form.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Notification/Security.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Sales/Order/Create/Form/Abstract.php create mode 100644 app/code/core/Mage/Adminhtml/Block/Shipping/Carrier/Tablerate/Grid.php create mode 100644 app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Address/Street.php create mode 100644 app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Address.php create mode 100644 app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Customer.php create mode 100644 app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image/Favicon.php create mode 100644 app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Secure.php create mode 100644 app/code/core/Mage/Adminhtml/Model/System/Config/Source/Price/Step.php create mode 100644 app/code/core/Mage/Adminhtml/Model/System/Config/Source/Web/Redirect.php create mode 100644 app/code/core/Mage/Bundle/sql/bundle_setup/mysql4-upgrade-0.1.12-0.1.13.php create mode 100644 app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Category/Flat.php create mode 100644 app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Product/Flat.php create mode 100644 app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.28-1.4.0.0.29.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.30-1.4.0.0.31.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.31-1.4.0.0.32.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.32-1.4.0.0.33.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.33-1.4.0.0.34.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.34-1.4.0.0.35.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.35-1.4.0.0.36.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.36-1.4.0.0.37.php create mode 100644 app/code/core/Mage/Catalog/sql/catalog_setup/mysql4-upgrade-1.4.0.0.37-1.4.0.0.38.php create mode 100644 app/code/core/Mage/CatalogInventory/Model/System/Config/Backend/Qtyincrements.php rename app/code/core/Mage/{GiftRegistry/Model/Mysql4/Gift/Collection.php => CatalogSearch/Model/Mysql4/Indexer/Fulltext.php} (55%) 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/etc/api.xml create mode 100644 app/code/core/Mage/Checkout/etc/wsdl.xml create mode 100644 app/code/core/Mage/Cms/Model/Mysql4/Page/Service.php create mode 100644 app/code/core/Mage/Core/Helper/Url/Rewrite.php create mode 100644 app/code/core/Mage/Core/Model/Template.php rename app/code/core/Mage/{Sales/Model/Mysql4/Recurring/Profile/Info.php => Core/sql/core_setup/mysql4-upgrade-0.8.26-0.8.27.php} (82%) create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Abstract.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Boolean.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Date.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/File.php rename app/code/core/Mage/{GiftRegistry/Model/Mysql4/Gift.php => Customer/Model/Attribute/Data/Hidden.php} (78%) create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Image.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Multiline.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Multiselect.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Postcode.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Select.php create mode 100644 app/code/core/Mage/Customer/Model/Attribute/Data/Text.php rename app/code/core/Mage/{GiftRegistry/Model/Gift.php => Customer/Model/Attribute/Data/Textarea.php} (75%) create mode 100644 app/code/core/Mage/Customer/Model/Entity/Form/Attribute.php create mode 100644 app/code/core/Mage/Customer/Model/Entity/Form/Attribute/Collection.php create mode 100644 app/code/core/Mage/Customer/Model/Form.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.11-1.4.0.0.12.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.7-1.4.0.0.8.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.8-1.4.0.0.9.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.10-1.4.0.0.11.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.12-1.4.0.0.13.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.7-1.4.0.0.8.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.8-1.4.0.0.9.php create mode 100644 app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.9-1.4.0.0.10.php create mode 100644 app/code/core/Mage/Directory/sql/directory_setup/mysql4-upgrade-0.8.10-0.8.11.php delete mode 100644 app/code/core/Mage/GiftRegistry/etc/config.xml create mode 100644 app/code/core/Mage/GoogleCheckout/Model/Mysql4/Notification.php create mode 100644 app/code/core/Mage/GoogleCheckout/Model/Notification.php create mode 100644 app/code/core/Mage/GoogleCheckout/sql/googlecheckout_setup/mysql4-upgrade-0.7.3-0.7.4.php create mode 100644 app/code/core/Mage/Newsletter/sql/newsletter_setup/mysql4-upgrade-0.8.2-0.8.3.php create mode 100644 app/code/core/Mage/Page/Block/Html/Welcome.php create mode 100644 app/code/core/Mage/Page/Block/Template/Links/Block.php delete mode 100644 app/code/core/Mage/Payment/Model/Billing/Agreement.php create mode 100644 app/code/core/Mage/Paypal/Model/Cart.php create mode 100644 app/code/core/Mage/ProductAlert/Block/Product/View.php create mode 100644 app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Recurring/Profile.php create mode 100644 app/code/core/Mage/Sales/Block/Order/Comments.php create mode 100644 app/code/core/Mage/Sales/Model/Mysql4/Order/Comment/Collection/Abstract.php create mode 100644 app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.15-1.4.0.16.php create mode 100644 app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.16-1.4.0.17.php create mode 100644 app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.17-1.4.0.18.php create mode 100644 app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.18-1.4.0.19.php create mode 100644 app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.19-1.4.0.20.php create mode 100644 app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.20-1.4.0.21.php create mode 100644 app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.4-1.4.0.0.5.php create mode 100644 app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.5-1.4.0.0.6.php rename app/design/{frontend/default/iphone/layout/poll.xml => adminhtml/default/default/layout/dataflow.xml} (50%) rename app/design/{frontend/default/iphone/layout/googleanalytics.xml => adminhtml/default/default/layout/search.xml} (76%) rename app/design/{frontend/default/iphone/template/catalog/product/view/options/wrapper/bottom.phtml => adminhtml/default/default/template/dashboard/graph/disabled.phtml} (78%) rename app/design/{frontend/default/iphone/template/catalog/category/page.phtml => adminhtml/default/default/template/newsletter/queue/preview.phtml} (66%) create mode 100644 app/design/adminhtml/default/default/template/newsletter/template/preview/iframeswitcher.phtml create mode 100644 app/design/adminhtml/default/default/template/newsletter/template/preview/store.phtml rename app/design/{frontend/default/iphone/template/catalog/product/view/description.phtml => adminhtml/default/default/template/notification/security.phtml} (72%) create mode 100644 app/design/adminhtml/default/default/template/system/convert/profile/process.phtml rename app/design/{frontend/default/iphone/layout/sendfriend.xml => adminhtml/default/find/layout/feed.xml} (57%) create mode 100644 app/design/adminhtml/default/find/template/head/window.phtml rename app/design/frontend/{default/iphone/template/catalog/product/view/type/virtual.phtml => base/default/template/catalog/product/view/type/default.phtml} (73%) rename app/design/frontend/{default/iphone/template/catalog/layer/filter.phtml => base/default/template/page/template/linksblock.phtml} (64%) rename app/design/frontend/{default/iphone/template/catalog/product/view/additional.phtml => base/default/template/productalert/product/view.phtml} (72%) rename app/design/frontend/{default/iphone/template/catalog/seo/sitemap.phtml => base/default/template/sales/order/comments.phtml} (62%) delete mode 100644 app/design/frontend/default/iphone/layout/bundle.xml delete mode 100644 app/design/frontend/default/iphone/layout/catalogsearch.xml delete mode 100644 app/design/frontend/default/iphone/layout/contacts.xml delete mode 100644 app/design/frontend/default/iphone/layout/directory.xml delete mode 100644 app/design/frontend/default/iphone/layout/downloadable.xml delete mode 100644 app/design/frontend/default/iphone/layout/giftmessage.xml delete mode 100644 app/design/frontend/default/iphone/layout/newsletter.xml delete mode 100644 app/design/frontend/default/iphone/layout/productalert.xml delete mode 100644 app/design/frontend/default/iphone/layout/reports.xml delete mode 100644 app/design/frontend/default/iphone/layout/rss.xml delete mode 100644 app/design/frontend/default/iphone/layout/sales.xml delete mode 100644 app/design/frontend/default/iphone/layout/shipping.xml delete mode 100644 app/design/frontend/default/iphone/layout/wishlist.xml delete mode 100644 app/design/frontend/default/iphone/template/catalog/category/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/layer/state.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/layer/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/navigation/left.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/navigation/top.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/compare/list.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/compare/sidebar.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/gallery.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/list.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/list/crosssell.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/list/related.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/list/toolbar/pager.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/list/upsell.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/new.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/price.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/send.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/addto.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/addtocart.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/attributes.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/bundle.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/media.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/options.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/options/js.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/options/type/date.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/options/type/file.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/options/type/select.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/options/type/text.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/options/wrapper.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/price.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/price_clone.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/tierprices.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/type/configurable.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/type/grouped.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/type/options/configurable.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/product/view/type/simple.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/seo/sitemap/container.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalog/seo/tree.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalogsearch/advanced/form.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalogsearch/advanced/result.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalogsearch/result.phtml delete mode 100644 app/design/frontend/default/iphone/template/catalogsearch/term.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/coupon.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/crosssell.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/noItems.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/render/default.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/render/simple.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/shipping.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/sidebar.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/cart/totals.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/address/select.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/addresses.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/billing.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/item/default.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/link.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/overview.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/shipping.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/state.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/multishipping/success.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/billing.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/link.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/login.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/payment.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/payment/methods.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/progress.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/review.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/review/info.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/review/item.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/review/totals.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/shipping.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/shipping_method.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/shipping_method/additional.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/onepage/shipping_method/available.phtml delete mode 100644 app/design/frontend/default/iphone/template/checkout/success.phtml delete mode 100644 app/design/frontend/default/iphone/template/cms/content.phtml delete mode 100644 app/design/frontend/default/iphone/template/cms/content_heading.phtml delete mode 100644 app/design/frontend/default/iphone/template/cms/default/home.phtml delete mode 100644 app/design/frontend/default/iphone/template/cms/default/no-route.phtml delete mode 100644 app/design/frontend/default/iphone/template/cms/meta.phtml delete mode 100644 app/design/frontend/default/iphone/template/contacts/form.phtml delete mode 100644 app/design/frontend/default/iphone/template/core/formkey.phtml delete mode 100644 app/design/frontend/default/iphone/template/core/messages.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/dashboard.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/dashboard/address.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/dashboard/hello.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/dashboard/info.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/dashboard/newsletter.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/dashboard/sidebar.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/link/back.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/account/navigation.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/address.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/address/book.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/address/edit.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/balance.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/dashboard.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/form/address.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/form/changepassword.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/form/edit.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/form/mini.login.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/form/mini.newsletter.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/form/newsletter.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/form/register.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/logout.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/order/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/orders.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/widget/dob.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/widget/gender.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/widget/name.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/widget/taxvat.phtml delete mode 100644 app/design/frontend/default/iphone/template/customer/wishlist.phtml delete mode 100644 app/design/frontend/default/iphone/template/giftmessage/form.phtml delete mode 100644 app/design/frontend/default/iphone/template/giftmessage/helper.phtml delete mode 100644 app/design/frontend/default/iphone/template/giftmessage/inline.phtml delete mode 100644 app/design/frontend/default/iphone/template/googlecheckout/link.phtml delete mode 100644 app/design/frontend/default/iphone/template/newsletter/subscribe.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/2columns-left.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/2columns-right.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/3columns.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/dashboard.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/html/breadcrumbs.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/html/notices.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/html/pager.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/html/top.links.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/html/wrapper.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/js/calendar.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/print.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/switch/flags.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/switch/languages.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/switch/stores.phtml delete mode 100644 app/design/frontend/default/iphone/template/page/template/links.phtml delete mode 100644 app/design/frontend/default/iphone/template/payment/form/cc.phtml delete mode 100644 app/design/frontend/default/iphone/template/payment/form/ccsave.phtml delete mode 100644 app/design/frontend/default/iphone/template/payment/form/checkmo.phtml delete mode 100644 app/design/frontend/default/iphone/template/payment/form/purchaseorder.phtml delete mode 100644 app/design/frontend/default/iphone/template/payment/info/checkmo.phtml delete mode 100644 app/design/frontend/default/iphone/template/payment/info/purchaseorder.phtml delete mode 100644 app/design/frontend/default/iphone/template/poll/active.phtml delete mode 100644 app/design/frontend/default/iphone/template/poll/result.phtml delete mode 100644 app/design/frontend/default/iphone/template/productalert/price.phtml delete mode 100644 app/design/frontend/default/iphone/template/productalert/stock.phtml delete mode 100644 app/design/frontend/default/iphone/template/rating/detailed.phtml delete mode 100644 app/design/frontend/default/iphone/template/rating/empty.phtml delete mode 100644 app/design/frontend/default/iphone/template/reports/home_product_compared.phtml delete mode 100644 app/design/frontend/default/iphone/template/reports/home_product_viewed.phtml delete mode 100644 app/design/frontend/default/iphone/template/reports/product_compared.phtml delete mode 100644 app/design/frontend/default/iphone/template/reports/product_viewed.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/customer/list.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/customer/recent.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/customer/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/form.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/helper/summary.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/helper/summary_short.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/list.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/product/detailed.phtml delete mode 100644 app/design/frontend/default/iphone/template/review/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/rss/list.phtml delete mode 100644 app/design/frontend/default/iphone/template/rss/nofeed.phtml delete mode 100644 app/design/frontend/default/iphone/template/rss/order/details.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/creditmemo.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/details.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/info.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/invoice.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/items.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/items/renderer/default.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/print.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/print/creditmemo.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/print/invoice.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/print/shipment.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/shipment.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/totals.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/trackinginfo.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/order/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/sales/reorder/sidebar.phtml delete mode 100644 app/design/frontend/default/iphone/template/sendfriend/send.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/cloud.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/customer/edit.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/customer/recent.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/customer/tags.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/customer/view.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/list.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/mytags.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/popular.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/product/result.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/result.phtml delete mode 100644 app/design/frontend/default/iphone/template/tag/search.phtml delete mode 100644 app/design/frontend/default/iphone/template/tax/checkout/discount.phtml delete mode 100644 app/design/frontend/default/iphone/template/tax/checkout/grandtotal.phtml delete mode 100644 app/design/frontend/default/iphone/template/tax/checkout/shipping.phtml delete mode 100644 app/design/frontend/default/iphone/template/tax/checkout/subtotal.phtml delete mode 100644 app/design/frontend/default/iphone/template/tax/checkout/tax.phtml delete mode 100644 app/design/frontend/default/iphone/template/tax/order/tax.phtml delete mode 100644 app/design/frontend/default/iphone/template/wishlist/email/items.phtml delete mode 100644 app/design/frontend/default/iphone/template/wishlist/email/rss.phtml delete mode 100644 app/design/frontend/default/iphone/template/wishlist/shared.phtml delete mode 100644 app/design/frontend/default/iphone/template/wishlist/sharing.phtml delete mode 100644 app/design/frontend/default/iphone/template/wishlist/sidebar.phtml rename app/{design/frontend/default/iphone/layout/core.xml => etc/modules/Find_Feed.xml} (81%) rename app/{design/frontend/default/iphone/template/catalog/product/view/options/type/default.phtml => etc/modules/Mage_Connect.xml} (77%) create mode 100644 app/locale/en_US/Find_Feed.csv create mode 100644 app/locale/en_US/Mage_Connect.csv create mode 100644 downloader/pearlib/pear.ini create mode 100644 downloader/pearlib/php/.channels/.alias/magento-community.txt create mode 100644 downloader/pearlib/php/.channels/.alias/magento-core.txt create mode 100644 downloader/pearlib/php/.channels/.alias/pear.txt create mode 100644 downloader/pearlib/php/.channels/.alias/pecl.txt create mode 100644 downloader/pearlib/php/.channels/__uri.reg create mode 100644 downloader/pearlib/php/.channels/connect.magentocommerce.com_community.reg create mode 100644 downloader/pearlib/php/.channels/connect.magentocommerce.com_core.reg create mode 100644 downloader/pearlib/php/.channels/pear.php.net.reg create mode 100644 downloader/pearlib/php/.channels/pecl.php.net.reg create mode 100644 downloader/pearlib/php/.depdb create mode 100644 downloader/pearlib/php/.depdblock create mode 100644 downloader/pearlib/php/.filemap create mode 100644 downloader/pearlib/php/.lock create mode 100644 downloader/pearlib/temp/channel.xml create mode 100644 js/prototype/windows/themes/magento/btn_bg.gif delete mode 100644 js/prototype/windows/themes/magento/button-close-focused.png create mode 100644 js/prototype/windows/themes/magento/content_bg.gif create mode 100644 js/prototype/windows/themes/magento/window_close.png create mode 100644 lib/Mage/Archive.php create mode 100644 lib/Mage/Archive/Abstract.php create mode 100644 lib/Mage/Archive/Bz.php create mode 100644 lib/Mage/Archive/Gz.php create mode 100644 lib/Mage/Archive/Interface.php create mode 100644 lib/Mage/Archive/Tar.php create mode 100644 lib/Mage/Autoload/Simple.php create mode 100644 lib/Mage/Connect/Channel/Generator.php rename app/design/frontend/default/iphone/template/checkout/links.phtml => lib/Mage/Connect/Channel/Parser.php (56%) create mode 100644 lib/Mage/Connect/Channel/VO.php create mode 100644 lib/Mage/Connect/Command.php create mode 100644 lib/Mage/Connect/Command/Channels.php create mode 100644 lib/Mage/Connect/Command/Channels_Header.php create mode 100644 lib/Mage/Connect/Command/Config.php create mode 100644 lib/Mage/Connect/Command/Config_Header.php create mode 100644 lib/Mage/Connect/Command/Install.php create mode 100644 lib/Mage/Connect/Command/Install_Header.php create mode 100644 lib/Mage/Connect/Command/Package.php create mode 100644 lib/Mage/Connect/Command/Package_Header.php create mode 100644 lib/Mage/Connect/Command/Registry.php create mode 100644 lib/Mage/Connect/Command/Registry_Header.php create mode 100644 lib/Mage/Connect/Command/Remote.php create mode 100644 lib/Mage/Connect/Command/Remote_Header.php create mode 100644 lib/Mage/Connect/Config.php create mode 100644 lib/Mage/Connect/Converter.php create mode 100644 lib/Mage/Connect/Frontend.php create mode 100644 lib/Mage/Connect/Frontend/CLI.php create mode 100644 lib/Mage/Connect/Ftp.php create mode 100644 lib/Mage/Connect/Loader.php create mode 100644 lib/Mage/Connect/Loader/Ftp.php create mode 100644 lib/Mage/Connect/Package.php create mode 100644 lib/Mage/Connect/Package/Extension.php create mode 100644 lib/Mage/Connect/Package/Hotfix.php create mode 100644 lib/Mage/Connect/Package/Maintainer.php create mode 100644 lib/Mage/Connect/Package/Reader.php create mode 100644 lib/Mage/Connect/Package/Target.php create mode 100644 lib/Mage/Connect/Package/VO.php create mode 100644 lib/Mage/Connect/Package/Writer.php create mode 100644 lib/Mage/Connect/Packager.php create mode 100644 lib/Mage/Connect/Repository.php create mode 100644 lib/Mage/Connect/Repository/Abstract.php create mode 100644 lib/Mage/Connect/Repository/Channel.php create mode 100644 lib/Mage/Connect/Repository/Channel/Abstract.php create mode 100644 lib/Mage/Connect/Repository/Channel/Commercial.php create mode 100644 lib/Mage/Connect/Repository/Channel/Community.php create mode 100644 lib/Mage/Connect/Repository/Channel/Core.php create mode 100644 lib/Mage/Connect/Repository/Local.php create mode 100644 lib/Mage/Connect/Rest.php create mode 100644 lib/Mage/Connect/Singleconfig.php create mode 100644 lib/Mage/Connect/Structures/Graph.php create mode 100644 lib/Mage/Connect/Structures/Node.php create mode 100644 lib/Mage/Connect/Validator.php create mode 100644 lib/Mage/DB/Exception.php create mode 100644 lib/Mage/DB/Mysqli.php create mode 100644 lib/Mage/Exception.php create mode 100644 lib/Mage/HTTP/Client.php create mode 100644 lib/Mage/HTTP/Client/Curl.php create mode 100644 lib/Mage/HTTP/Client/Socket.php create mode 100644 lib/Mage/HTTP/IClient.php create mode 100644 lib/Mage/System/Args.php create mode 100644 lib/Mage/System/Dirs.php create mode 100644 lib/Mage/Xml/Generator.php create mode 100644 lib/Mage/Xml/Parser.php create mode 100644 lib/Varien/Data/Form/Filter/Date.php create mode 100644 lib/Varien/Data/Form/Filter/Escapehtml.php create mode 100644 lib/Varien/Data/Form/Filter/Interface.php create mode 100644 lib/Varien/Data/Form/Filter/Striptags.php delete mode 100644 lib/Varien/Db/test.php create mode 100644 lib/Zend/Application/Resource/Cachemanager.php create mode 100644 lib/Zend/Application/Resource/Dojo.php create mode 100644 lib/Zend/Application/Resource/Log.php create mode 100644 lib/Zend/Application/Resource/Mail.php create mode 100644 lib/Zend/Application/Resource/Multidb.php create mode 100644 lib/Zend/Barcode.php create mode 100644 lib/Zend/Barcode/Exception.php create mode 100644 lib/Zend/Barcode/Object/Code25.php create mode 100644 lib/Zend/Barcode/Object/Code25interleaved.php create mode 100644 lib/Zend/Barcode/Object/Code39.php create mode 100644 lib/Zend/Barcode/Object/Ean13.php create mode 100644 lib/Zend/Barcode/Object/Ean2.php create mode 100644 lib/Zend/Barcode/Object/Ean5.php create mode 100644 lib/Zend/Barcode/Object/Ean8.php create mode 100644 lib/Zend/Barcode/Object/Error.php create mode 100644 lib/Zend/Barcode/Object/Exception.php create mode 100644 lib/Zend/Barcode/Object/Identcode.php create mode 100644 lib/Zend/Barcode/Object/Itf14.php create mode 100644 lib/Zend/Barcode/Object/Leitcode.php create mode 100644 lib/Zend/Barcode/Object/ObjectAbstract.php create mode 100644 lib/Zend/Barcode/Object/Planet.php create mode 100644 lib/Zend/Barcode/Object/Postnet.php create mode 100644 lib/Zend/Barcode/Object/Royalmail.php create mode 100644 lib/Zend/Barcode/Object/Upca.php create mode 100644 lib/Zend/Barcode/Object/Upce.php create mode 100644 lib/Zend/Barcode/Renderer/Exception.php create mode 100644 lib/Zend/Barcode/Renderer/Image.php create mode 100644 lib/Zend/Barcode/Renderer/Pdf.php create mode 100644 lib/Zend/Barcode/Renderer/RendererAbstract.php create mode 100644 lib/Zend/Cache/Backend/BlackHole.php create mode 100644 lib/Zend/Cache/Backend/Static.php create mode 100644 lib/Zend/Cache/Frontend/Capture.php create mode 100644 lib/Zend/Cache/Manager.php create mode 100644 lib/Zend/Config/Writer/FileAbstract.php create mode 100644 lib/Zend/Controller/Action/Helper/Cache.php create mode 100644 lib/Zend/Currency/CurrencyInterface.php create mode 100644 lib/Zend/Feed/Pubsubhubbub.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/CallbackAbstract.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/CallbackInterface.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/Exception.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/HttpResponse.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/Model/ModelAbstract.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/Model/Subscription.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/Model/SubscriptionInterface.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/Publisher.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/Subscriber.php create mode 100644 lib/Zend/Feed/Pubsubhubbub/Subscriber/Callback.php create mode 100644 lib/Zend/Feed/Reader/Collection.php create mode 100644 lib/Zend/Feed/Reader/Collection/Author.php create mode 100644 lib/Zend/Feed/Reader/Collection/Category.php create mode 100644 lib/Zend/Feed/Reader/Collection/CollectionAbstract.php create mode 100644 lib/Zend/Feed/Reader/Feed/Atom/Source.php create mode 100644 lib/Zend/Feed/Writer.php create mode 100644 lib/Zend/Feed/Writer/Deleted.php create mode 100644 lib/Zend/Feed/Writer/Entry.php create mode 100644 lib/Zend/Feed/Writer/Exception/InvalidMethodException.php create mode 100644 lib/Zend/Feed/Writer/Extension/Atom/Renderer/Feed.php create mode 100644 lib/Zend/Feed/Writer/Extension/Content/Renderer/Entry.php create mode 100644 lib/Zend/Feed/Writer/Extension/DublinCore/Renderer/Entry.php create mode 100644 lib/Zend/Feed/Writer/Extension/DublinCore/Renderer/Feed.php create mode 100644 lib/Zend/Feed/Writer/Extension/ITunes/Entry.php create mode 100644 lib/Zend/Feed/Writer/Extension/ITunes/Feed.php create mode 100644 lib/Zend/Feed/Writer/Extension/ITunes/Renderer/Entry.php create mode 100644 lib/Zend/Feed/Writer/Extension/ITunes/Renderer/Feed.php create mode 100644 lib/Zend/Feed/Writer/Extension/RendererAbstract.php create mode 100644 lib/Zend/Feed/Writer/Extension/RendererInterface.php create mode 100644 lib/Zend/Feed/Writer/Extension/Slash/Renderer/Entry.php create mode 100644 lib/Zend/Feed/Writer/Extension/Threading/Renderer/Entry.php create mode 100644 lib/Zend/Feed/Writer/Extension/WellFormedWeb/Renderer/Entry.php create mode 100644 lib/Zend/Feed/Writer/Feed.php create mode 100644 lib/Zend/Feed/Writer/Feed/FeedAbstract.php create mode 100644 lib/Zend/Feed/Writer/Renderer/Entry/Atom.php create mode 100644 lib/Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php create mode 100644 lib/Zend/Feed/Writer/Renderer/Entry/Rss.php create mode 100644 lib/Zend/Feed/Writer/Renderer/Feed/Atom.php create mode 100644 lib/Zend/Feed/Writer/Renderer/Feed/Atom/AtomAbstract.php create mode 100644 lib/Zend/Feed/Writer/Renderer/Feed/Atom/Source.php create mode 100644 lib/Zend/Feed/Writer/Renderer/Feed/Rss.php create mode 100644 lib/Zend/Feed/Writer/Renderer/RendererAbstract.php create mode 100644 lib/Zend/Feed/Writer/Renderer/RendererInterface.php create mode 100644 lib/Zend/Feed/Writer/Source.php create mode 100644 lib/Zend/Filter/Boolean.php create mode 100644 lib/Zend/Filter/Compress.php create mode 100644 lib/Zend/Filter/Compress/Bz2.php create mode 100644 lib/Zend/Filter/Compress/CompressAbstract.php create mode 100644 lib/Zend/Filter/Compress/CompressInterface.php create mode 100644 lib/Zend/Filter/Compress/Gz.php create mode 100644 lib/Zend/Filter/Compress/Lzf.php create mode 100644 lib/Zend/Filter/Compress/Rar.php create mode 100644 lib/Zend/Filter/Compress/Tar.php create mode 100644 lib/Zend/Filter/Compress/Zip.php create mode 100644 lib/Zend/Filter/Decompress.php create mode 100644 lib/Zend/Filter/Null.php create mode 100644 lib/Zend/Gdata/Gapps/Extension/Property.php create mode 100644 lib/Zend/Gdata/Gapps/GroupEntry.php create mode 100644 lib/Zend/Gdata/Gapps/GroupFeed.php create mode 100644 lib/Zend/Gdata/Gapps/GroupQuery.php create mode 100644 lib/Zend/Gdata/Gapps/MemberEntry.php create mode 100644 lib/Zend/Gdata/Gapps/MemberFeed.php create mode 100644 lib/Zend/Gdata/Gapps/MemberQuery.php create mode 100644 lib/Zend/Gdata/Gapps/OwnerEntry.php create mode 100644 lib/Zend/Gdata/Gapps/OwnerFeed.php create mode 100644 lib/Zend/Gdata/Gapps/OwnerQuery.php create mode 100755 lib/Zend/Http/Client/Adapter/Stream.php create mode 100755 lib/Zend/Http/Response/Stream.php create mode 100644 lib/Zend/Log/FactoryInterface.php create mode 100644 lib/Zend/Log/Filter/Abstract.php create mode 100644 lib/Zend/Log/Writer/ZendMonitor.php create mode 100644 lib/Zend/Markup.php create mode 100644 lib/Zend/Markup/Exception.php create mode 100644 lib/Zend/Markup/Parser/Bbcode.php create mode 100644 lib/Zend/Markup/Parser/Exception.php create mode 100644 lib/Zend/Markup/Parser/ParserInterface.php create mode 100644 lib/Zend/Markup/Parser/Textile.php create mode 100644 lib/Zend/Markup/Renderer/Exception.php create mode 100644 lib/Zend/Markup/Renderer/Html.php create mode 100644 lib/Zend/Markup/Renderer/Html/Code.php create mode 100644 lib/Zend/Markup/Renderer/Html/HtmlAbstract.php create mode 100644 lib/Zend/Markup/Renderer/Html/Img.php create mode 100644 lib/Zend/Markup/Renderer/Html/List.php create mode 100644 lib/Zend/Markup/Renderer/Html/Url.php create mode 100644 lib/Zend/Markup/Renderer/RendererAbstract.php create mode 100644 lib/Zend/Markup/Renderer/TokenConverterInterface.php create mode 100644 lib/Zend/Markup/Token.php create mode 100644 lib/Zend/Markup/TokenList.php create mode 100644 lib/Zend/Oauth.php create mode 100644 lib/Zend/Oauth/Client.php create mode 100644 lib/Zend/Oauth/Config.php create mode 100644 lib/Zend/Oauth/Config/ConfigInterface.php create mode 100644 lib/Zend/Oauth/Consumer.php create mode 100644 lib/Zend/Oauth/Exception.php create mode 100644 lib/Zend/Oauth/Http.php create mode 100644 lib/Zend/Oauth/Http/AccessToken.php create mode 100644 lib/Zend/Oauth/Http/RequestToken.php create mode 100644 lib/Zend/Oauth/Http/UserAuthorization.php create mode 100644 lib/Zend/Oauth/Http/Utility.php create mode 100644 lib/Zend/Oauth/Signature/Hmac.php create mode 100644 lib/Zend/Oauth/Signature/Plaintext.php create mode 100644 lib/Zend/Oauth/Signature/Rsa.php create mode 100644 lib/Zend/Oauth/Signature/SignatureAbstract.php create mode 100644 lib/Zend/Oauth/Token.php create mode 100644 lib/Zend/Oauth/Token/Access.php create mode 100644 lib/Zend/Oauth/Token/AuthorizedRequest.php create mode 100644 lib/Zend/Oauth/Token/Request.php create mode 100644 lib/Zend/Paginator/SerializableLimitIterator.php create mode 100644 lib/Zend/Pdf/Annotation/Markup.php create mode 100644 lib/Zend/Pdf/Filter/RunLength.php rename lib/Zend/Queue/Adapter/Db/{queue_sqlite.php => queue_sqlite.sql} (100%) create mode 100644 lib/Zend/Serializer.php create mode 100644 lib/Zend/Serializer/Adapter/AdapterAbstract.php create mode 100644 lib/Zend/Serializer/Adapter/AdapterInterface.php create mode 100644 lib/Zend/Serializer/Adapter/Amf0.php create mode 100644 lib/Zend/Serializer/Adapter/Amf3.php create mode 100644 lib/Zend/Serializer/Adapter/Igbinary.php create mode 100644 lib/Zend/Serializer/Adapter/Json.php create mode 100644 lib/Zend/Serializer/Adapter/PhpCode.php create mode 100644 lib/Zend/Serializer/Adapter/PhpSerialize.php create mode 100644 lib/Zend/Serializer/Adapter/PythonPickle.php create mode 100644 lib/Zend/Serializer/Adapter/Wddx.php create mode 100644 lib/Zend/Serializer/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/BaseUserService.php create mode 100644 lib/Zend/Service/DeveloperGarden/BaseUserService/AccountBalance.php create mode 100644 lib/Zend/Service/DeveloperGarden/Client/ClientAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/Client/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/Client/Soap.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall/ConferenceAccount.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall/ConferenceDetail.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall/ConferenceSchedule.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall/Participant.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall/ParticipantDetail.php create mode 100644 lib/Zend/Service/DeveloperGarden/ConferenceCall/ParticipantStatus.php create mode 100644 lib/Zend/Service/DeveloperGarden/Credential.php create mode 100644 lib/Zend/Service/DeveloperGarden/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/IpLocation.php create mode 100644 lib/Zend/Service/DeveloperGarden/IpLocation/IpAddress.php create mode 100644 lib/Zend/Service/DeveloperGarden/LocalSearch.php create mode 100644 lib/Zend/Service/DeveloperGarden/LocalSearch/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/LocalSearch/SearchParameters.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/BaseUserService/ChangeQuotaPool.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/BaseUserService/GetAccountBalance.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/BaseUserService/GetQuotaInformation.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/AddConferenceTemplateParticipantRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/CommitConferenceRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/CreateConferenceRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/CreateConferenceTemplateRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/GetConferenceListRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/GetConferenceStatusRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/GetConferenceTemplateListRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/GetConferenceTemplateParticipantRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/GetConferenceTemplateRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/GetParticipantStatusRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/GetRunningConferenceRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/NewParticipantRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/RemoveConferenceRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/RemoveConferenceTemplateParticipantRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/RemoveConferenceTemplateRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/RemoveParticipantRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/UpdateConferenceRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/UpdateConferenceTemplateParticipantRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/UpdateConferenceTemplateRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/ConferenceCall/UpdateParticipantRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/IpLocation/LocateIPRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/LocalSearch/LocalSearchRequest.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/RequestAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/SendSms/SendFlashSMS.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/SendSms/SendSMS.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/SendSms/SendSmsAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/SmsValidation/GetValidatedNumbers.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/SmsValidation/Invalidate.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/SmsValidation/SendValidationKeyword.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/SmsValidation/Validate.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/VoiceButler/CallStatus.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/VoiceButler/NewCall.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/VoiceButler/NewCallSequenced.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/VoiceButler/TearDownCall.php create mode 100644 lib/Zend/Service/DeveloperGarden/Request/VoiceButler/VoiceButlerAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/BaseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/BaseUserService/ChangeQuotaPoolResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/BaseUserService/GetAccountBalanceResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/BaseUserService/GetQuotaInformationResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/AddConferenceTemplateParticipantResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/AddConferenceTemplateParticipantResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/CCSResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/CommitConferenceResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/ConferenceCallAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/CreateConferenceResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/CreateConferenceResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/CreateConferenceTemplateResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/CreateConferenceTemplateResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceListResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceListResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceStatusResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceStatusResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceTemplateListResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceTemplateListResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceTemplateParticipantResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceTemplateParticipantResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceTemplateResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetConferenceTemplateResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetParticipantStatusResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetParticipantStatusResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetRunningConferenceResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/GetRunningConferenceResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/NewParticipantResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/NewParticipantResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/RemoveConferenceResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/RemoveConferenceTemplateParticipantResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/RemoveConferenceTemplateResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/RemoveParticipantResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/UpdateConferenceResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/UpdateConferenceTemplateParticipantResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/UpdateConferenceTemplateResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ConferenceCall/UpdateParticipantResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/IpLocation/CityType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/IpLocation/GeoCoordinatesType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/IpLocation/IPAddressLocationType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/IpLocation/LocateIPResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/IpLocation/LocateIPResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/IpLocation/RegionType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/LocalSearch/LocalSearchResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/LocalSearch/LocalSearchResponseType.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/ResponseAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SecurityTokenServer/Exception.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SecurityTokenServer/GetTokensResponse.php rename lib/Zend/{Ldap/Collection/Iterator => Service/DeveloperGarden/Response/SecurityTokenServer}/Interface.php (55%) create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SecurityTokenServer/SecurityTokenResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SendSms/SendFlashSMSResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SendSms/SendSMSResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SendSms/SendSmsAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SmsValidation/GetValidatedNumbersResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SmsValidation/InvalidateResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SmsValidation/SendValidationKeywordResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SmsValidation/ValidateResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/SmsValidation/ValidatedNumber.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/VoiceButler/CallStatus2Response.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/VoiceButler/CallStatusResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/VoiceButler/NewCallResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/VoiceButler/NewCallSequencedResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/VoiceButler/TearDownCallResponse.php create mode 100644 lib/Zend/Service/DeveloperGarden/Response/VoiceButler/VoiceButlerAbstract.php create mode 100644 lib/Zend/Service/DeveloperGarden/SecurityTokenServer.php create mode 100644 lib/Zend/Service/DeveloperGarden/SecurityTokenServer/Cache.php create mode 100644 lib/Zend/Service/DeveloperGarden/SendSms.php create mode 100644 lib/Zend/Service/DeveloperGarden/SmsValidation.php create mode 100644 lib/Zend/Service/DeveloperGarden/VoiceCall.php create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/IPLocation.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/IPLocation.xsd create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/ODGBaseUserService.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/ODGBaseUserService.xsd create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/SmsService.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/SmsValidationUserService.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/TokenService.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/VoiceButlerService.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/VoiceButlerService.xsd create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/ccsPort.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/ccsPort.xsd create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/localsearch.wsdl create mode 100644 lib/Zend/Service/DeveloperGarden/Wsdl/localsearch.xsd create mode 100644 lib/Zend/Service/LiveDocx.php create mode 100644 lib/Zend/Service/LiveDocx/Exception.php create mode 100644 lib/Zend/Service/LiveDocx/MailMerge.php create mode 100644 lib/Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php create mode 100644 lib/Zend/Service/WindowsAzure/Credentials/Exception.php create mode 100644 lib/Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php create mode 100644 lib/Zend/Service/WindowsAzure/Credentials/SharedKey.php create mode 100644 lib/Zend/Service/WindowsAzure/Credentials/SharedKeyLite.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDataSources.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDiagnosticInfrastructureLogs.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationDirectories.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationInstance.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationLogs.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationObjectBaseAbstract.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationPerformanceCounters.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/ConfigurationWindowsEventLog.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/DirectoryConfigurationSubscription.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/Exception.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/LogLevel.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/Manager.php create mode 100644 lib/Zend/Service/WindowsAzure/Diagnostics/PerformanceCounterSubscription.php create mode 100644 lib/Zend/Service/WindowsAzure/Exception.php create mode 100644 lib/Zend/Service/WindowsAzure/RetryPolicy/Exception.php create mode 100644 lib/Zend/Service/WindowsAzure/RetryPolicy/NoRetry.php create mode 100644 lib/Zend/Service/WindowsAzure/RetryPolicy/RetryN.php create mode 100644 lib/Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php create mode 100644 lib/Zend/Service/WindowsAzure/SessionHandler.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/Batch.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/BatchStorageAbstract.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/Blob.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/Blob/Stream.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/BlobContainer.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/BlobInstance.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/DynamicTableEntity.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/LeaseInstance.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/PageRegionInstance.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/Queue.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/QueueInstance.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/QueueMessage.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/SignedIdentifier.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/StorageEntityAbstract.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/Table.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/TableEntity.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/TableEntityQuery.php create mode 100644 lib/Zend/Service/WindowsAzure/Storage/TableInstance.php create mode 100644 lib/Zend/Tool/Framework/Client/Console/ResponseDecorator/AlignCenter.php create mode 100644 lib/Zend/Tool/Framework/Client/Console/ResponseDecorator/Blockize.php create mode 100644 lib/Zend/Tool/Framework/Client/Console/ResponseDecorator/Indention.php create mode 100644 lib/Zend/Tool/Framework/Client/Manifest.php create mode 100644 lib/Zend/Tool/Framework/Loader/BasicLoader.php create mode 100644 lib/Zend/Tool/Framework/Loader/Interface.php create mode 100644 lib/Zend/Tool/Framework/Metadata/Attributable.php create mode 100644 lib/Zend/Tool/Framework/System/Provider/Config.php create mode 100644 lib/Zend/Tool/Project/Context/Zf/AbstractClassFile.php create mode 100644 lib/Zend/Tool/Project/Context/Zf/DocsDirectory.php create mode 100644 lib/Zend/Tool/Project/Context/Zf/LayoutScriptFile.php create mode 100644 lib/Zend/Tool/Project/Context/Zf/LayoutScriptsDirectory.php create mode 100644 lib/Zend/Tool/Project/Provider/Application.php create mode 100644 lib/Zend/Tool/Project/Provider/DbAdapter.php create mode 100644 lib/Zend/Tool/Project/Provider/DbTable.php create mode 100644 lib/Zend/Tool/Project/Provider/Layout.php create mode 100644 lib/Zend/Validate/Barcode/AdapterAbstract.php create mode 100644 lib/Zend/Validate/Barcode/AdapterInterface.php create mode 100644 lib/Zend/Validate/Barcode/Code25.php create mode 100644 lib/Zend/Validate/Barcode/Code25interleaved.php create mode 100644 lib/Zend/Validate/Barcode/Code39.php create mode 100644 lib/Zend/Validate/Barcode/Code39ext.php create mode 100644 lib/Zend/Validate/Barcode/Code93.php create mode 100644 lib/Zend/Validate/Barcode/Code93ext.php create mode 100644 lib/Zend/Validate/Barcode/Ean12.php create mode 100644 lib/Zend/Validate/Barcode/Ean14.php create mode 100644 lib/Zend/Validate/Barcode/Ean18.php create mode 100644 lib/Zend/Validate/Barcode/Ean2.php create mode 100644 lib/Zend/Validate/Barcode/Ean5.php create mode 100644 lib/Zend/Validate/Barcode/Ean8.php create mode 100644 lib/Zend/Validate/Barcode/Gtin12.php create mode 100644 lib/Zend/Validate/Barcode/Gtin13.php create mode 100644 lib/Zend/Validate/Barcode/Gtin14.php create mode 100644 lib/Zend/Validate/Barcode/Identcode.php create mode 100644 lib/Zend/Validate/Barcode/Intelligentmail.php create mode 100644 lib/Zend/Validate/Barcode/Issn.php create mode 100644 lib/Zend/Validate/Barcode/Itf14.php create mode 100644 lib/Zend/Validate/Barcode/Leitcode.php create mode 100644 lib/Zend/Validate/Barcode/Planet.php create mode 100644 lib/Zend/Validate/Barcode/Postnet.php create mode 100644 lib/Zend/Validate/Barcode/Royalmail.php create mode 100644 lib/Zend/Validate/Barcode/Sscc.php delete mode 100644 lib/Zend/Validate/Barcode/UpcA.php create mode 100644 lib/Zend/Validate/Barcode/Upca.php create mode 100644 lib/Zend/Validate/Barcode/Upce.php create mode 100644 lib/Zend/Validate/Callback.php create mode 100644 lib/Zend/Validate/CreditCard.php create mode 100644 lib/Zend/Validate/Isbn.php create mode 100644 lib/Zend/Validate/PostCode.php create mode 100644 lib/Zend/View/Helper/Currency.php create mode 100644 lib/Zend/XmlRpc/Generator/DomDocument.php create mode 100644 lib/Zend/XmlRpc/Generator/GeneratorAbstract.php create mode 100644 lib/Zend/XmlRpc/Generator/XmlWriter.php create mode 100644 skin/frontend/default/blank/images/pager_arrow_left.gif create mode 100644 skin/frontend/default/blank/images/pager_arrow_right.gif create mode 100644 skin/frontend/default/blue/images/pager_arrow_left.gif create mode 100644 skin/frontend/default/blue/images/pager_arrow_right.gif create mode 100644 skin/frontend/default/default/images/pager_arrow_left.gif create mode 100644 skin/frontend/default/default/images/pager_arrow_right.gif delete mode 100644 skin/frontend/default/iphone/css/clears.css create mode 100644 skin/frontend/default/modern/images/pager_arrow_left.gif create mode 100644 skin/frontend/default/modern/images/pager_arrow_right.gif diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 2328d04de9..1e9d20981c 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,3 +1,1019 @@ +==== 1.4.2.0 ==== + +=== Major Highlights === +* Starting from this release we are including TheFind extension. +* New Magento Connect Manager excluded from this version. + +== Upgrade Notes == +* Those who installed Magento version 1.4.2.0-beta1 or 1.4.2.0-rc1 through Magento Connect should reinstall it manually, because this version contains old version of Magento Connect Manager + +== Improvements == +* Added "Switch/Maestro" card type support to centinel 3DS validator. Added comment about maestro and 3d-secure to paypal system config +* Added more flexible filters implementation in collections: +** Varien_Data_Collection::addFilter() registers filters as objects and implements getFilter() method to be able to detect/modify already existing filters +** Varien_Data_Collection_Db::_renderFilters(): +*** Added a hook _renderFiltersBefore() +*** Implemented 'public' filter type, which maps the provided filter field from public into internal view and passes the "value" as a condition through _getConditionSql() +** Added $this->_renderFilters() call to abstract EAV collection to accommodate the filters that may be set by addFilter() method +* Added ability to pass multiple recipient emails and names to Mage_Core_Model_Email_Template::send() +* Backordered Item Status for subitems in Orders +** Added correct message at order for all backordered items. At back-end all items shows as backordered if their quantity is below or equal to zero +** Fix of duplication backorder messages for composite product options with same backordered item - saving backorder messages per product id +* Magento Connect Manager +** checking cyclic dependency references and conflicts with local files +** implemented adding to MCM manually installed extension +** changed upgrade logic, previous version of package should be deleted before install new +** Implemented new download process and dependencies rules +** Added correct behavior during extension reinstall, so dependencies will not reinstall automatically +* Optimized rewrite selection from DB, added url rewrite and suffix validation at admin backend +* Added verification of access level for app/etc/local.xml. +** Now if server configuration has issue and this file accessible from browser admin user gets notification in backend. +* Upgraded Zend Framework to version 1.10.8 +* Added the Recurring Profiles tab in customer management +* Implemented cache for shipping rates and fixing issues with rounding +* Design packages and themes optimization/refactoring/improvements: +** minor improvements and fixes +** improved upgrade-ability of CE themes +* iPhone Theme Refactoring +* Added Widget settings sharing between widget types +* For Invoices, Shipment, Credit Memos added possibility to show admin comments at user frontend (checkboxes "Visible on Frontend" in admin interface) +** Added JS to enables/disable checkbox 'Append Comments' depending on checkbox 'Email Order Confirmation' +** Refactored invoice/shipment/refund comments collections models to one abstract Comment Collection Model +** Refactored Block Order Invoice/Shipment/Creditmemo comments to usage of common block and design - Block Order Comments +* A little more accurate profiler - important for very quick measurements +* Add Shopping Cart API +* Implementing payment refund notifications +* Added website price scope for bundle items +* Added support of pending transaction to payflow pro. Also fixed "denied payment review" message in payment +* Upgraded TinyMCE to v.3.3.7 +* Added to prototype validation by length min-length validation +* Added Varien.DateElement for front-end date form fields and re-implemented Varien.DOB +* Added functionality to disable dashboard charts in backend (System > Configuration > Admin > Dashboard) +* Added functionality to disable dashboard charts during installation +* Adminhtml W3C Validation improvements +* Added ability to use session save method from configuration +* Rendering customer attributes +* Added favicon manager under System > Configuration > Design > HTML Head + +== Changes == +* Refactored shipping rates calculation to keep process solid and do not try to recreate internal process of calculation, as it was +* Added caching of requests to shipping carriers, because otherwise we get too much duplicate requests during calculation of every shipping method +* Refactored "Special products" RSS feeed +* Shortened the names of all foreign keys longer than 49 characters +* Compilation scope for some EAV models which was causing blank page after enabling compilation +* Deleted Mage_Sales_Model_Recurring_Profile_Info, which was not on its place and added accidentally +* Category and product design settings inheritance logic +* Refactored one routine in Inventory Observer to remove code duplication +* Disabling product attribute usage in promo rules not affect existing promo rules +* Refactoring validation states for Centinel +** Added template method Mage_Centinel_Model_StateAbstract::isLookupSuccessful +* Add boolean type for catalog price rules and condition for category_ids +* Removed Maestro/Switch/Solo card from system. Added Maestro/Switch and Solo cards to Chronopay and Cybersource methods +* Mage_Adminhtml_Block_Sales_Order_Creditmemo block had dependence from 'canCapture' 'canCapturePartial'. It was changed to 'canRefund' 'canRefundPartialPerInvoice'. For set result of Mage_Adminhtml_Block_Sales_Items_Abstract::CanEditQty`s we can use setCanEditQty +* Added Maestro/Switch and Solo Dollars card types for paypal_direct payment method. Also removed Maestro/Solo/Switch card type for this method +* Removed "Shipping address" block on recurring profile view page if product is virtual. Also fixed virtual order detection +* Refactored PayPal cart line items and cart totals calculation to accommodate various discounts and tax settings +** added hidden discount and hidden shipping taxes to the calculation +** eliminated cart line items logic from the helper, moved it to the paypal/cart model +** simplified transferring of the totals and line items to PayPal API objects +* Refactored sales rule discount detection on "buy_x_get_y" rule type +* Added catalog_product table definition to product review collection +* Changed type of obscure input field to 'password', so this field is hidden even when user enters data in it +* Removed dependence to payment method on getting billing agreement method title. For now payment method title stored in billing agreement +* Removed invoice creation thought zero subtotal checkout with new order status "pending" +* Removed SID from url generation when Use SID on Frontend option is disabled +* Added customer session validation for loadCustomerQuote method +* Iphone clears.css has been deleted + +== Fixes == +* Fixed Default shipping address is passed to PayPal instead of the selected shipping address + * reverted cloning of shipping address and it's setting to quote. + * implemented method assignCustomerWithAddressChange() with setting billing and shipping addresses +* Fixed Added transferring of last four digits of credit card number to give possibility refund authorize transactions. +* Fixed Returning from paypal cancel existing order + * Canceling order in cancelAction() only if it was placed from current quote +* Fixed Taxes->Incorrect product price and tax value on the last chechout step +* Fixed Opening bestseller product (admin/dashboards) results in adding new product +** fixed case when dashboard shows report for non-existing product (i.e. deleted one) +* Fixed Bestsellers statistic bug +** removed NULL values from statistic tables and changed foreign keys to cascade deleting stats for deleted products +* Fixed Gift message displaying conditions not properly work on frontend and backend +* Fixed QTY of product is incorrectly showed in Customer's Current Activities - Shopping Cart and Customer's Shopping Cart. +* Fixed Gift message displaying conditions not properly work on frontend and backend - fixed missed bracked +* Fixed Magento Connect Manager -> No warning message +* Fixed Unable to upload community extention in Magento Connect Manager without Community Channel installed +* Fixed Bundle product price calculated not correctly +* Fixed Customer's email doesn't escalate to billing/shipping addresses +** added copying email field from quote address to order address +** added sending email to PayPal, when user's address doesn't contain email info +* Fixed Catalog-specific attribute options do not load when using through catalog/output helper +** method _getLoadDataFields at product attribute resource collection modified to select additional needed fields; +* Fixed saving attribute value in store view scope only +* Fixed Not searchable attributes are searched by Quick search. +* Fixed Customers won't appear in the search results on the customer grid in the admin +* Fixed Huge memory consumption on flat shipping rates import +** decrease to 5000 count of data wich inserts into DB in one iterate, to avoid exceed of 128M memory_limit +* Fixed Config fields "Disable output" doesn't implement inherited value +* Fixed Category created for some store view not displayed on frontend +** include_in_menu attribute was made as required to set default value when category created in specified store +* Fixed creating of "Shopping Cart Price Rule' +** setActualProductAttributes method was called with 'attribute_set_id' value in $attributes param. But it does not exist in 'eav/attribute' table. So we need to check it +* Fixed PayPal PE transaction_id detection: Overrided getPaypalTransactionId method in PE API - changed transaction id getting to process payflow accounts not assigned to paypal side +* Fixed Configurable Product Catalog Price Rule Issue: the main idea is to calculate price rule on configurable price separately from base price +* Fixed fatal error during import large file +* Fixed Shipping information is not displayed in backend after Google Checkout operations +* Fixed Field Mapping Issue during customer import +* Fixed CMS blocks grid inoperable with store filter in GWS-limited mode +* Fixed incorrect qty increment behaviour +** qty increment not decimal validate +** when adding product with qty increment to cart - redirect to product's page +** generate message about mismatch of qty increment when editing item qty at cart +* Fixed ups/usps and Guam +* Fidex issues with attaching product to multiple stores: refresh product index query update +* Fixed displaying of bundle product weight +* Fixed "Select a PayPal Solution" checkbox bug: Website Payments Pro and Website Payments Pro Payflow Edition consider each other status in their checkboxes control logic +* Fixed Invoice Comments Stripped When Quantities Updated +* Fixed XSS security issue on frontend +* Fixed Google Chekout: Discount for shipping amount doesn't apply +* Fixed XSS issue in address form +* Fixed Address in the customers address book cannot be deleted +* Fixed CatalogSearch_Fulltext not being renewed for configurable products when editing attached simple products +* Fixed Google Checkout: shipping method info is empty at order page in admin backend +* Fixed Google Checkout: with discounted shipping - discount is applied again +* Fixed Wrong timezone/DST in reports +* Fixed coupon_code attribute inconsistency in some upgrade paths (from 1.4.0.0 to 1.4.1.0) +* Fixed Created extension archive through Magento Connect include ".svn" directories +* Fixed version of downloader +* Fixed Magento Connect: User should has a possibility to choose version for extension upgrade +* Fixed Magento Connect: User shouldn't be able to download Magento into "0000 permissions" folders +* Fixed Magento Connect: JS validation is absent for "Authors" tab on package extensions page +* Fixed Magento Connect: Saving information on settings page +* Fixed Magento Connect: "Configuration" step - server validation is absent during installation +* Fixed Magento Connect: "Log in" page - Message or some information about required fields doesn't appeared +* Fixed Magento Connect: "Configuration" step - incorrect message appeared during installation +* Fixed wrong shipping price in case of sales rule with fixed cart discount and 1 item in cart +* Fixed the label for the configurable product attribute does not reflect correctly on the frontend +* Fixed sales rule with fixed discount for whole cart doesn't work +* Fixed "Slash for category or product urls causes error 404" +* Fixed Shared shopping cart on the stores with different domains +** check origin url in all store urls +** prevent to getting SID param from current query +* Fixed #18454: Import profiles do not reset websites values +* Fixed Issue with zero grand total express checkout for recurring products. +* Fixed "Allow Gift message" setting on the product page doesn't work in Front. +* Fixed "Duplicate" of bundle product leads to an error +* Fixed Catalog sitemap for categories shows inactive sub categories if flat catalog enabled +* Fixed Added support of all product attributes in conditions/actions of salesRules. +* Fixed Disabling product attribute usage in promo rules not affect existing promo rules +* Fixed "Cart Price Rule not working with Product Attributes" (boolean values not properly shown in rule conditions) +* Fixed Wrong amounts invoiced with FPT +* Fixed Wrong order status after refund and additional related issue on frontend during checkout +* Fixed Unable to delete uploaded sample for downloadable product +* Fixed Paypal Direct send wrong billing address to API +* Fixed Incorrect viewing of category settings after refreshing page +* Fixed Catalog price rule discount not working during backend order creation +* Fixed Double headers for session cookie set +* Fixed Custom design is not reset properly after shipment comment emails +* Fixed Tax report displays incorrect figures +* Fixed Removed invoice creation on "completed" IPN message with payment_entity = "auth" to prevent double capture creation on single transaction with IPR. +* Fixed Image browser in WYSIWYG editor doesn't fill mouse over/out fields +* Fixed Added rounding to "Refund Shipping" field on credit memo creation page. +* Fixed Added additional error messages to customer address validation on PHP side while creating. +* Fixed "No server side check for password length when customer edits his account information" +** Also added proper processing for password == '0', earlier it was considered as non-set password +* Fixed WYSIWYG editor breaks directives that are not in src attribute +* fixed directives decoding for a case when the secret key is present in URLs +* Fixed Duplicate of a product creates it with no SKU value and is saved +* Fixed Redundant catalog product attribute "category_ids" remains during upgrade from 1.3 to 1.4 +* Fixed Reports/Shopping cart/Products in carts optimization +* Fixed "If all Storeviews value set up - disabled --> Front end shows default storeview instead of 404 page" +* Fixed Added error on zero subtotal checkout with paypal express. Removed paypal express button on shopping cart with zero grand total. +* Fixed Field labels and field values are not aligned vertically on Sales Orders in Admin +* Fixed Spacing between field labels and field values is inappropriate on the Recurring Profiles tab in My Account section +* Fixed Not searchable attributes are searched by Quick search. +** Checking if attribute used in quick search before adding to fulltext field +* Fixed Mage_Customer_Model_Customer::getGroupId can't return zero value +* Fixed #23184: Huge memory consumption on flat shipping rates import +* Optimized and refactored Table Rate import +* Fixed Scrolling during category load results in some js-errors +* Fixed "Javascript alert on "manage category" page" +* Fixed Security Vulnerability on Mage_Core_Block_Template level +* Fixed Merged CSS breaks Secure Pages (https) +* Fixed SOAP webservices do not work when enabling "Add Store Code to URLs" +* Fixed Incorrect displaying of the Start Date entered by customer while adding to the cart recurring product +* Fixed Downloadable Product "lable" typo +* Fixed While creating gift message from backend it disappears in case of refreshing page +* Fixed Product export fails when the quantity of exported products is 25 000 or more (memory leak in products) +* Fixed While creating gift message from backend it disappears in case of refreshing page +* Fixed Google Chekout: Discount for shipping amount doesn't apply +** onepage checkout recalculates shipping charges after setting the payment method (not solved yet in multishipping) +** added warning about Carrier Calculated Shipping in Google Checkout system configuration +** GC API callback now sets the payment method to quote on requests +** the free shipping calculator now marks the entire address as "free shipping" if all its items have free shipping +* Fixed On wide monitors checkbox "Create Permanent redirect" in admin backend wraps up to the end of input box +* Fixed Tag isn't showed in Product Page and My account->My Tags, if tag are deleted by customer, approved by administrator, added by customer +* Fixed Non standard images make troubles with "Next"/"Previous" buttons +* Fixed There is no validation of the Tracking number field during first time creation of the shipment +* Fixed Missed dollar sign in variable name +* Fixed Incorrect escaping of Mage_Catalog_Model_Abstract::loadByAttribute method +** Zend_DB_Select::where must get null values to skip quoting into $cond empty strings if value is null +* Fixed "URL rewrites duplicating when assigning to root category" +* Fixed Shipping method UPS_XML missing titles +* Fixed The pager is missing for tagged product list +* Fixed Report > Products Ordered ignores Store view switcher +* Fixed Flat catalog index problem after upgrade with customizations present +* Fixed Incorrect bundle items inventory decrements +* Fixed Category and product design settings inheritance +* Fixed Removed fatal error on removing non existent quote item from quote +* Fixed Credit Card Maestro/Solo: The field "Start Date" is not displayed on order information page +** deleted unused Maestro/Solo from Payment module config +** moved Maestro/Switch and Solo card definition from Chronopay to Payment module config +** deleted Meastro/Switch definition with incorrect code MS from Cybersource module config +** fixed logic of showing "Issue number" and "Start Date" of Switch/Solo card on frontend +* Added warning about offline refund +* Fixed Mage_Checkout_Block_Cart_Item_Renderer::getIsInStock bug +* Fixed Fatal on edit configurable product page, if custom required price attribute is used +* Fixed #0011135: View invoice error with changed query string +* Fixed Trailing semi-colon displayed on Profile Export page +* Fixed New Orders & Other Authenticated RSS feeds should use HTTPS +* Fixed Dataflow export products sku filter works as not "starts with", but "like" +* Fixed Removed default shipping address assign on paypal express checkout +* Fixed The customers from Puerto Rico can't pay with PayPal (Express Checkout in PaypalUk) +* Fixed Shared shopping cart on the stores with different domains +* Fixed Discount amount for the whole cart divide proportionally between all affected items according to their base price and then applied. +* Fixed Removed store selector in single store mode on url rewrite edit page +* Fixed Javascript validator's translation strings missing +* Fixed Quick Search Autocomplete does not work via ajax http protocol for https page +* Fixed Inventory->Qty Increments - unable to add +* Fixed Loading search query performance issue +* Fixed Changed labels in checkout and payment information blocs for credit cards Solo Maestro Switch +* Fixed Product q-ty doesnt decrease after google checkout +** added same 'checkout_submit_all_after' event to AmazonPayments +** removed 'TODO' notice from Multishipping Checkout, because current scheme is better and will not be influenced by any Multishipping refactoring +** fixed Observer reaction on 'checkout_submit_all_after' to include needed reindexing +* Added checkout_multishipping_controller_success_action and checkout_onepage_controller_success_action events that pass the created order ids on frontend checkout success actions +* Fixed Google Analytics tracking pages with wrong URI: +** Completely reimplemented googleanalytics/ga block: +*** it doesn't depend on session/quote, but just uses order_ids, if passed +*** the page_name parameter is reimplemented as it was intended to be: an optional parameter that can be customized via layout for certain actions +*** moved out the integration part with google checkout to observer +*** eCommerce tracking passes shipping address instead of the billing address, if available +*** replaced the "affiliation" into store frontend name in eCommerce tracking (as it is intended to be) +*** eliminated passing order item "category" in eCommerce tracking (that never existed) +*** optimized javascript code of GA with Google Checkout integration +** Eliminated mutual code coupling between Google Analytics and Google Checkout modules +** Improved integration of Google Analytics and Google Checkout: +*** the GA integration should appear only when GC buttons are available +*** there will be no integration when there is no GA tracking code configured +*** the GA/GC integration seems like wasn't working because there was no pageTracker js variable accessible to the GC scripts +* Fixed Wrong links in backend to "New Products/Low Stock/Customer reviews" RSS feeds +* Fixed "Send auto-generated password" generates e-mail with incorrect template +* Fixed Unable to refund Credit Memo because of Shipping Rounding +* Fixed Added custom option info to recurring profile info page on frontend and backend. +* Fixed Product Visibility and Status disappear when in search +* Fixed Removed validation of new customer shipping address on backend for orders with virtual products only +* Fixed ability to buy Product which have status "Out of Stock" through a direct link on button "Checkout with PayPal" +* Fixed All free shipping methods in absent in Transfer Shipping Options menu on PayPal side +* Fixed Payment methods titles for the PDF prints through admin gets from default config instead of the storeview config +* Fixed PayPal and Puerto Rico shipping address +* Fixed "Transfer Shipping Options" pass on PayPal side not correct value for Flat Rate method +* Fixed Centinel JCB validation test cases 8-9 +* Fixed Saving caterory in store view scope +* Fixed Attribute upgrades moved from 1.4.0.0.15 to 1.4.0.0.33 +* Fixed that product tagged by administrator has wrong URL at front-end +* Fixed refusal from Card Verification (through link Exit), does not allow to place order repeatedly +** If lookup was filed and customer tries again we will do new lookup. +** If lookup was success and customer tries again without some changes we will not do new lookup +** If authentication was filed and customer tries again we will do new lookup and authentication +** If authentication was success and customer tries again without some changes we will not do new lookup and authentication +* Fixed #22536: Light-weight email templates. Wishlist share email fix +* Fixed declaration of Mage_Cybersource_Model_Api_ExtendedSoapClient::__doRequest() compatibility with SoapClient::__doRequest() +* Fixed Two registration emails from a wrong store and without a logo are sent when a customer is created in Admin panel +* Fixed Reindex for bundle products with date fields +* Fixed Status is "Ready" instead to be "Reindex required" then creating new subcategory in mode "Manual Update" +** index status changed to STATUS_REQUIRE_REINDEX when search engine changes +* Fixed #23321: Wrong type casting in method +* Fixed Print-All Includes Tracking # from All Shipments on Every Shipment +* Fixed Ignored 'Include in Navigation Menu' category option with enabled flat catalog. +* Fixed Admin unable to add Image through WYSIWYG to description and Short description without intermediate product saving +* Fixed QTY decrement after multishipping +* Double clicking adds product to cart twice +* Fixed Catalog Price Rule(for NOT LOGGEN IN customers) is not applied for shopping cart and while checkout as guest or while first registration. +* Fixed Payment methods titles for the PDF prints through admin gets from default config instead of the storeview config +* Fixed Mage_Adminhtml_Model_System_Config_Backend_Serialized::_afterLoad() does not check input for unserialize() +* Fixed Sending letters through "Contact Us" form, leads to error +* Fixed PayPal Express with Flat Rate: incorrect counting Shipping amounts per order +* Fixed Saving attribute value in store view scope only causes data loss. +* Fixed #22607: Dispose of Mage_GiftRegistry module +* Fixed Related products are not saved when you attach them to a product +* Fixed Added qty to bundle unit price calculation to quote totals recalculating. +* Fixed Saving category cause: 'Exception' with message 'File was not uploaded.' in /home/vadim.kusakin/dev/qa/2759/lib/Varien/File/Uploader.php:139 +* Fixed Fixed MAGE-638 Magento Connect -> MCM -> If agreement checkbox is unchecked, "Continue" button should be disabled +* Fixed Set the same column font size as in cells in PDF documents printing +* Fixed Home page appears instead of predefined 404 page +* Fixed Removed converting of "is one of" and "is not one of" values in decimal. +* Fixed Wrong column type for order_increment_id on Invoice, Shipments, Creditmemo grids +** order_increment_id was setted as "text" instead of "number" type +* Fixed Inconsistency with credit memos showing buttons online vs offline +* Fixed PayPal Express shortcut is missed on product page +* Fixed An email is sent to a customer after its profile is edited in the Admin panel +* Fixed that Payflow Pro includes only the first line of billing/shipping addresses into request +* Fixed Incorrect showing of product page when inputing a product description with table which have attribute align = left +* Fixed Wrong link for bestsellers in admin dashboard. Grids.php fixture doesn't do anything for this bug - just to beautify code. +* Fixed Added fixes to reports - base_discount_amount is actually kept negative in DB. +* Fixed Empty dropdown 'status' at the creation New Review Grid. +* Fixed Incorrect work of "Recently Compared Products" functional on category's page +* Fixed behavior when having single store, javascript raises exception and all followed code is not executed +* Fixed that Special price for dynamic bundle applies twice +* Fixed #21960: Labels in page/html_wrapper and core/text_list in layout +* Fixed GUI bugs on Recurrent Profile frontend part +* Fixed Magento Connect -> Message about invalid URL is duplicated +* Fixed that suspend Recurring Profile from front side leads to error +* Fixed Missing pager for tagged product list +* Fixed Wrong profiler output for getUrl in Category +* Fixed Saving of billing agreement relation with order - added force billing agreement re-saving and fixed isValid method in agreement detection. +* Fixed Incorrect sort order reliable on mysql internal order during eav attribute load +** move prepare select to separate method +* Fixed passing additional totals to PayPal when cart line items are disabled: +** simplified paypal/abstract api to just set the paypal/cart instance and the needed configuration settings +** moved workarounds of setting shipping and discount totals as line items into the appropriate APIs: WPS and NVP +* Fixed In My product Review short description HTML tags are shown +* Fixed that Refund from google chekout don't display on the order in Magento +* Fixed that "Compare Products" block does not appear on the category page and product page +* Fixed Non-existing attribute's source model causes fatal error +* Fixed Varien_Db_Select memory leak +* Fixed #18569: Gift Messages not in OrderInfo returned array +* Fixed PayPal API credentials wizard popup size +* Fixed #11449: customer_id is mismatch with entity_id in customer.create +* Fixed merging CSS-files with different skin domain to pick a proper base URL +* Fixed Bad UI style on checkout success page +* Fixed buying more than 1 virtual product in multishipping checkout +* Fixed #22518: Wrong amount for second refund +* Fixed #22776: Bug Causing Recursion Error +* Fixed #22668: Incorrect reports for coupons +* Fixed Products -> Product with "Out of stock" status displayed on frontend, but shouldn't +* Fixed Password miss match for newly created in Back end customer +* Fixed "There has been an error processing your request" page is displayed when specified order status is selected on Reports->Sales->Tax page +* Fixed bug with 'Use Flat Catalog Category' +* Fixed #13770, #16300, #21040 : Product Media Api Broken, product_media.create API overwrites image itself each upload, product_media.update API does not upgrade the image itself +* Fixed #16306: Webservice with htaccess (changes in code style) +* Fixed #22536: Light-weight email templates +* Fixed #18935: Soap api v2 multiple complexFilters with the same key +* Fixed incorrect Window titles on frontend +* Fixed Eliminated display currency usage (instead of the base website currency) in shopping cart price rule conditions +* Fixed #21146: Magento falls into the white screen when saving URL rewrite for a product on the Default Store View +** corrected syntax mistakes +* Fixed batch of issues related to google checkout: +** Invoice don't create automatically with Google Checkout +** Google checkout invoice duplication +** Automatically authorize the buyer's credit card for the full amount of the order +** Refund from google checkout don't display on the order in Magento +** Google Chekout: Discount for shipping amount doesn't apply +** Different order amount in Google checkout and Magento orders +** Applying of discount for shipping, when using google checkout +** Order is in google sandbox doesn't contain gift card +* Fixed #23461: Wrong attribute value in catalog link widget XML +* Fixed getting complete state for orders with zero grand total when processed +* Added Store id param to billing agreement entity. Also fixed store setting in billing agreement payment method. +* Fixed fatal error in payment method list fetching (MAGE-500) +* Fixed #22575: Trace error during using filter "Products" on Tags page +* Fixed Grids with settings remain active while disabled PayPal methods +* Fixed configuration merger fatal error when store/website resource structure is inconsistent +* Fixed PayPal admin setup: checkbox problem +* Fixed Adding shipping address transferring on non guest checkout in Paypal Standard +* Fixed "Save in address book" checkbox in the Shipping address area doesn't work while admin order creation +* Fixed pre-selecting default address during checkout +* Fixed Email with empty password is sent to a customer after an order is created in the Admin panel +* Fixed Necessary to add data validation for filed "Trial Billing Frequency" in Recurring Profile +* Fixed "Out of Stock" product is possible to purchase successfully through Shortcut button +* Fixed phpdocs in lib/Varien and removed junk file +* Fixed #21146: Magento falls into the white screen when saving URL rewrite for a product on the Default Store View +* Fixed #21643: Fixed "wsdl" parameter validation for Soap V2 +** Changed class SoapServer with class Zend_Soap_server +** Added ability to set response charset from admin panel: System->Configuration->Magento Core API +* Fixed #21499: Default billing and shipping address +* Fixed #21565: missing "comment" for salesOrderStatusHistoryEntity +* Fixed #20481: Access Control List not retrieved for API user for resources() and resourceFaults() operations +* Fixed #18367: FCGI Error on WSDL Url with Apache and mod_fastcgi +* Fixed #22053: use HTTP 301 code instead of 302 in case of web/url/redirect_to_base +* Fixed #20654: Admin order creation->Move mouse cursor isn't changed into hand while move it on some product for adding +* Fixed #21590: Attribute 'Date': testing for uniqueness fields not working +* Fixed #21566: Type of attribute 'Price': Possible to add text value for field 'default value' +* Fixed #22053: added optional behavior (301 or 302) +* Fixed #21570: Review from not logged in user is saved in list of All Reviews when "Allow guests to write reviews = No" +* Fixed #22090: Different values of Qty Increments during create and after duplicate products +* Fixed #22489: Eliminate difference between bundle.js in different skins +* Fixed #22419: Set default stock_data if not exist in create/update product +* Fixed #20227: "Review(x)" link should be added to the compare page. +* Fixed #21570: Review from not logged in user is saved in list of All Reviews when "Allow guests to write reviews = No" +* Fixed #20959: Locale problem in shipping tracking popup raises exception +* Fixed #21955: Layout cache ignores product column count update +* Fixed #20011: After using filter "Color" or "Manufacture" in Configurable Product meaning from column is disappear +* Fixed #21908: Incorrect attribute ordering in "Compare products" page. +* Fixed #22222: Edit review-> if browse stores in the "Visible In " drop-down, rating values reseted +* Fixed #22075: Product Attribute title specified for StoreView isn't showing on the configurable product's page +* Fixed #22605: catalog_category.level return root categories when website or store are null +* Fixed #21806: Different values display on the shopping cart in front-end and back-end +* Fixed #20113: Shipping address display as default on the front-end and as not default on admin for one customer +* Fixed #22575: Trace error during using filter "Products" on Tags page +** added 'filter_index' to array parameter in addColumn() method call +* Fixed #14591: Incorrect SKU for Configurable Product with Custom Options +* Fixed #22476: Blank Column in Related Products Grid +** deleted duplicate output for editable columns +* Fixed #22575: Trace error during using filter "Products" on Tags page +** apply filter_index field values to index +* Fixed #22644: A discrepancy between GT(Base) and GT(Purchased) +* Fixed #22645: Incorrect original price when using custom price in order. +* Fixed #22653: Missed checking for file existence in JS/CSS merger +** checking in source file exists. If not - do not check last modification and force to merge target file again +* Fixed #22594: Unable to place orders through checkout with multiple addresses with PayPal direct + zero subtotal for one order +* Fixed #21185: Newsletter confirmed automatically BEFORE account email is confirmed. +* Fixed #22167: "Add new row" button in downloadable product +* Fixed #21952: BUG - Category / Url Model (UYN-886991) +* Fixed #15334, #17794 +** API category did not pass validation process due to available_sort_by must be ArrayOfString +** Added category validation for backend (missed) +** Creating separate validation for available_sort_by and default_sort_by attributes +* Fixed #22599 Upgrade from 1.1.8 to 1.8.0.0 database compatibility issues (PARTIAL) +* Fixed #22661: 1 cent bug +* Fixed #22434: 100% discount of products -> the amounts of Tax and Grand Totals are or negative or not corectly +* Fixed #10073: Unnecessary option for downloadable products +* Fixed #20014: Qty use decimals for downloadable +* Fixed #22164: Incorrect message for maximum shipping amount +* Fixed #22174: Custom 'Qty to Refund' isn't remembered after message about incorrect amount +* Fixed #22182: The value of 'Customer Since' field to duplicate clients at different sites. +* Fixed #22243: Add new review by admin->type of this review is 'guest', but should be 'administrator' +* Fixed #22313: Time of order creation if not displayed by the "Order Created At (datetime)" template variable. +* Fixed #22348: "Add to card" button is absent for giftcard product in the catalog +* Fixed #22640: Creating customer unable after adress tab manipulations +* Fixed #22670: Credit memo - incorrect shipping price displaying +* Fixed #22798: Excl and Inc. Tax don't display on the Estimate Shipping and Tax block +* Fixed #20088: Admin able to push on-line refund button for the capture off-line invoice +* Fixed #16306: Webservice with htaccess. Added server authorization (.htaccess) +* Fixed #22266: HEADERS ALREADY SENT Error during dataflow import +** Additionally: moveing layout update in separate layout file of dataflow module. +* Fixed #21412: The "Save Attribute" and "Save and Continue Edit" buttons become disabled after saving attribute with attribute code that exists +* Fixed #22844: After login to admin got 404 instead Startup Page +* Fixed #22852: shopping cart price rule - search by ID - error page +* Fixed #15897: Unsubscription Email Sender in the Newsletters Subscription Options is not working correctly +* Fixed #15899: Newsletters subscription confirmation in not working +* Fixed #22908: Grid Serializer doesn't handle dropdowns as edit columns +* Fixed #22946: 'Products Tagged by Administrators' grid contains information about product that is assigned by the customer +* Fixed #22935: Issue with Google AdWords and DSMM Code +* Fixed #22910: view of system/design table with no records under IE 8 +* Fixed #22914: view of URL rewrite table with no records under IE 8 +* Fixed #22935: Issue with Google AdWords and DSMM Code +* Fixed #22536: Light-weight email templates +* Fixed #23017: Memcache session fallback does not work +* Fixed #22992: Trace appears during create reorder from front-end +* Fixed #22991: Cannot add items to shopping cart after active 'Use Flat Catalog Product' +* Fixed #22813: Google base Undefined Offset when Managing attribute mapping +* Fixed #23138: URL rewrite error on product creation +* Added Regions for baltic states and Finland +* Fixed #23092: Memcached and compiler +* Fixed #19804: sorting/searching by "inventory" field +* Fixed #23241: Catalog price rule not correctly appy for customer group +* Fixed #16294: WSDL missing attributes for customerCustomerEntity +* Fixed #22851: Used wrong resource model for api/user +* Fixed #18207: SOAP-ERROR: Parsing Schema: can't import schema from 'http://schemas.xmlsoap.org/soap/encoding/' +* Fixed Fatal error: Call to undefined function eaccelerator_fetch() + + +==== 1.4.x-devel-83018 ==== + +== Fixes == +* Fixed Opening bestseller product (admin/dashboards) results in adding new product +** fixed case when dashboard shows report for non-existing product (i.e. deleted one) +* Fixed Bestsellers statistic bug +** removed NULL values from statistic tables and changed foreign keys to cascade deleting stats for deleted products +* Fixed Gift message displaying conditions not properly work on frontend and backend +* Fixed QTY of product is incorrectly showed in Customer's Current Activities - Shopping Cart and Customer's Shopping Cart. +* Fixed Gift message displaying conditions not properly work on frontend and backend - fixed missed bracked +* Fixed Magento Connect Manager -> No warning message +* Fixed Unable to upload community extention in Magento Connect Manager without Community Channel installed +* Fixed Bundle product price calculated not correctly +* Fixed Customer's email doesn't escalate to billing/shipping addresses +** added copying email field from quote address to order address +** added sending email to PayPal, when user's address doesn't contain email info + +==== 1.4.x-devel-82478 ==== + +== Improvements == +* Added "Switch/Maestro" card type support to centinel 3DS validator. Added comment about maestro and 3d-secure to paypal system config +* Added more flexible filters implementation in collections: +** Varien_Data_Collection::addFilter() registers filters as objects and implements getFilter() method to be able to detect/modify already existing filters +** Varien_Data_Collection_Db::_renderFilters(): +*** Added a hook _renderFiltersBefore() +*** Implemented 'public' filter type, which maps the provided filter field from public into internal view and passes the "value" as a condition through _getConditionSql() +** Added $this->_renderFilters() call to abstract EAV collection to accommodate the filters that may be set by addFilter() method +* Added ability to pass multiple recipient emails and names to Mage_Core_Model_Email_Template::send() + +== Changes == +* Refactored shipping rates calculation to keep process solid and do not try to recreate internal process of calculation, as it was +* Added caching of requests to shipping carriers, because otherwise we get too much duplicate requests during calculation of every shipping method +* Refactored "Special products" RSS feeed + +== Fixes == +* Fixed Catalog-specific attribute options do not load when using through catalog/output helper +** method _getLoadDataFields at product attribute resource collection modified to select additional needed fields; +* Fixed saving attribute value in store view scope only +* Fixed Not searchable attributes are searched by Quick search. +* Fixed Customers won't appear in the search results on the customer grid in the admin +* Fixed Huge memory consumption on flat shipping rates import +** decrease to 5000 count of data wich inserts into DB in one iterate, to avoid exceed of 128M memory_limit +* Fixed Config fields "Disable output" doesn't implement inherited value +* Fixed Category created for some store view not displayed on frontend +** include_in_menu attribute was made as required to set default value when category created in specified store +* Fixed creating of "Shopping Cart Price Rule' +** setActualProductAttributes method was called with 'attribute_set_id' value in $attributes param. But it does not exist in 'eav/attribute' table. So we need to check it +* Fixed PayPal PE transaction_id detection: Overrided getPaypalTransactionId method in PE API - changed transaction id getting to process payflow accounts not assigned to paypal side +* Fixed Configurable Product Catalog Price Rule Issue: the main idea is to calculate price rule on configurable price separately from base price +* Fixed fatal error during import large file +* Fixed Shipping information is not displayed in backend after Google Checkout operations +* Fixed Field Mapping Issue during customer import +* Fixed CMS blocks grid inoperable with store filter in GWS-limited mode +* Fixed incorrect qty increment behaviour +** qty increment not decimal validate +** when adding product with qty increment to cart - redirect to product's page +** generate message about mismatch of qty increment when editing item qty at cart +* Fixed ups/usps and Guam +* Fidex issues with attaching product to multiple stores: refresh product index query update +* Fixed displaying of bundle product weight +* Fixed "Select a PayPal Solution" checkbox bug: Website Payments Pro and Website Payments Pro Payflow Edition consider each other status in their checkboxes control logic +* Fixed Invoice Comments Stripped When Quantities Updated +* Fixed XSS security issue on frontend + +==== 1.4.x-devel-81496 ==== + +== Improvements == +* Backordered Item Status for subitems in Orders +** Added correct message at order for all backordered items. At back-end all items shows as backordered if their quantity is below or equal to zero +** Fix of duplication backorder messages for composite product options with same backordered item - saving backorder messages per product id +* Magento Connect Manager +** checking cyclic dependency references and conflicts with local files +** implemented adding to MCM manually installed extension +** changed upgrade logic, previous version of package should be deleted before install new +** Implemented new download process and dependencies rules +** Added correct behavior during extension reinstall, so dependencies will not reinstall automatically + +== Changes == +* Shortened the names of all foreign keys longer than 49 characters + +== Fixes == +* Fixed Google Chekout: Discount for shipping amount doesn't apply +* Fixed XSS issue in address form +* Fixed Address in the customers address book cannot be deleted +* Fixed CatalogSearch_Fulltext not being renewed for configurable products when editing attached simple products +* Fixed Google Checkout: shipping method info is empty at order page in admin backend +* Fixed Google Checkout: with discounted shipping - discount is applied again +* Fixed Wrong timezone/DST in reports +* Fixed coupon_code attribute inconsistency in some upgrade paths (from 1.4.0.0 to 1.4.1.0) +* Fixed Created extension archive through Magento Connect include ".svn" directories +* Fixed version of downloader +* Fixed Magento Connect: User should has a possibility to choose version for extension upgrade +* Fixed Magento Connect: User shouldn't be able to download Magento into "0000 permissions" folders +* Fixed Magento Connect: JS validation is absent for "Authors" tab on package extensions page +* Fixed Magento Connect: Saving information on settings page +* Fixed Magento Connect: "Configuration" step - server validation is absent during installation +* Fixed Magento Connect: "Log in" page - Message or some information about required fields doesn't appeared +* Fixed Magento Connect: "Configuration" step - incorrect message appeared during installation +* Fixed wrong shipping price in case of sales rule with fixed cart discount and 1 item in cart +* Fixed the label for the configurable product attribute does not reflect correctly on the frontend +* Fixed sales rule with fixed discount for whole cart doesn't work + +==== 1.4.x-devel-80991 ==== + +== Improvements == +* Optimized rewrite selection from DB, added url rewrite and suffix validation at admin backend +* Added verification of access level for app/etc/local.xml. +** Now if server configuration has issue and this file accessible from browser admin user gets notification in backend. + +== Changes == +* Compilation scope for some EAV models which was causing blank page after enabling compilation + +== Fixes == +* Fixed "Slash for category or product urls causes error 404" +* Fixed Shared shopping cart on the stores with different domains +** check origin url in all store urls +** prevent to getting SID param from current query +* Fixed #18454: Import profiles do not reset websites values +* Fixed Issue with zero grand total express checkout for recurring products. +* Fixed "Allow Gift message" setting on the product page doesn't work in Front. +* Fixed "Duplicate" of bundle product leads to an error +* Fixed Catalog sitemap for categories shows inactive sub categories if flat catalog enabled +* Fixed Added support of all product attributes in conditions/actions of salesRules. +* Fixed Disabling product attribute usage in promo rules not affect existing promo rules +* Fixed "Cart Price Rule not working with Product Attributes" (boolean values not properly shown in rule conditions) +* Fixed Wrong amounts invoiced with FPT +* Fixed Wrong order status after refund and additional related issue on frontend during checkout +* Fixed Unable to delete uploaded sample for downloadable product +* Fixed Paypal Direct send wrong billing address to API +* Fixed Incorrect viewing of category settings after refreshing page +* Fixed Catalog price rule discount not working during backend order creation +* Fixed Double headers for session cookie set + +==== 1.4.x-devel-80262 ==== + +== Improvements == +* Upgraded Zend Framework to version 1.10.8 +* Added the Recurring Profiles tab in customer management + +== Changes == +* Deleted Mage_Sales_Model_Recurring_Profile_Info, which was not on its place and added accidentally +* Category and product design settings inheritance logic + +== Fixes == +* Fixed Custom design is not reset properly after shipment comment emails +* Fixed Tax report displays incorrect figures +* Fixed Removed invoice creation on "completed" IPN message with payment_entity = "auth" to prevent double capture creation on single transaction with IPR. +* Fixed Image browser in WYSIWYG editor doesn't fill mouse over/out fields +* Fixed Added rounding to "Refund Shipping" field on credit memo creation page. +* Fixed Added additional error messages to customer address validation on PHP side while creating. +* Fixed "No server side check for password length when customer edits his account information" +** Also added proper processing for password == '0', earlier it was considered as non-set password +* Fixed WYSIWYG editor breaks directives that are not in src attribute +* fixed directives decoding for a case when the secret key is present in URLs +* Fixed Duplicate of a product creates it with no SKU value and is saved +* Fixed Redundant catalog product attribute "category_ids" remains during upgrade from 1.3 to 1.4 +* Fixed Reports/Shopping cart/Products in carts optimization +* Fixed "If all Storeviews value set up - disabled --> Front end shows default storeview instead of 404 page" +* Fixed Added error on zero subtotal checkout with paypal express. Removed paypal express button on shopping cart with zero grand total. +* Fixed Field labels and field values are not aligned vertically on Sales Orders in Admin +* Fixed Spacing between field labels and field values is inappropriate on the Recurring Profiles tab in My Account section +* Fixed Not searchable attributes are searched by Quick search. +** Checking if attribute used in quick search before adding to fulltext field +* Fixed Mage_Customer_Model_Customer::getGroupId can't return zero value +* Fixed #23184: Huge memory consumption on flat shipping rates import +* Optimized and refactored Table Rate import +* Fixed Scrolling during category load results in some js-errors +* Fixed "Javascript alert on "manage category" page" +* Fixed Security Vulnerability on Mage_Core_Block_Template level +* Fixed Merged CSS breaks Secure Pages (https) + +==== 1.4.x-devel-79607 ==== + +== Improvements == +* Implemented cache for shipping rates and fixing issues with rounding + +== Changes == +* Refactored one routine in Inventory Observer to remove code duplication +* Disabling product attribute usage in promo rules not affect existing promo rules + +== Fixes == +* Fixed SOAP webservices do not work when enabling "Add Store Code to URLs" +* Fixed Incorrect displaying of the Start Date entered by customer while adding to the cart recurring product +* Fixed Downloadable Product "lable" typo +* Fixed While creating gift message from backend it disappears in case of refreshing page +* Fixed Product export fails when the quantity of exported products is 25 000 or more (memory leak in products) +* Fixed While creating gift message from backend it disappears in case of refreshing page +* Fixed Google Chekout: Discount for shipping amount doesn't apply +** onepage checkout recalculates shipping charges after setting the payment method (not solved yet in multishipping) +** added warning about Carrier Calculated Shipping in Google Checkout system configuration +** GC API callback now sets the payment method to quote on requests +** the free shipping calculator now marks the entire address as "free shipping" if all its items have free shipping +* Fixed On wide monitors checkbox "Create Permanent redirect" in admin backend wraps up to the end of input box +* Fixed Tag isn't showed in Product Page and My account->My Tags, if tag are deleted by customer, approved by administrator, added by customer +* Fixed Non standard images make troubles with "Next"/"Previous" buttons +* Fixed There is no validation of the Tracking number field during first time creation of the shipment +* Fixed Missed dollar sign in variable name +* Fixed Incorrect escaping of Mage_Catalog_Model_Abstract::loadByAttribute method +** Zend_DB_Select::where must get null values to skip quoting into $cond empty strings if value is null +* Fixed "URL rewrites duplicating when assigning to root category" +* Fixed Shipping method UPS_XML missing titles +* Fixed The pager is missing for tagged product list +* Fixed Report > Products Ordered ignores Store view switcher +* Fixed Flat catalog index problem after upgrade with customizations present +* Fixed Incorrect bundle items inventory decrements +* Fixed Category and product design settings inheritance +* Fixed Removed fatal error on removing non existent quote item from quote +* Fixed Credit Card Maestro/Solo: The field "Start Date" is not displayed on order information page +** deleted unused Maestro/Solo from Payment module config +** moved Maestro/Switch and Solo card definition from Chronopay to Payment module config +** deleted Meastro/Switch definition with incorrect code MS from Cybersource module config +** fixed logic of showing "Issue number" and "Start Date" of Switch/Solo card on frontend +* Added warning about offline refund +* Fixed Mage_Checkout_Block_Cart_Item_Renderer::getIsInStock bug +* Fixed Fatal on edit configurable product page, if custom required price attribute is used +* Fixed #0011135: View invoice error with changed query string +* Fixed Trailing semi-colon displayed on Profile Export page +* Fixed New Orders & Other Authenticated RSS feeds should use HTTPS +* Fixed Dataflow export products sku filter works as not "starts with", but "like" +* Fixed Removed default shipping address assign on paypal express checkout +* Fixed The customers from Puerto Rico can't pay with PayPal (Express Checkout in PaypalUk) +* Fixed Shared shopping cart on the stores with different domains +* Fixed Discount amount for the whole cart divide proportionally between all affected items according to their base price and then applied. +* Fixed Removed store selector in single store mode on url rewrite edit page +* Fixed Javascript validator's translation strings missing +* Fixed Quick Search Autocomplete does not work via ajax http protocol for https page +* Fixed Inventory->Qty Increments - unable to add +* Fixed Loading search query performance issue +* Fixed Changed labels in checkout and payment information blocs for credit cards Solo Maestro Switch +* Fixed Product q-ty doesnt decrease after google checkout +** added same 'checkout_submit_all_after' event to AmazonPayments +** removed 'TODO' notice from Multishipping Checkout, because current scheme is better and will not be influenced by any Multishipping refactoring +** fixed Observer reaction on 'checkout_submit_all_after' to include needed reindexing +* Added checkout_multishipping_controller_success_action and checkout_onepage_controller_success_action events that pass the created order ids on frontend checkout success actions +* Fixed Google Analytics tracking pages with wrong URI: +** Completely reimplemented googleanalytics/ga block: +*** it doesn't depend on session/quote, but just uses order_ids, if passed +*** the page_name parameter is reimplemented as it was intended to be: an optional parameter that can be customized via layout for certain actions +*** moved out the integration part with google checkout to observer +*** eCommerce tracking passes shipping address instead of the billing address, if available +*** replaced the "affiliation" into store frontend name in eCommerce tracking (as it is intended to be) +*** eliminated passing order item "category" in eCommerce tracking (that never existed) +*** optimized javascript code of GA with Google Checkout integration +** Eliminated mutual code coupling between Google Analytics and Google Checkout modules +** Improved integration of Google Analytics and Google Checkout: +*** the GA integration should appear only when GC buttons are available +*** there will be no integration when there is no GA tracking code configured +*** the GA/GC integration seems like wasn't working because there was no pageTracker js variable accessible to the GC scripts +* Fixed Wrong links in backend to "New Products/Low Stock/Customer reviews" RSS feeds +* Fixed "Send auto-generated password" generates e-mail with incorrect template +* Fixed Unable to refund Credit Memo because of Shipping Rounding +* Fixed Added custom option info to recurring profile info page on frontend and backend. +* Fixed Product Visibility and Status disappear when in search +* Fixed Removed validation of new customer shipping address on backend for orders with virtual products only + + +==== 1.4.x-devel-78617 ==== + +== Improvements == +* Design packages and themes optimization/refactoring/improvements: +** minor improvements and fixes +** improved upgrade-ability of CE themes +* iPhone Theme Refactoring +* Added Widget settings sharing between widget types +* For Invoices, Shipment, Credit Memos added possibility to show admin comments at user frontend (checkboxes "Visible on Frontend" in admin interface) +** Added JS to enables/disable checkbox 'Append Comments' depending on checkbox 'Email Order Confirmation' +** Refactored invoice/shipment/refund comments collections models to one abstract Comment Collection Model +** Refactored Block Order Invoice/Shipment/Creditmemo comments to usage of common block and design - Block Order Comments +* A little more accurate profiler - important for very quick measurements +* Add Shopping Cart API +* Implementing payment refund notifications +* Added website price scope for bundle items +* Added support of pending transaction to payflow pro. Also fixed "denied payment review" message in payment + +== Changes == +* Refactoring validation states for Centinel +** Added template method Mage_Centinel_Model_StateAbstract::isLookupSuccessful +* Add boolean type for catalog price rules and condition for category_ids +* Removed Maestro/Switch/Solo card from system. Added Maestro/Switch and Solo cards to Chronopay and Cybersource methods +* Mage_Adminhtml_Block_Sales_Order_Creditmemo block had dependence from 'canCapture' 'canCapturePartial'. It was changed to 'canRefund' 'canRefundPartialPerInvoice'. For set result of Mage_Adminhtml_Block_Sales_Items_Abstract::CanEditQty`s we can use setCanEditQty +* Added Maestro/Switch and Solo Dollars card types for paypal_direct payment method. Also removed Maestro/Solo/Switch card type for this method +* Removed "Shipping address" block on recurring profile view page if product is virtual. Also fixed virtual order detection +* Refactored PayPal cart line items and cart totals calculation to accommodate various discounts and tax settings +** added hidden discount and hidden shipping taxes to the calculation +** eliminated cart line items logic from the helper, moved it to the paypal/cart model +** simplified transferring of the totals and line items to PayPal API objects +* Refactored sales rule discount detection on "buy_x_get_y" rule type +* Added catalog_product table definition to product review collection +* Changed type of obscure input field to 'password', so this field is hidden even when user enters data in it +* Removed dependence to payment method on getting billing agreement method title. For now payment method title stored in billing agreement +* Removed invoice creation thought zero subtotal checkout with new order status "pending" + +== Fixes == +* Fixed ability to buy Product which have status "Out of Stock" through a direct link on button "Checkout with PayPal" +* Fixed All free shipping methods in absent in Transfer Shipping Options menu on PayPal side +* Fixed Payment methods titles for the PDF prints through admin gets from default config instead of the storeview config +* Fixed PayPal and Puerto Rico shipping address +* Fixed "Transfer Shipping Options" pass on PayPal side not correct value for Flat Rate method +* Fixed Centinel JCB validation test cases 8-9 +* Fixed Saving caterory in store view scope +* Fixed Attribute upgrades moved from 1.4.0.0.15 to 1.4.0.0.33 +* Fixed that product tagged by administrator has wrong URL at front-end +* Fixed refusal from Card Verification (through link Exit), does not allow to place order repeatedly +** If lookup was filed and customer tries again we will do new lookup. +** If lookup was success and customer tries again without some changes we will not do new lookup +** If authentication was filed and customer tries again we will do new lookup and authentication +** If authentication was success and customer tries again without some changes we will not do new lookup and authentication +* Fixed #22536: Light-weight email templates. Wishlist share email fix +* Fixed declaration of Mage_Cybersource_Model_Api_ExtendedSoapClient::__doRequest() compatibility with SoapClient::__doRequest() +* Fixed Two registration emails from a wrong store and without a logo are sent when a customer is created in Admin panel +* Fixed Reindex for bundle products with date fields +* Fixed Status is "Ready" instead to be "Reindex required" then creating new subcategory in mode "Manual Update" +** index status changed to STATUS_REQUIRE_REINDEX when search engine changes +* Fixed #23321: Wrong type casting in method +* Fixed Print-All Includes Tracking # from All Shipments on Every Shipment +* Fixed Ignored 'Include in Navigation Menu' category option with enabled flat catalog. +* Fixed Admin unable to add Image through WYSIWYG to description and Short description without intermediate product saving +* Fixed QTY decrement after multishipping +* Double clicking adds product to cart twice +* Fixed Catalog Price Rule(for NOT LOGGEN IN customers) is not applied for shopping cart and while checkout as guest or while first registration. +* Fixed Payment methods titles for the PDF prints through admin gets from default config instead of the storeview config +* Fixed Mage_Adminhtml_Model_System_Config_Backend_Serialized::_afterLoad() does not check input for unserialize() +* Fixed Sending letters through "Contact Us" form, leads to error +* Fixed PayPal Express with Flat Rate: incorrect counting Shipping amounts per order +* Fixed Saving attribute value in store view scope only causes data loss. +* Fixed #22607: Dispose of Mage_GiftRegistry module +* Fixed Related products are not saved when you attach them to a product +* Fixed Added qty to bundle unit price calculation to quote totals recalculating. +* Fixed Saving category cause: 'Exception' with message 'File was not uploaded.' in /home/vadim.kusakin/dev/qa/2759/lib/Varien/File/Uploader.php:139 +* Fixed Fixed MAGE-638 Magento Connect -> MCM -> If agreement checkbox is unchecked, "Continue" button should be disabled +* Fixed Set the same column font size as in cells in PDF documents printing +* Fixed Home page appears instead of predefined 404 page +* Fixed Removed converting of "is one of" and "is not one of" values in decimal. +* Fixed Wrong column type for order_increment_id on Invoice, Shipments, Creditmemo grids +** order_increment_id was setted as "text" instead of "number" type +* Fixed Inconsistency with credit memos showing buttons online vs offline +* Fixed PayPal Express shortcut is missed on product page +* Fixed An email is sent to a customer after its profile is edited in the Admin panel +* Fixed that Payflow Pro includes only the first line of billing/shipping addresses into request +* Fixed Incorrect showing of product page when inputing a product description with table which have attribute align = left +* Fixed Wrong link for bestsellers in admin dashboard. Grids.php fixture doesn't do anything for this bug - just to beautify code. +* Fixed Added fixes to reports - base_discount_amount is actually kept negative in DB. +* Fixed Empty dropdown 'status' at the creation New Review Grid. +* Fixed Incorrect work of "Recently Compared Products" functional on category's page +* Fixed behavior when having single store, javascript raises exception and all followed code is not executed +* Fixed that Special price for dynamic bundle applies twice +* Fixed #21960: Labels in page/html_wrapper and core/text_list in layout +* Fixed GUI bugs on Recurrent Profile frontend part +* Fixed Magento Connect -> Message about invalid URL is duplicated +* Fixed that suspend Recurring Profile from front side leads to error +* Fixed Missing pager for tagged product list +* Fixed Wrong profiler output for getUrl in Category +* Fixed Saving of billing agreement relation with order - added force billing agreement re-saving and fixed isValid method in agreement detection. +* Fixed Incorrect sort order reliable on mysql internal order during eav attribute load +** move prepare select to separate method +* Fixed passing additional totals to PayPal when cart line items are disabled: +** simplified paypal/abstract api to just set the paypal/cart instance and the needed configuration settings +** moved workarounds of setting shipping and discount totals as line items into the appropriate APIs: WPS and NVP +* Fixed In My product Review short description HTML tags are shown +* Fixed that Refund from google chekout don't display on the order in Magento +* Fixed that "Compare Products" block does not appear on the category page and product page +* Fixed Non-existing attribute's source model causes fatal error +* Fixed Varien_Db_Select memory leak + + +==== 1.4.x-devel-77975 ==== + +== Improvements == +* Upgraded Zend Framework to version 1.10.5 +* Upgraded TinyMCE to v.3.3.7 +* Added to prototype validation by length min-length validation +* Added Varien.DateElement for front-end date form fields and re-implemented Varien.DOB +* Added functionality to disable dashboard charts in backend (System > Configuration > Admin > Dashboard) +* Added functionality to disable dashboard charts during installation +* Adminhtml W3C Validation improvements +* Added ability to use session save method from configuration + +== Changes == +* Removed SID from url generation when Use SID on Frontend option is disabled +* Added customer session validation for loadCustomerQuote method +* Iphone clears.css has been deleted + +== Fixes == +* Fixed #18569: Gift Messages not in OrderInfo returned array +* Fixed PayPal API credentials wizard popup size +* Fixed #11449: customer_id is mismatch with entity_id in customer.create +* Fixed merging CSS-files with different skin domain to pick a proper base URL +* Fixed Bad UI style on checkout success page +* Fixed buying more than 1 virtual product in multishipping checkout +* Fixed #22518: Wrong amount for second refund +* Fixed #22776: Bug Causing Recursion Error +* Fixed #22668: Incorrect reports for coupons +* Fixed Products -> Product with "Out of stock" status displayed on frontend, but shouldn't +* Fixed Password miss match for newly created in Back end customer +* Fixed "There has been an error processing your request" page is displayed when specified order status is selected on Reports->Sales->Tax page +* Fixed bug with 'Use Flat Catalog Category' +* Fixed #13770, #16300, #21040 : Product Media Api Broken, product_media.create API overwrites image itself each upload, product_media.update API does not upgrade the image itself +* Fixed #16306: Webservice with htaccess (changes in code style) +* Fixed #22536: Light-weight email templates +* Fixed #18935: Soap api v2 multiple complexFilters with the same key +* Fixed incorrect Window titles on frontend +* Fixed Eliminated display currency usage (instead of the base website currency) in shopping cart price rule conditions +* Fixed #21146: Magento falls into the white screen when saving URL rewrite for a product on the Default Store View +** corrected syntax mistakes +* Fixed batch of issues related to google checkout: +** Invoice don't create automatically with Google Checkout +** Google checkout invoice duplication +** Automatically authorize the buyer's credit card for the full amount of the order +** Refund from google checkout don't display on the order in Magento +** Google Chekout: Discount for shipping amount doesn't apply +** Different order amount in Google checkout and Magento orders +** Applying of discount for shipping, when using google checkout +** Order is in google sandbox doesn't contain gift card +* Fixed #23461: Wrong attribute value in catalog link widget XML +* Fixed getting complete state for orders with zero grand total when processed +* Added Store id param to billing agreement entity. Also fixed store setting in billing agreement payment method. +* Fixed fatal error in payment method list fetching (MAGE-500) +* Fixed #22575: Trace error during using filter "Products" on Tags page +* Fixed Grids with settings remain active while disabled PayPal methods +* Fixed configuration merger fatal error when store/website resource structure is inconsistent +* Fixed PayPal admin setup: checkbox problem +* Fixed Adding shipping address transferring on non guest checkout in Paypal Standard +* Fixed "Save in address book" checkbox in the Shipping address area doesn't work while admin order creation +* Fixed pre-selecting default address during checkout +* Fixed Email with empty password is sent to a customer after an order is created in the Admin panel +* Fixed Necessary to add data validation for filed "Trial Billing Frequency" in Recurring Profile +* Fixed "Out of Stock" product is possible to purchase successfully through Shortcut button +* Fixed phpdocs in lib/Varien and removed junk file + + +==== 1.4.x-devel-77328 ==== + +== Improvements == +* Rendering customer attributes +* Added favicon manager under System > Configuration > Design > HTML Head + +== Fixes == +* Fixed #21146: Magento falls into the white screen when saving URL rewrite for a product on the Default Store View +* Fixed #21643: Fixed "wsdl" parameter validation for Soap V2 +** Changed class SoapServer with class Zend_Soap_server +** Added ability to set response charset from admin panel: System->Configuration->Magento Core API +* Fixed #21499: Default billing and shipping address +* Fixed #21565: missing "comment" for salesOrderStatusHistoryEntity +* Fixed #20481: Access Control List not retrieved for API user for resources() and resourceFaults() operations +* Fixed #18367: FCGI Error on WSDL Url with Apache and mod_fastcgi +* Fixed #22053: use HTTP 301 code instead of 302 in case of web/url/redirect_to_base +* Fixed #20654: Admin order creation->Move mouse cursor isn't changed into hand while move it on some product for adding +* Fixed #21590: Attribute 'Date': testing for uniqueness fields not working +* Fixed #21566: Type of attribute 'Price': Possible to add text value for field 'default value' +* Fixed #22053: added optional behavior (301 or 302) +* Fixed #21570: Review from not logged in user is saved in list of All Reviews when "Allow guests to write reviews = No" +* Fixed #22090: Different values of Qty Increments during create and after duplicate products +* Fixed #22489: Eliminate difference between bundle.js in different skins +* Fixed #22419: Set default stock_data if not exist in create/update product +* Fixed #20227: "Review(x)" link should be added to the compare page. +* Fixed #21570: Review from not logged in user is saved in list of All Reviews when "Allow guests to write reviews = No" +* Fixed #20959: Locale problem in shipping tracking popup raises exception +* Fixed #21955: Layout cache ignores product column count update +* Fixed #20011: After using filter "Color" or "Manufacture" in Configurable Product meaning from column is disappear +* Fixed #21908: Incorrect attribute ordering in "Compare products" page. +* Fixed #22222: Edit review-> if browse stores in the "Visible In " drop-down, rating values reseted +* Fixed #22075: Product Attribute title specified for StoreView isn't showing on the configurable product's page +* Fixed #22605: catalog_category.level return root categories when website or store are null +* Fixed #21806: Different values display on the shopping cart in front-end and back-end +* Fixed #20113: Shipping address display as default on the front-end and as not default on admin for one customer +* Fixed #22575: Trace error during using filter "Products" on Tags page +** added 'filter_index' to array parameter in addColumn() method call +* Fixed #14591: Incorrect SKU for Configurable Product with Custom Options +* Fixed #22476: Blank Column in Related Products Grid +** deleted duplicate output for editable columns +* Fixed #22575: Trace error during using filter "Products" on Tags page +** apply filter_index field values to index +* Fixed #22644: A discrepancy between GT(Base) and GT(Purchased) +* Fixed #22645: Incorrect original price when using custom price in order. +* Fixed #22653: Missed checking for file existents in JS/CSS merger +** cheking in source file exists. If not - do not check last modification and force to merge target file again +* Fixed #22594: Unable to place orders through checkout with multiple addresses with PayPal direct + zero subtotal for one order +* Fixed #21185: Newsletter confirmed automatically BEFORE account email is confirmed. +* Fixed #22167: "Add new row" button in downloadable product +* Fixed #21952: BUG - Category / Url Model (UYN-886991) +* Fixed #15334, #17794 +** API category did not pass validation process due to available_sort_by must be ArrayOfString +** Added category validation for backend (missed) +** Creating separate validation for available_sort_by and default_sort_by attributes +* Fixed #22599 Upgrade from 1.1.8 to 1.8.0.0 database compatibility issues (PARTIAL) +* Fixed #22661: 1 cent bug +* Fixed #22434: 100% discount of products -> the amounts of Tax and Grand Totals are or negative or not corectly +* Fixed #10073: Unnecessary option for downloadable products +* Fixed #20014: Qty use decimals for downloadable +* Fixed #22164: Incorrect message for maximum shipping amount +* Fixed #22174: Custom 'Qty to Refund' isn't remembered after message about incorrect amount +* Fixed #22182: The value of 'Customer Since' field to duplicate clients at different sites. +* Fixed #22243: Add new review by admin->type of this review is 'guest', but should be 'administrator' +* Fixed #22313: Time of order creation if not displayed by the "Order Created At (datetime)" template variable. +* Fixed #22348: "Add to card" button is absent for giftcard product in the catalog +* Fixed #22640: Creating customer unable after adress tab manipulations +* Fixed #22670: Credit memo - incorrect shipping price displaying +* Fixed #22798: Excl and Inc. Tax don't display on the Estimate Shipping and Tax block +* Fixed #20088: Admin able to push on-line refund button for the capture off-line invoice +* Fixed #16306: Webservice with htaccess. Added server authorization (.htaccess) +* Fixed #22266: HEADERS ALREADY SENT Error during dataflow import +** Additionally: moveing layout update in separate layout file of dataflow module. +* Fixed #21412: The "Save Attribute" and "Save and Continue Edit" buttons become disabled after saving attribute with attribute code that exists +* Fixed #22844: After login to admin got 404 instead Startup Page +* Fixed #22852: shopping cart price rule - search by ID - error page +* Fixed #15897: Unsubscription Email Sender in the Newsletters Subscription Options is not working correctly +* Fixed #15899: Newsletters subscription confirmation in not working +* Fixed #22908: Grid Serializer doesn't handle dropdowns as edit columns +* Fixed #22946: 'Products Tagged by Administrators' grid contains information about product that is assigned by the customer +* Fixed #22935: Issue with Google AdWords and DSMM Code +* Fixed #22910: view of system/design table with no records under IE 8 +* Fixed #22914: view of URL rewrite table with no records under IE 8 +* Fixed #22935: Issue with Google AdWords and DSMM Code +* Fixed #22536: Light-weight email templates +* Fixed #23017: Memcache session fallback does not work +* Fixed #22992: Trace appears during create reorder from front-end +* Fixed #22991: Cannot add items to shopping cart after active 'Use Flat Catalog Product' +* Fixed #22813: Google base Undefined Offset when Managing attribute mapping +* Fixed #23138: URL rewrite error on product creation +* Added Regions for baltic states and Finland +* Fixed #23092: Memcached and compiler +* Fixed #19804: sorting/searching by "inventory" field +* Fixed #23241: Catalog price rule not correctly appy for customer group +* Fixed #16294: WSDL missing attributes for customerCustomerEntity +* Fixed #22851: Used wrong resource model for api/user +* Fixed #18207: SOAP-ERROR: Parsing Schema: can't import schema from 'http://schemas.xmlsoap.org/soap/encoding/' +* Fixed Fatal error: Call to undefined function eaccelerator_fetch() + + + +==== 1.4.2.0-beta1 ==== + +=== Major Highlights === +* Included new Magento Connect Manager 2 + ==== 1.4.1.1 ==== === Changes === diff --git a/app/Mage.php b/app/Mage.php index cec1153838..2157104377 100644 --- a/app/Mage.php +++ b/app/Mage.php @@ -152,8 +152,8 @@ public static function getVersionInfo() return array( 'major' => '1', 'minor' => '4', - 'revision' => '1', - 'patch' => '1', + 'revision' => '2', + 'patch' => '0', 'stability' => '', 'number' => '', ); diff --git a/app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes.php b/app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes.php new file mode 100644 index 0000000000..17c55520bf --- /dev/null +++ b/app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes.php @@ -0,0 +1,64 @@ + + */ +class Find_Feed_Block_Adminhtml_Edit_Codes extends Mage_Adminhtml_Block_Widget_Form_Container +{ + /** + * Initialize form container + * + */ + public function __construct() + { + $this->_blockGroup = 'find_feed'; + $this->_controller = 'adminhtml_edit_codes'; + + parent::__construct(); + + $this->_removeButton('back'); + $url = $this->getUrl('*/codes_grid/saveForm'); + $this->_updateButton('save', 'onclick', 'saveNewImportItem(\''.$url.'\')'); + $this->_updateButton('reset', 'label', 'Close'); + $this->_updateButton('reset', 'onclick', 'closeNewImportItem()'); + } + + /** + * Return Form Header text + * + * @return string + */ + public function getHeaderText() + { + return Mage::helper('find_feed')->__('Import attribute map'); + } +} diff --git a/app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes/Edit/Form.php b/app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes/Edit/Form.php new file mode 100644 index 0000000000..43ab782e8f --- /dev/null +++ b/app/code/community/Find/Feed/Block/Adminhtml/Edit/Codes/Edit/Form.php @@ -0,0 +1,124 @@ + + */ +class Find_Feed_Block_Adminhtml_Edit_Codes_Edit_Form extends Mage_Adminhtml_Block_Widget_Form +{ + /** + * Import codes list + * + * @return array + */ + protected function _getImportCodeList() + { + $attributes = Mage::getConfig()->getNode(Find_Feed_Model_Import::XML_NODE_FIND_FEED_ATTRIBUTES)->children(); + $result = array(); + foreach ($attributes as $node) { + $label = trim((string)$node->label); + if ($label) { + $result[$label] = $label; + } + } + + return $result; + } + + /** + * Magento entity type list for eav attributes + * + * @return array + */ + protected function _getCatalogEntityType() + { + return Mage::getSingleton('eav/config')->getEntityType('catalog_product')->getId(); + } + + + /** + * Magento eav attributes list + * + * @return array + */ + protected function _getEavAttributeList() + { + $result = array(); + $collection = Mage::getResourceModel('catalog/product_attribute_collection'); + foreach ($collection as $model) { + $result[$model->getAttributeCode()] = $model->getAttributeCode(); + } + return $result; + } + + /** + * Prepare form + * + * @return Varien_Object + */ + protected function _prepareForm() + { + $form = new Varien_Data_Form(array( + 'id' => 'import_item_form', + 'method' => 'post' + )); + + $fieldset = $form->addFieldset('generate_fieldset', array( + 'legend' => Mage::helper('find_feed')->__('Item params') + )); + $fieldset->addField('import_code', 'select', array( + 'label' => Mage::helper('find_feed')->__('Import code'), + 'name' => 'import_code', + 'required' => true, + 'options' => $this->_getImportCodeList() + )); + $fieldset->addField('eav_code', 'select', array( + 'label' => Mage::helper('find_feed')->__('Eav code'), + 'name' => 'eav_code', + 'required' => true, + 'options' => $this->_getEavAttributeList() + )); + + $source = Mage::getModel('eav/entity_attribute_source_boolean'); + $isImportedOptions = $source->getOptionArray(); + + $fieldset->addField('is_imported', 'select', array( + 'label' => Mage::helper('find_feed')->__('Is imported'), + 'name' => 'is_imported', + 'value' => 1, + 'options' => $isImportedOptions + )); + $form->setUseContainer(true); + + $this->setForm($form); + return parent::_prepareForm(); + } +} diff --git a/app/code/community/Find/Feed/Block/Adminhtml/List/Codes.php b/app/code/community/Find/Feed/Block/Adminhtml/List/Codes.php new file mode 100644 index 0000000000..0e14a48980 --- /dev/null +++ b/app/code/community/Find/Feed/Block/Adminhtml/List/Codes.php @@ -0,0 +1,53 @@ + + */ +class Find_Feed_Block_Adminhtml_List_Codes extends Mage_Adminhtml_Block_Widget_Grid_Container +{ + /** + * Initialize grid container settings + * + */ + public function __construct() + { + $this->_blockGroup = 'find_feed'; + $this->_controller = 'adminhtml_list_codes'; + $this->_headerText = Mage::helper('find_feed')->__('Attributes map'); + $this->_addButtonLabel = Mage::helper('find_feed')->__('Add new'); + + parent::__construct(); + + $url = $this->getUrl('*/codes_grid/editForm'); + $this->_updateButton('add', 'onclick', 'openNewImportWindow(\''.$url.'\');'); + } +} diff --git a/app/code/community/Find/Feed/Block/Adminhtml/List/Codes/Grid.php b/app/code/community/Find/Feed/Block/Adminhtml/List/Codes/Grid.php new file mode 100644 index 0000000000..6a71ccc901 --- /dev/null +++ b/app/code/community/Find/Feed/Block/Adminhtml/List/Codes/Grid.php @@ -0,0 +1,131 @@ + + */ +class Find_Feed_Block_Adminhtml_List_Codes_Grid extends Mage_Adminhtml_Block_Widget_Grid +{ + /** + * Initialize grid settings + * + */ + protected function _construct() + { + parent::_construct(); + + $this->setId('find_feed_list_codes'); + $this->setUseAjax(true); + } + + /** + * Prepare codes collection + * + * @return Find_Feed_Block_Adminhtml_List_Codes_Grid + */ + protected function _prepareCollection() + { + $collection = Mage::getResourceModel('find_feed/codes_collection'); + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + /** + * Configuration of grid + * + * @return $this + */ + protected function _prepareColumns() + { + $this->addColumn('import_code', array( + 'header'=> Mage::helper('find_feed')->__('Feed code'), + 'width' => '80px', + 'type' => 'text', + 'index' => 'import_code' + )); + + $this->addColumn('eav_code', array( + 'header'=> Mage::helper('find_feed')->__('Eav code'), + 'width' => '80px', + 'type' => 'text', + 'index' => 'eav_code' + )); + + $source = Mage::getModel('eav/entity_attribute_source_boolean'); + $isImportedOptions = $source->getOptionArray(); + + $this->addColumn('is_imported', array( + 'header' => Mage::helper('find_feed')->__('In feed'), + 'width' => '100px', + 'index' => 'is_imported', + 'type' => 'options', + 'options' => $isImportedOptions + )); + return parent::_prepareColumns(); + } + + /** + * Prepare massaction + * + * @return $this + */ + protected function _prepareMassaction() + { + $this->setMassactionIdField('code_id'); + $this->getMassactionBlock()->setFormFieldName('code_id'); + + $this->getMassactionBlock()->addItem('enable', array( + 'label' => Mage::helper('find_feed')->__('Import'), + 'url' => $this->getUrl('*/codes_grid/massEnable'), + 'selected' => true, + )); + $this->getMassactionBlock()->addItem('disable', array( + 'label' => Mage::helper('find_feed')->__('Not import'), + 'url' => $this->getUrl('*/codes_grid/massDisable'), + )); + $this->getMassactionBlock()->addItem('delete', array( + 'label' => Mage::helper('find_feed')->__('Delete'), + 'url' => $this->getUrl('*/codes_grid/delete'), + )); + + return $this; + } + + /** + * Return Grid URL for AJAX query + * + * @return string + */ + public function getGridUrl() + { + return $this->getUrl('*/codes_grid/grid', array('_current'=>true)); + } +} diff --git a/app/code/community/Find/Feed/Block/Adminhtml/List/Items.php b/app/code/community/Find/Feed/Block/Adminhtml/List/Items.php new file mode 100644 index 0000000000..80ec99cfe1 --- /dev/null +++ b/app/code/community/Find/Feed/Block/Adminhtml/List/Items.php @@ -0,0 +1,51 @@ + + */ +class Find_Feed_Block_Adminhtml_List_Items extends Mage_Adminhtml_Block_Widget_Grid_Container +{ + /** + * Initialize grid container settings + * + */ + public function __construct() + { + $this->_blockGroup = 'find_feed'; + $this->_controller = 'adminhtml_list_items'; + $this->_headerText = Mage::helper('find_feed')->__('Product import'); + + parent::__construct(); + + $this->_removeButton('add'); + } +} diff --git a/app/code/community/Find/Feed/Block/Adminhtml/List/Items/Grid.php b/app/code/community/Find/Feed/Block/Adminhtml/List/Items/Grid.php new file mode 100644 index 0000000000..84cdb1e067 --- /dev/null +++ b/app/code/community/Find/Feed/Block/Adminhtml/List/Items/Grid.php @@ -0,0 +1,183 @@ + + */ +class Find_Feed_Block_Adminhtml_List_Items_Grid extends Mage_Adminhtml_Block_Widget_Grid +{ + /** + * Initialize grid settings + * + */ + protected function _construct() + { + parent::_construct(); + + $this->setId('find_feed_list_items'); + $this->setDefaultSort('id'); + $this->setUseAjax(true); + } + + /** + * Return Current work store + * + * @return Mage_Core_Model_Store + */ + protected function _getStore() + { + return Mage::app()->getStore(); + } + + /** + * Prepare product collection + * + * @return Find_Feed_Block_Adminhtml_List_Items_Grid + */ + protected function _prepareCollection() + { + $collection = Mage::getModel('catalog/product')->getCollection() + ->setStore($this->_getStore()) + ->addAttributeToSelect('name') + ->addAttributeToSelect('sku') + ->addAttributeToSelect('price') + ->addAttributeToSelect('attribute_set_id') + ->addAttributeToSelect('is_imported'); + $this->setCollection($collection); + + return parent::_prepareCollection(); + } + + /** + * Prepare grid columns + * + * @return Find_Feed_Block_Adminhtml_List_Items_Grid + */ + protected function _prepareColumns() + { + $this->addColumn('id', array( + 'header' => Mage::helper('find_feed')->__('ID'), + 'sortable' => true, + 'width' => '60px', + 'index' => 'entity_id' + )); + + $this->addColumn('name', array( + 'header' => Mage::helper('find_feed')->__('Product Name'), + 'index' => 'name', + 'column_css_class' => 'name' + )); + + $this->addColumn('type', array( + 'header' => Mage::helper('find_feed')->__('Type'), + 'width' => '60px', + 'index' => 'type_id', + 'type' => 'options', + 'options' => Mage::getSingleton('catalog/product_type')->getOptionArray(), + )); + + $entityTypeId = Mage::helper('find_feed')->getProductEntityType(); + $sets = Mage::getResourceModel('eav/entity_attribute_set_collection') + ->setEntityTypeFilter($entityTypeId) + ->load() + ->toOptionHash(); + + $this->addColumn('set_name', array( + 'header' => Mage::helper('find_feed')->__('Attrib. Set Name'), + 'width' => '100px', + 'index' => 'attribute_set_id', + 'type' => 'options', + 'options' => $sets, + )); + + $this->addColumn('sku', array( + 'header' => Mage::helper('find_feed')->__('SKU'), + 'width' => '80px', + 'index' => 'sku', + 'column_css_class' => 'sku' + )); + + $this->addColumn('price', array( + 'header' => Mage::helper('find_feed')->__('Price'), + 'align' => 'center', + 'type' => 'currency', + 'currency_code' => $this->_getStore()->getCurrentCurrencyCode(), + 'rate' => $this->_getStore()->getBaseCurrency()->getRate($this->_getStore()->getCurrentCurrencyCode()), + 'index' => 'price' + )); + + $source = Mage::getModel('eav/entity_attribute_source_boolean'); + $isImportedOptions = $source->getOptionArray(); + + $this->addColumn('is_imported', array( + 'header' => Mage::helper('find_feed')->__('In feed'), + 'width' => '100px', + 'index' => 'is_imported', + 'type' => 'options', + 'options' => $isImportedOptions + )); + + return parent::_prepareColumns(); + } + + /** + * Prepare massaction + * + * @return Find_Feed_Block_Adminhtml_List_Items_Grid + */ + protected function _prepareMassaction() + { + $this->setMassactionIdField('entity_id'); + $this->getMassactionBlock()->setFormFieldName('item_id'); + + $this->getMassactionBlock()->addItem('enable', array( + 'label' => Mage::helper('find_feed')->__('Publish'), + 'url' => $this->getUrl('*/items_grid/massEnable'), + 'selected' => true, + )); + $this->getMassactionBlock()->addItem('disable', array( + 'label' => Mage::helper('find_feed')->__('Not publish'), + 'url' => $this->getUrl('*/items_grid/massDisable'), + )); + + return $this; + } + + /** + * Return Grid URL for AJAX query + * + * @return string + */ + public function getGridUrl() + { + return $this->getUrl('*/*/grid', array('_current'=>true)); + } +} diff --git a/app/code/community/Find/Feed/Helper/Data.php b/app/code/community/Find/Feed/Helper/Data.php new file mode 100755 index 0000000000..a63f1a395d --- /dev/null +++ b/app/code/community/Find/Feed/Helper/Data.php @@ -0,0 +1,69 @@ +getNode(Find_Feed_Model_Import::XML_NODE_FIND_FEED_ATTRIBUTES); + $attributeRequired = array(); + foreach ($attributeConfig->children() as $ac) { + if ((int)$ac->required) { + $attributeRequired[] = (string)$ac->label; + } + } + + foreach ($attributeRequired as $value) { + if (!isset($attributes[$value])) { + return false; + } + } + return true; + } + + /** + * Product entity type + * + * @return int + */ + public function getProductEntityType() + { + return Mage::getSingleton('eav/config')->getEntityType('catalog_product')->getId(); + } +} diff --git a/app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Frequency.php b/app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Frequency.php new file mode 100644 index 0000000000..611a353ff3 --- /dev/null +++ b/app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Frequency.php @@ -0,0 +1,63 @@ + 'Daily', + 'value' => self::DAILY), + array( + 'label' => 'Weekly', + 'value' => self::WEEKLY), + array( + 'label' => 'Monthly', + 'value' => self::MONTHLY), + array( + 'label' => 'Every minute', + 'value' => self::EVERY_MINUTE) + ); + } +} diff --git a/app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Hours.php b/app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Hours.php new file mode 100644 index 0000000000..9c172f8386 --- /dev/null +++ b/app/code/community/Find/Feed/Model/Adminhtml/System/Source/Cron/Hours.php @@ -0,0 +1,50 @@ + $i, 'value' => $i); + } + return $hours; + } +} diff --git a/app/code/community/Find/Feed/Model/Codes.php b/app/code/community/Find/Feed/Model/Codes.php new file mode 100644 index 0000000000..bf5a2c480a --- /dev/null +++ b/app/code/community/Find/Feed/Model/Codes.php @@ -0,0 +1,43 @@ +_init('find_feed/codes'); + } +} diff --git a/app/code/community/Find/Feed/Model/Import.php b/app/code/community/Find/Feed/Model/Import.php new file mode 100755 index 0000000000..45de9d1665 --- /dev/null +++ b/app/code/community/Find/Feed/Model/Import.php @@ -0,0 +1,241 @@ +processImport(); + } + + /** + * TheFind feed process import + */ + public function processImport() + { + $file = $this->_createFile(); + if ($file) { + $this->_deleteFtpFiles(); + $this->_sendFile($file); + if (!$this->_deleteFile($file)) { + Mage::throwException(Mage::helper('find_feed')->__("FTP: Can't delete files")); + } + } + } + + /** + * Create temp csv file and write export + * + * @return mixed + */ + protected function _createFile() + { + $dir = $this->_getTmpDir(); + $fileName = Mage::getStoreConfig(self::XML_PATH_SETTINGS_FINDFEED_FILENAME); + if (!$dir || !$fileName) { + return false; + } + + if (!($attributes = $this->_getImportAttributes()) || count($attributes) <= 0) { + return false; + } + + $headers = array_keys($attributes); + + $file = new Varien_Io_File; + $file->checkAndCreateFolder($dir); + $file->cd($dir); + $file->streamOpen($fileName, 'w+'); + $file->streamLock(); + $file->streamWriteCsv($headers, self::SEPARATOR, self::ENCLOSURE); + + $productCollectionPrototype = Mage::getResourceModel('catalog/product_collection'); + $productCollectionPrototype->setPageSize(self::COLLECTION_PAGE_SIZE); + $pageNumbers = $productCollectionPrototype->getLastPageNumber(); + unset($productCollectionPrototype); + + for ($i = 1; $i <= $pageNumbers; $i++) { + $productCollection = Mage::getResourceModel('catalog/product_collection'); + $productCollection->addAttributeToSelect($attributes); + $productCollection->addAttributeToFilter('is_imported', 1); + $productCollection->setPageSize(self::COLLECTION_PAGE_SIZE); + $productCollection->setCurPage($i)->load(); + foreach ($productCollection as $product) { + $attributesRow = array(); + foreach ($attributes as $key => $value) { + $attributesRow[$key] = $product->getData($value); + } + $file->streamWriteCsv($attributesRow, self::SEPARATOR, self::ENCLOSURE); + } + unset($productCollection); + } + + $file->streamUnlock(); + $file->streamClose(); + + if ($file->fileExists($fileName)) { + return $fileName; + } + return false; + } + + /** + * List import codes (attribute map) model + * + * @return mixed + */ + protected function _getImportAttributes() + { + $attributes = Mage::getResourceModel('find_feed/codes_collection') + ->getImportAttributes(); + + if (!Mage::helper('find_feed')->checkRequired($attributes)) { + return false; + } + return $attributes; + } + + /** + * Send file to remote ftp server + * + * @param string $fileName + */ + protected function _sendFile($fileName) + { + $dir = $this->_getTmpDir(); + $ftpServer = Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_SERVER); + $ftpUserName = Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_USER); + $ftpPass = Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_PASSWORD); + $ftpPath = trim(Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_PATH), '/'); + if ($ftpPath) { + $ftpPath = $ftpPath.'/'; + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'ftp://'.$ftpUserName.':'.$ftpPass.'@'.$ftpServer.'/'.$ftpPath.$fileName); + curl_setopt($ch, CURLOPT_UPLOAD, 1); + curl_setopt($ch, CURLOPT_INFILE, fopen($dir.$fileName, 'r')); + curl_setopt($ch, CURLOPT_INFILESIZE, filesize($dir.$fileName)); + curl_exec($ch); + curl_close($ch); + } + + /** + * Delete all files in current feed ftp directory + * + * @return bool + */ + protected function _deleteFtpFiles() + { + if (is_callable('ftp_connect')) { + $ftpServer = Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_SERVER); + $ftpUserName = Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_USER); + $ftpPass = Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_PASSWORD); + $ftpPath = trim(Mage::getStoreConfig(self::XML_PATH_SETTINGS_FTP_PATH), '/'); + if ($ftpPath) { + $ftpPath = $ftpPath.'/'; + } + + try { + $connId = ftp_connect($ftpServer); + + $loginResult = ftp_login($connId, $ftpUserName, $ftpPass); + if (!$loginResult) { + return false; + } + ftp_pasv($connId, true); + + $ftpDir = $ftpPath?$ftpPath:'.'; + $nlist = ftp_nlist($connId, $ftpDir); + if ($nlist === false) { + return false; + } + foreach ($nlist as $file) { + if (!preg_match('/\.[xX][mM][lL]$/', $file)) { + ftp_delete($connId, $file); + } + } + + ftp_close($connId); + } catch (Exception $e) { + Mage::log($e->getMessage()); + return false; + } + return true; + } else { + return false; + } + } + + /** + * Current tmp directory + * + * @return string + */ + protected function _getTmpDir() + { + return Mage::getBaseDir('var') . DS . 'export' . DS . 'find_feed' . DS; + } + + /** + * Delete tmp file + * + * @param string $fileName + * @return true + */ + protected function _deleteFile($fileName) + { + $dir = $this->_getTmpDir(); + $file = new Varien_Io_File; + if ($file->fileExists($dir . $fileName, true)) { + $file->cd($dir); + $file->rm($fileName); + } + return true; + } +} diff --git a/app/design/frontend/default/iphone/template/core/link.phtml b/app/code/community/Find/Feed/Model/Mysql4/Codes.php similarity index 52% rename from app/design/frontend/default/iphone/template/core/link.phtml rename to app/code/community/Find/Feed/Model/Mysql4/Codes.php index 11e528be87..aa381ab8e8 100644 --- a/app/design/frontend/default/iphone/template/core/link.phtml +++ b/app/code/community/Find/Feed/Model/Mysql4/Codes.php @@ -4,10 +4,10 @@ * * 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. + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/afl-3.0.php + * http://opensource.org/licenses/osl-3.0.php * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@magentocommerce.com so we can send you a copy immediately. @@ -18,10 +18,25 @@ * 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_iphone + * @category Find + * @package Find_Feed * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -?> -getLinkAttributes() ?>>htmlEscape($this->getAnchorText()) ?> + +/** + * Thefind feed codes (attribute map) model + * + * @category Find + * @package Find_Feed + */ +class Find_Feed_Model_Mysql4_Codes extends Mage_Core_Model_Mysql4_Abstract +{ + /** + * Class local constructor + */ + protected function _construct() + { + $this->_init('find_feed/feed_import_codes', 'code_id'); + } +} diff --git a/app/code/community/Find/Feed/Model/Mysql4/Codes/Collection.php b/app/code/community/Find/Feed/Model/Mysql4/Codes/Collection.php new file mode 100644 index 0000000000..2c1ae1a25d --- /dev/null +++ b/app/code/community/Find/Feed/Model/Mysql4/Codes/Collection.php @@ -0,0 +1,55 @@ +_init('find_feed/codes'); + } + + /** + * Fetch attributes to import + * + * @return array + */ + public function getImportAttributes() + { + $this->addFieldToFilter('is_imported', array('eq' => '1')); + return $this->_toOptionHash('import_code', 'eav_code'); + } + +} diff --git a/app/design/frontend/default/iphone/template/page/template/container.phtml b/app/code/community/Find/Feed/Model/Mysql4/Setup.php old mode 100644 new mode 100755 similarity index 57% rename from app/design/frontend/default/iphone/template/page/template/container.phtml rename to app/code/community/Find/Feed/Model/Mysql4/Setup.php index 4d5efadbe3..c7561edcee --- a/app/design/frontend/default/iphone/template/page/template/container.phtml +++ b/app/code/community/Find/Feed/Model/Mysql4/Setup.php @@ -4,10 +4,10 @@ * * 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. + * This source file is subject to the Open Software License (OSL 3.0) + * that is bundled with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: - * http://opensource.org/licenses/afl-3.0.php + * http://opensource.org/licenses/osl-3.0.php * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@magentocommerce.com so we can send you a copy immediately. @@ -18,18 +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 design - * @package default_iphone + * @category Find + * @package Find_Feed * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) - * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -?> - -
-

getTitle() ?>

-
-getChildHtml() ?> +class Find_Feed_Model_Mysql4_Setup extends Mage_Catalog_Model_Resource_Eav_Mysql4_Setup +{ +} + diff --git a/app/code/community/Find/Feed/Model/Observer.php b/app/code/community/Find/Feed/Model/Observer.php new file mode 100644 index 0000000000..43c287b065 --- /dev/null +++ b/app/code/community/Find/Feed/Model/Observer.php @@ -0,0 +1,92 @@ +getStore(); + $website = $observer->getWebsite(); + $groups['settings']['fields']['cron_schedule']['value'] = $this->_getSchedule(); + + Mage::getModel('adminhtml/config_data') + ->setSection('feed') + ->setWebsite($website) + ->setStore($store) + ->setGroups($groups) + ->save(); + } + + /** + * Transform system settings option to cron schedule string + * + * @return string + */ + protected function _getSchedule() + { + $data = Mage::app()->getRequest()->getPost('groups'); + + $frequency = !empty($data['settings']['fields']['cron_frequency']['value'])? + $data['settings']['fields']['cron_frequency']['value']: + 0; + $hours = !empty($data['settings']['fields']['cron_hours']['value'])? + $data['settings']['fields']['cron_hours']['value']: + 0; + + $schedule = "0 $hours "; + + switch ($frequency) { + case Find_Feed_Model_Adminhtml_System_Source_Cron_Frequency::DAILY: + $schedule .= "* * *"; + break; + case Find_Feed_Model_Adminhtml_System_Source_Cron_Frequency::WEEKLY: + $schedule .= "* * 1"; + break; + case Find_Feed_Model_Adminhtml_System_Source_Cron_Frequency::MONTHLY: + $schedule .= "1 * *"; + break; + case Find_Feed_Model_Adminhtml_System_Source_Cron_Frequency::EVERY_MINUTE: + $schedule = "0-59 * * * *"; + break; + default: + $schedule .= "* */1 *"; + break; + } + + return $schedule; + } +} diff --git a/app/code/community/Find/Feed/controllers/Adminhtml/Codes/GridController.php b/app/code/community/Find/Feed/controllers/Adminhtml/Codes/GridController.php new file mode 100644 index 0000000000..1bf761087a --- /dev/null +++ b/app/code/community/Find/Feed/controllers/Adminhtml/Codes/GridController.php @@ -0,0 +1,161 @@ +loadLayout(); + $this->renderLayout(); + } + + /** + * Grid action + * + */ + public function gridAction() + { + $this->loadLayout(); + $this->getResponse()->setBody($this->getLayout()->createBlock('find_feed/adminhtml_list_codes_grid')->toHtml()); + } + + /** + * Grid edit form action + * + */ + public function editFormAction() + { + $this->loadLayout(); + $this->getResponse()->setBody($this->getLayout()->createBlock('find_feed/adminhtml_edit_codes')->toHtml()); + } + + /** + * Save grid edit form action + * + */ + public function saveFormAction() + { + $codeId = $this->getRequest()->getParam('code_id'); + $response = new Varien_Object(); + try { + $model = Mage::getModel('find_feed/codes'); + if ($codeId) { + $model->load($codeId); + } + $model->setImportCode($this->getRequest()->getParam('import_code')); + $model->setEavCode($this->getRequest()->getParam('eav_code')); + $model->setIsImported(intval($this->getRequest()->getParam('is_imported'))); + $model->save(); + $response->setError(0); + } catch(Exception $e) { + $response->setError(1); + $response->setMessage('Save error'); + } + $this->getResponse()->setBody($response->toJson()); + } + + /** + * Codes (attribute map) list for mass action + * + * @return array + */ + protected function _getMassActionCodes() + { + $idList = $this->getRequest()->getParam('code_id'); + if (!empty($idList)) { + $codes = array(); + foreach ($idList as $id) { + $model = Mage::getModel('find_feed/codes'); + if ($model->load($id)) { + array_push($codes, $model); + } + } + return $codes; + } else { + return array(); + } + } + + /** + * Set imported codes (attribute map) mass action + */ + public function massEnableAction() + { + $updatedCodes = 0; + foreach ($this->_getMassActionCodes() as $code) { + $code->setIsImported(1); + $code->save(); + $updatedCodes++; + } + if ($updatedCodes > 0) { + $this->_getSession()->addSuccess(Mage::helper('find_feed')->__("%s codes imported", $updatedCodes)); + } + $this->_redirect('*/*/index'); + } + + /** + * Set not imported codes (attribute map) mass action + */ + public function massDisableAction() + { + $updatedCodes = 0; + foreach ($this->_getMassActionCodes() as $code) { + $code->setIsImported(0); + $code->save(); + $updatedCodes++; + } + if ($updatedCodes > 0) { + $this->_getSession()->addSuccess(Mage::helper('find_feed')->__("%s codes not imported", $updatedCodes)); + } + $this->_redirect('*/*/index'); + } + + /** + * Delete codes (attribute map) mass action + */ + public function deleteAction() + { + $updatedCodes = 0; + foreach ($this->_getMassActionCodes() as $code) { + $code->delete(); + $updatedCodes++; + } + if ($updatedCodes > 0) { + $this->_getSession()->addSuccess(Mage::helper('find_feed')->__("%s codes deleted", $updatedCodes)); + } + $this->_redirect('*/*/index'); + } +} diff --git a/app/code/community/Find/Feed/controllers/Adminhtml/Items/GridController.php b/app/code/community/Find/Feed/controllers/Adminhtml/Items/GridController.php new file mode 100644 index 0000000000..6bb4b7977e --- /dev/null +++ b/app/code/community/Find/Feed/controllers/Adminhtml/Items/GridController.php @@ -0,0 +1,115 @@ +loadLayout(); + $this->renderLayout(); + } + + /** + * Grid action + */ + public function gridAction() + { + $this->loadLayout(); + $this->getResponse()->setBody($this->getLayout()->createBlock('find_feed/adminhtml_list_items_grid')->toHtml()); + } + + /** + * Product list for mass action + * + * @return array + */ + protected function _getMassActionProducts() + { + $idList = $this->getRequest()->getParam('item_id'); + if (!empty($idList)) { + $products = array(); + foreach ($idList as $id) { + $model = Mage::getModel('catalog/product'); + if ($model->load($id)) { + array_push($products, $model); + } + } + return $products; + } else { + return array(); + } + } + + /** + * Add product to feed mass action + */ + public function massEnableAction() + { + $idList = $this->getRequest()->getParam('item_id'); + $updateAction = Mage::getModel('catalog/product_action'); + $attrData = array( + 'is_imported' => 1 + ); + $updatedProducts = count($idList); + if ($updatedProducts) { + try { + $updateAction->updateAttributes($idList, $attrData, Mage::app()->getStore()->getId()); + Mage::getModel('find_feed/import')->processImport(); + $this->_getSession()->addSuccess(Mage::helper('find_feed')->__("%s product in feed.", $updatedProducts)); + } catch (Exception $e) { + $this->_getSession()->addError(Mage::helper('find_feed')->__("Unable to process an import. ") . $e->getMessage()); + } + } + $this->_redirect('*/*/index'); + } + + /** + * Not add product to feed mass action + */ + public function massDisableAction() + { + $updatedProducts = 0; + foreach ($this->_getMassActionProducts() as $product) { + $product->setIsImported(0); + $product->save(); + $updatedProducts++; + } + if ($updatedProducts) { + Mage::getModel('find_feed/import')->processImport(); + $this->_getSession()->addSuccess(Mage::helper('find_feed')->__("%s product not in feed.", $updatedProducts)); + } + $this->_redirect('*/*/index'); + } +} diff --git a/app/code/community/Find/Feed/etc/adminhtml.xml b/app/code/community/Find/Feed/etc/adminhtml.xml new file mode 100644 index 0000000000..462f7f809a --- /dev/null +++ b/app/code/community/Find/Feed/etc/adminhtml.xml @@ -0,0 +1,51 @@ + + + + + + + + TheFind feed + 5 + + + Manage attributes + adminhtml/codes_grid/index + 5 + + + Manage items + adminhtml/items_grid/index + 10 + + + + + + + diff --git a/app/code/community/Find/Feed/etc/config.xml b/app/code/community/Find/Feed/etc/config.xml new file mode 100755 index 0000000000..fbbfbc7d10 --- /dev/null +++ b/app/code/community/Find/Feed/etc/config.xml @@ -0,0 +1,480 @@ + + + + + + 0.0.2 + + + + + + Find_Feed_Model + find_feed_mysql4 + + + Find_Feed_Model_Mysql4 + + + find_feed_import_codes
+
+
+
+
+ + + + Find_Feed + Find_Feed_Model_Mysql4_Setup + + + + + Find_Feed_Block + + + + Find_Feed_Helper + + +
+ + + + + + find_feed/observer + saveSystemConfig + + + + + + + + + + + + + + Feed + + + + + + + + + + + + + + + feed/settings/cron_schedule + + + find_feed/import::dispatch + + + + + + + + + + Find_Feed_Adminhtml + + + + + + + + + + find + + + + + + + + + feed.xml + + + + + + + <required>1</required> + <label>Title</label> + + + 1 + + + + 1 + + + + 1 + + + + 1 + + + + 0 + + + + 0 + UPC-EAN + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + + 0 + + + +
diff --git a/app/code/community/Find/Feed/etc/system.xml b/app/code/community/Find/Feed/etc/system.xml new file mode 100755 index 0000000000..7b9f0aa53c --- /dev/null +++ b/app/code/community/Find/Feed/etc/system.xml @@ -0,0 +1,128 @@ + + + + + + + 300 + + + + + + find + 10 + 1 + 1 + 1 + + + + text + 200 + 1 + 1 + 1 + + + + + + + text + 10 + 1 + 1 + 1 + + + + text + 15 + 1 + 1 + 1 + + + + text + 20 + 1 + 1 + 1 + here to get started.]]> + + + + password + 30 + 1 + 1 + 1 + + + + text + 30 + 1 + 1 + 1 + + + 40 + + select + adminhtml/system_config_source_yesno + 1 + 1 + 1 + + + + select + find_feed/adminhtml_system_source_cron_frequency + 60 + 1 + 1 + 1 + + + + select + find_feed/adminhtml_system_source_cron_hours + 70 + 1 + 1 + 1 + + + + + + + diff --git a/app/code/community/Find/Feed/sql/find_feed_setup/mysql4-install-0.0.1.php b/app/code/community/Find/Feed/sql/find_feed_setup/mysql4-install-0.0.1.php new file mode 100755 index 0000000000..860059b23f --- /dev/null +++ b/app/code/community/Find/Feed/sql/find_feed_setup/mysql4-install-0.0.1.php @@ -0,0 +1,41 @@ +startSetup(); + +$this->run(" + +CREATE TABLE {$this->getTable('find_feed_import_codes')} ( + `code_id` int(10) unsigned NOT NULL auto_increment, + `import_code` varchar(255) NOT NULL, + `eav_code` varchar(255) NOT NULL, + `is_imported` int(10) unsigned NOT NULL, + PRIMARY KEY (`code_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +"); + +$this->endSetup(); diff --git a/app/code/community/Find/Feed/sql/find_feed_setup/mysql4-upgrade-0.0.1-0.0.2.php b/app/code/community/Find/Feed/sql/find_feed_setup/mysql4-upgrade-0.0.1-0.0.2.php new file mode 100644 index 0000000000..34726cbc26 --- /dev/null +++ b/app/code/community/Find/Feed/sql/find_feed_setup/mysql4-upgrade-0.0.1-0.0.2.php @@ -0,0 +1,50 @@ +startSetup(); + +$this->addAttribute('catalog_product', 'is_imported', array( + 'group' => 'General', + 'type' => 'int', + 'input' => 'select', + 'label' => 'In feed', + 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, + 'visible' => 1, + 'required' => 0, + 'visible_on_front' => 0, + 'is_html_allowed_on_front' => 0, + 'is_configurable' => 0, + 'source' => 'eav/entity_attribute_source_boolean', + 'searchable' => 0, + 'filterable' => 0, + 'comparable' => 0, + 'unique' => false, + 'user_defined' => false, + 'is_user_defined' => false, + 'used_in_product_listing' => true +)); + +$this->endSetup(); diff --git a/app/code/community/Phoenix/Moneybookers/controllers/ProcessingController.php b/app/code/community/Phoenix/Moneybookers/controllers/ProcessingController.php index 66aa9b619d..3342b023fa 100644 --- a/app/code/community/Phoenix/Moneybookers/controllers/ProcessingController.php +++ b/app/code/community/Phoenix/Moneybookers/controllers/ProcessingController.php @@ -56,9 +56,9 @@ public function paymentAction() ); $order->save(); - $session->getQuote()->setIsActive(false)->save(); $session->setMoneybookersQuoteId($session->getQuoteId()); $session->setMoneybookersRealOrderId($session->getLastRealOrderId()); + $session->getQuote()->setIsActive(false)->save(); $session->clear(); $this->loadLayout(); @@ -99,8 +99,18 @@ public function cancelAction() $event = Mage::getModel('moneybookers/event') ->setEventData($this->getRequest()->getParams()); $message = $event->cancelEvent(); - $this->_getCheckout()->setQuoteId($this->_getCheckout()->getMoneybookersQuoteId()); - $this->_getCheckout()->addError($message); + + // set quote to active + $session = $this->_getCheckout(); + if ($quoteId = $session->getMoneybookersQuoteId()) { + $quote = Mage::getModel('sales/quote')->load($quoteId); + if ($quote->getId()) { + $quote->setIsActive(true)->save(); + $session->setQuoteId($quoteId); + } + } + + $session->addError($message); $this->_redirect('checkout/cart'); } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Edit/Form.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Edit/Form.php index 4a645cec06..effbdf7155 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Edit/Form.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Edit/Form.php @@ -48,34 +48,40 @@ public function __construct() protected function _prepareLayout() { + $category = $this->getCategory(); + $categoryId = (int) $category->getId(); // 0 when we create category, otherwise some value for editing category + $this->setChild('tabs', $this->getLayout()->createBlock('adminhtml/catalog_category_tabs', 'tabs') ); - if (!$this->getCategory()->isReadonly()) { + // Save button + if (!$category->isReadonly()) { $this->setChild('save_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData(array( 'label' => Mage::helper('catalog')->__('Save Category'), - 'onclick' => "categorySubmit('".$this->getSaveUrl()."',true)", + 'onclick' => "categorySubmit('" . $this->getSaveUrl() . "', true)", 'class' => 'save' )) ); } - if (!in_array($this->getCategory()->getId(), $this->getRootIds()) && - $this->getCategory()->isDeleteable()) { + + // Delete button + if (!in_array($categoryId, $this->getRootIds()) && $category->isDeleteable()) { $this->setChild('delete_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData(array( 'label' => Mage::helper('catalog')->__('Delete Category'), - 'onclick' => "categoryDelete('".$this->getUrl('*/*/delete', array('_current'=>true))."',true)", + 'onclick' => "categoryDelete('" . $this->getUrl('*/*/delete', array('_current' => true)) . "', true, {$categoryId})", 'class' => 'delete' )) ); } - if (!$this->getCategory()->isReadonly()) { - $resetPath = $this->getCategory()->getId() ? '*/*/edit' : '*/*/add'; + // Reset button + if (!$category->isReadonly()) { + $resetPath = $categoryId ? '*/*/edit' : '*/*/add'; $this->setChild('reset_button', $this->getLayout()->createBlock('adminhtml/widget_button') ->setData(array( @@ -178,7 +184,16 @@ public function getTabsHtml() public function getHeader() { if ($this->hasStoreRootCategory()) { - return $this->getCategoryId() ? $this->getCategoryName() : Mage::helper('catalog')->__('New Category'); + if ($this->getCategoryId()) { + return $this->getCategoryName(); + } else { + $parentId = (int) $this->getRequest()->getParam('parent'); + if ($parentId && ($parentId != Mage_Catalog_Model_Category::TREE_ROOT_ID)) { + return Mage::helper('catalog')->__('New Subcategory'); + } else { + return Mage::helper('catalog')->__('New Root Category'); + } + } } return Mage::helper('catalog')->__('Set Root Category for Store'); } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Helper/Pricestep.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Helper/Pricestep.php new file mode 100644 index 0000000000..af127eadd3 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Helper/Pricestep.php @@ -0,0 +1,64 @@ + + */ +class Mage_Adminhtml_Block_Catalog_Category_Helper_Pricestep extends Varien_Data_Form_Element_Text +{ + /** + * Retrieve Element HTML fragment + * + * @return string + */ + public function getElementHtml() + { + $disabled = false; + if (!$this->getValue()) { + $this->setData('disabled', 'disabled'); + $disabled = true; + } + $html = parent::getElementHtml(); + $htmlId = 'use_config_' . $this->getHtmlId(); + $html .= '
getReadonly()) { + $html .= ' disabled="disabled"'; + } + $html .= ' onclick="toggleValueElements(this, this.parentNode);" class="checkbox" type="checkbox" />'; + + $html .= ' '; + $html .= ''; + + return $html; + } +} diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Attributes.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Attributes.php index b3bc9f022f..788d718ebf 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Attributes.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/Attributes.php @@ -109,7 +109,7 @@ protected function _prepareForm() { )); } } - + $this->_setFieldset($attributes, $fieldset); foreach ($attributes as $attribute) { @@ -129,6 +129,21 @@ protected function _prepareForm() { } } + if ($this->getCategory()->getLevel() == 1) { + $fieldset->removeField('custom_use_parent_settings'); + } else { + if ($this->getCategory()->getCustomUseParentSettings()) { + foreach ($this->getCategory()->getDesignAttributes() as $attribute) { + if ($element = $form->getElement($attribute->getAttributeCode())) { + $element->setDisabled(true); + } + } + } + if ($element = $form->getElement('custom_use_parent_settings')) { + $element->setOnclick('onCustomUseParentChanged(this)'); + } + } + if ($this->getCategory()->hasLockedAttributes()) { foreach ($this->getCategory()->getLockedAttributes() as $attribute) { if ($element = $form->getElement($attribute)) { diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/General.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/General.php index e3bdd0de9d..cffbc203cf 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/General.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tab/General.php @@ -70,18 +70,14 @@ public function _prepareLayout() // ), // 'name' // ); - if ($this->getRequest()->getParam('parent')) { - $fieldset->addField('path', 'hidden', array( - 'name' => 'path', - 'value' => $this->getRequest()->getParam('parent') - )); - } else { - $storeId = (int) $this->getRequest()->getParam('store'); - $fieldset->addField('path', 'hidden', array( - 'name' => 'path', - 'value' => 1 - )); + $parentId = $this->getRequest()->getParam('parent'); + if (!$parentId) { + $parentId = Mage_Catalog_Model_Category::TREE_ROOT_ID; } + $fieldset->addField('path', 'hidden', array( + 'name' => 'path', + 'value' => $parentId + )); } else { $fieldset->addField('id', 'hidden', array( 'name' => 'id', diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tabs.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tabs.php index 106ce3d187..83b85f16bc 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tabs.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Tabs.php @@ -94,6 +94,15 @@ public function getAttributeTabBlock() protected function _prepareLayout() { $categoryAttributes = $this->getCategory()->getAttributes(); + if (!$this->getCategory()->getId()) { + foreach ($categoryAttributes as $attribute) { + $default = $attribute->getDefaultValue(); + if ($default != '') { + $this->getCategory()->setData($attribute->getAttributeCode(), $default); + } + } + } + $attributeSetId = $this->getCategory()->getDefaultAttributeSetId(); $groupCollection = Mage::getResourceModel('eav/entity_attribute_group_collection') ->setAttributeSetFilter($attributeSetId) diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Widget/Chooser.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Widget/Chooser.php index ec2cb3c047..0738275ffd 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Widget/Chooser.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Category/Widget/Chooser.php @@ -89,7 +89,10 @@ public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element) if ($element->getValue()) { $value = explode('/', $element->getValue()); - $categoryId = isset($value[1]) ? $value[1] : false; + $categoryId = false; + if (isset($value[0]) && isset($value[1]) && $value[0] == 'category') { + $categoryId = $value[1]; + } if ($categoryId) { $label = Mage::getSingleton('catalog/category')->load($categoryId)->getName(); $chooser->setLabel($label); diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Attribute/Urlkey.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Attribute/Urlkey.php index cd1435bef9..1e1172bceb 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Attribute/Urlkey.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Attribute/Urlkey.php @@ -51,7 +51,7 @@ public function getElementHtml() ); $hidden = new Varien_Data_Form_Element_Hidden($data); $hidden->setForm($element->getForm()); - + $storeId = $element->getForm()->getDataObject()->getStoreId(); $data['html_id'] = $element->getHtmlId() . '_create_redirect'; $data['label'] = Mage::helper('catalog')->__('Create Permanent Redirect for old URL'); @@ -59,7 +59,7 @@ public function getElementHtml() $data['checked'] = Mage::helper('catalog')->shouldSaveUrlRewritesHistory($storeId); $checkbox = new Varien_Data_Form_Element_Checkbox($data); $checkbox->setForm($element->getForm()); - - return parent::getElementHtml() . $hidden->getElementHtml() . $checkbox->getElementHtml() . $checkbox->getLabelHtml(); + + return parent::getElementHtml() . '
' . $hidden->getElementHtml() . $checkbox->getElementHtml() . $checkbox->getLabelHtml(); } } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Fieldset/Element.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Fieldset/Element.php index 90447be1f0..c53ebaba3b 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Fieldset/Element.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Form/Renderer/Fieldset/Element.php @@ -96,8 +96,16 @@ public function canDisplayUseDefault() */ public function usedDefault() { - $devaultValue = $this->getDataObject()->getAttributeDefaultValue($this->getAttribute()->getAttributeCode()); - return $devaultValue === false; + $attributeCode = $this->getAttribute()->getAttributeCode(); + $defaultValue = $this->getDataObject()->getAttributeDefaultValue($attributeCode); + + if (!$this->getDataObject()->getExistsStoreValueFlag($attributeCode)) { + return true; + } + if ($defaultValue === false && !$this->getAttribute()->getIsRequired() && $this->getElement()->getValue()) { + return false; + } + return $defaultValue === false; } /** diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Edit/Tab/Main.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Edit/Tab/Main.php index 867135a779..cc96dedbe2 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Edit/Tab/Main.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Attribute/Edit/Tab/Main.php @@ -127,10 +127,10 @@ protected function _prepareForm() $fieldset = $form->addFieldset('front_fieldset', array('legend'=>Mage::helper('catalog')->__('Frontend Properties'))); $fieldset->addField('is_searchable', 'select', array( - 'name' => 'is_searchable', - 'label' => Mage::helper('catalog')->__('Use in Quick Search'), - 'title' => Mage::helper('catalog')->__('Use in Quick Search'), - 'values' => $yesnoSource, + 'name' => 'is_searchable', + 'label' => Mage::helper('catalog')->__('Use in Quick Search'), + 'title' => Mage::helper('catalog')->__('Use in Quick Search'), + 'values' => $yesnoSource, )); $fieldset->addField('is_visible_in_advanced_search', 'select', array( @@ -239,6 +239,11 @@ protected function _prepareForm() ->addFieldDependence('html_allowed_on_front', 'wysiwyg_enabled', '0') ); + Mage::dispatchEvent('adminhtml_catalog_product_attribute_edit_prepare_form', array( + 'form' => $form, + 'attribute' => $attributeObject + )); + return $this; } @@ -250,7 +255,7 @@ protected function _prepareForm() protected function _getAdditionalElementTypes() { return array( - 'apply' => Mage::getConfig()->getBlockClassName('adminhtml/catalog_product_helper_form_apply') + 'apply' => Mage::getConfig()->getBlockClassName('adminhtml/catalog_product_helper_form_apply'), ); } } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php index b580699c90..ff4e130415 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit.php @@ -118,7 +118,7 @@ protected function _prepareLayout() $this->getLayout()->createBlock('adminhtml/widget_button') ->setData(array( 'label' => Mage::helper('catalog')->__('Duplicate'), - 'onclick' => 'setLocation(\''.$this->getDuplicateUrl().'\')', + 'onclick' => 'setLocation(\'' . $this->getDuplicateUrl() . '\')', 'class' => 'add' )) ); diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Related.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Related.php index ac4db82e99..000fc79ac5 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Related.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Related.php @@ -44,7 +44,7 @@ public function __construct() $this->setDefaultSort('entity_id'); $this->setUseAjax(true); if ($this->_getProduct()->getId()) { - $this->setDefaultFilter(array('in_products'=>1)); + $this->setDefaultFilter(array('in_products' => 1)); } } @@ -73,10 +73,10 @@ protected function _addColumnFilterToCollection($column) $productIds = 0; } if ($column->getFilter()->getValue()) { - $this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds)); + $this->getCollection()->addFieldToFilter('entity_id', array('in' => $productIds)); } else { if($productIds) { - $this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$productIds)); + $this->getCollection()->addFieldToFilter('entity_id', array('nin' => $productIds)); } } } else { @@ -102,7 +102,7 @@ protected function _prepareCollection() if (empty($productIds)) { $productIds = array(0); } - $collection->addFieldToFilter('entity_id', array('in'=>$productIds)); + $collection->addFieldToFilter('entity_id', array('in' => $productIds)); } $this->setCollection($collection); @@ -143,6 +143,7 @@ protected function _prepareColumns() 'width' => 60, 'index' => 'entity_id' )); + $this->addColumn('name', array( 'header' => Mage::helper('catalog')->__('Name'), 'index' => 'name' @@ -205,7 +206,7 @@ protected function _prepareColumns() 'validate_class' => 'validate-number', 'index' => 'position', 'width' => 60, - 'editable' => !$this->isReadonly(), + 'editable' => !$this->_getProduct()->getRelatedReadonly(), 'edit_only' => !$this->_getProduct()->getId() )); @@ -221,7 +222,7 @@ public function getGridUrl() { return $this->getData('grid_url') ? $this->getData('grid_url') - : $this->getUrl('*/*/relatedGrid', array('_current'=>true)); + : $this->getUrl('*/*/relatedGrid', array('_current' => true)); } /** diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Config/Simple.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Config/Simple.php index bf5cfe75eb..e6433bd5e2 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Config/Simple.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Super/Config/Simple.php @@ -33,11 +33,19 @@ */ class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config_Simple extends Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Attributes { + /** + * Link to currently editing product + * + * @var Mage_Catalog_Model_Product + */ + protected $_product = null; + protected function _prepareForm() { $form = new Varien_Data_Form(); $form->setFieldNameSuffix('simple_product'); + $form->setDataObject($this->_getProduct()); $fieldset = $form->addFieldset('simple_product', array( 'legend' => Mage::helper('catalog')->__('Quick simple product creation') @@ -179,6 +187,9 @@ protected function _prepareForm() */ protected function _getProduct() { - return Mage::registry('current_product'); + if (!$this->_product) { + $this->_product = Mage::registry('current_product'); + } + return $this->_product; } } // Class Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config_Simple End diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php index b601cc89d1..f6f2a0dc98 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag.php @@ -89,7 +89,7 @@ protected function _prepareColumns() return parent::_prepareColumns(); } - protected function getRowUrl($row) + public function getRowUrl($row) { return $this->getUrl('*/tag/edit', array( 'tag_id' => $row->getId(), diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php index c4fa62f4ed..7eb2cb30c3 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tab/Tag/Customer.php @@ -86,7 +86,7 @@ protected function _prepareColumns() return parent::_prepareColumns(); } - protected function getRowUrl($row) + public function getRowUrl($row) { return $this->getUrl('*/customer/edit', array('id' => $row->getCustomerId())); } diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php index 2dd513f492..8806f1dfe4 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Edit/Tabs.php @@ -58,7 +58,7 @@ protected function _prepareLayout() foreach ($groupCollection as $group) { $attributes = $product->getAttributes($group->getId(), true); - // do not add grops without attributes + // do not add groups without attributes foreach ($attributes as $key => $attribute) { if( !$attribute->getIsVisible() ) { @@ -144,13 +144,13 @@ protected function _prepareLayout() } if (Mage::getSingleton('admin/session')->isAllowed('admin/catalog/tag')){ $this->addTab('tags', array( - 'label' => Mage::helper('catalog')->__('Product Tags'), - 'url' => $this->getUrl('*/*/tagGrid', array('_current' => true)), - 'class' => 'ajax', + 'label' => Mage::helper('catalog')->__('Product Tags'), + 'url' => $this->getUrl('*/*/tagGrid', array('_current' => true)), + 'class' => 'ajax', )); $this->addTab('customers_tags', array( - 'label' => Mage::helper('catalog')->__('Customers Tagged Product'), + 'label' => Mage::helper('catalog')->__('Customers Tagged Product'), 'url' => $this->getUrl('*/*/tagCustomerGrid', array('_current' => true)), 'class' => 'ajax', )); diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php index 87f21dd6f2..d4e3faf306 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Grid.php @@ -79,8 +79,8 @@ protected function _prepareCollection() } else { $collection->addAttributeToSelect('price'); - $collection->addAttributeToSelect('status'); - $collection->addAttributeToSelect('visibility'); + $collection->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner'); + $collection->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner'); } $this->setCollection($collection); diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Gallery.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Gallery.php index 4010525dbf..07c3ab6312 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Gallery.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Helper/Form/Gallery.php @@ -87,8 +87,8 @@ public function canDisplayUseDefault($attribute) */ public function usedDefault($attribute) { - $devaultValue = $this->getDataObject()->getAttributeDefaultValue($attribute->getAttributeCode()); - return is_null($devaultValue); + $defaultValue = $this->getDataObject()->getAttributeDefaultValue($attribute->getAttributeCode()); + return $defaultValue === false; } /** diff --git a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Widget/Chooser.php b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Widget/Chooser.php index 7b65cdc619..31aac510f7 100644 --- a/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Widget/Chooser.php +++ b/app/code/core/Mage/Adminhtml/Block/Catalog/Product/Widget/Chooser.php @@ -69,10 +69,12 @@ public function prepareElementHtml(Varien_Data_Form_Element_Abstract $element) ->setSourceUrl($sourceUrl) ->setUniqId($uniqId); - if ($element->getValue()) { $value = explode('/', $element->getValue()); - $productId = isset($value[1]) ? $value[1] : false; + $productId = false; + if (isset($value[0]) && isset($value[1]) && $value[0] == 'product') { + $productId = $value[1]; + } $categoryId = isset($value[2]) ? $value[2] : false; $label = ''; if ($categoryId) { diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Form.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Form.php index 3190f3d9af..58dbb2cdba 100644 --- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Form.php +++ b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Form.php @@ -37,7 +37,12 @@ class Mage_Adminhtml_Block_Customer_Edit_Form extends Mage_Adminhtml_Block_Widge protected function _prepareForm() { - $form = new Varien_Data_Form(array('id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post')); + $form = new Varien_Data_Form(array( + 'id' => 'edit_form', + 'action' => $this->getData('action'), + 'method' => 'post', + 'enctype' => 'multipart/form-data' + )); $customer = Mage::registry('current_customer'); diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php index 180147591a..24c4f243ee 100644 --- a/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php +++ b/app/code/core/Mage/Adminhtml/Block/Customer/Edit/Tab/Account.php @@ -46,12 +46,21 @@ public function initForm() $customer = Mage::registry('current_customer'); + /* @var $customerForm Mage_Customer_Model_Form */ + $customerForm = Mage::getModel('customer/form'); + $customerForm->setEntity($customer) + ->setFormCode('adminhtml_customer') + ->initDefaultValues(); + $fieldset = $form->addFieldset('base_fieldset', array('legend'=>Mage::helper('customer')->__('Account Information')) ); - - $this->_setFieldset($customer->getAttributes(), $fieldset); + $attributes = $customerForm->getAttributes(); + foreach ($attributes as $attribute) { + $attribute->unsIsVisible(); + } + $this->_setFieldset($attributes, $fieldset); if ($customer->getId()) { $form->getElement('website_id')->setDisabled('disabled'); @@ -60,8 +69,6 @@ public function initForm() $fieldset->removeField('created_in'); } - $form->getElement('email')->addClass('validate-email'); - // if (Mage::app()->isSingleStoreMode()) { // $fieldset->removeField('website_id'); // $fieldset->addField('website_id', 'hidden', array( @@ -110,8 +117,7 @@ public function initForm() } } } - } - else { + } else { $newFieldset = $form->addFieldset( 'password_fieldset', array('legend'=>Mage::helper('customer')->__('Password Management')) @@ -142,9 +148,10 @@ public function initForm() } // make sendemail and sendmail_store_id disabled, if website_id has empty value - if ($sendemail = $form->getElement('sendemail_store_id')) { + $sendEmail = $form->getElement('sendemail_store_id'); + if ($sendEmail) { $prefix = $form->getHtmlIdPrefix(); - $sendemail->setAfterElementHtml( + $sendEmail->setAfterElementHtml( ''; - - $headBlock = $this->getLayout()->createBlock('page/html_head'); - $headBlock->addJs('prototype/prototype.js'); - $headBlock->addJs('mage/adminhtml/loader.js'); - echo $headBlock->getCssJsHtml(); - - echo ' - '.($profile->getId() ? $this->htmlEscape($profile->getName()) : $this->__('No Profile')).' -'; - echo ''; - - if ($profile->getId()) { - - echo '"; - - $showFinished = true; - $batchModel = Mage::getSingleton('dataflow/batch'); - /* @var $batchModel Mage_Dataflow_Model_Batch */ - if ($batchModel->getId()) { - if ($batchModel->getAdapter()) { - $numberOfRecords = $profile->getData('gui_data/import/number_of_records'); - if (!$numberOfRecords) { - $batchParams = $batchModel->getParams(); - $numberOfRecords = isset($batchParams['number_of_records']) ? $batchParams['number_of_records'] : 1; - } - - $showFinished = false; - $batchImportModel = $batchModel->getBatchImportModel(); - $importIds = $batchImportModel->getIdCollection(); - $countItems = count($importIds); - - $batchConfig = array( + $this->setNumberOfRecords($numberOfRecords); + $this->setShowFinished(false); + $batchImportModel = $batchModel->getBatchImportModel(); + $importIds = $batchImportModel->getIdCollection(); + $this->setBatchItemsCount(count($importIds)); + $this->setBatchConfig( + array( 'styles' => array( 'error' => array( 'icon' => Mage::getDesign()->getSkinUrl('images/error_msg_icon.gif'), @@ -154,157 +85,117 @@ protected function _toHtml() . '' . '#{text}' . '', - 'text' => $this->__('Processed %s%% %s/%d records', '#{percent}', '#{updated}', $countItems), + 'text' => $this->__('Processed %s%% %s/%d records', '#{percent}', '#{updated}', $this->getBatchItemsCount()), 'successText' => $this->__('Imported %s records', '#{updated}') + ) + ); + $jsonIds = array_chunk($importIds, $numberOfRecords); + $importData = array(); + foreach ($jsonIds as $part => $ids) { + $importData[] = array( + 'batch_id' => $batchModel->getId(), + 'rows[]' => $ids ); -echo ' - - -'; - - - $jsonIds = array_chunk($importIds, $numberOfRecords); - foreach ($jsonIds as $part => $ids) { - $data = array( - 'batch_id' => $batchModel->getId(), - 'rows[]' => $ids - ); - echo ''; - } - echo ''; - //print $this->getUrl('*/*/batchFinish', array('id' => $batchModel->getId())); - } - else { - $batchModel->delete(); + /** + * Generating form key + * @return string + */ + public function getFormKey() + { + return Mage::getSingleton('core/session')->getFormKey(); + } + /** + * Return batch model and initialize it if need + * @return Mage_Dataflow_Model_Batch + */ + public function getBatchModel() + { + return $this->_prepareBatchModel() + ->_getBatchModel(); + } + /** + * Generating exceptions data + * @return array + */ + public function getExceptions() + { + if (!is_null(parent::getExceptions())) + return parent::getExceptions(); + $exceptions = array(); + $this->getProfile()->run(); + foreach ($this->getProfile()->getExceptions() as $e) { + switch ($e->getLevel()) { + case Varien_Convert_Exception::FATAL: + $img = 'error_msg_icon.gif'; + $liStyle = 'background-color:#FBB; '; + break; + case Varien_Convert_Exception::ERROR: + $img = 'error_msg_icon.gif'; + $liStyle = 'background-color:#FDD; '; + break; + case Varien_Convert_Exception::WARNING: + $img = 'fam_bullet_error.gif'; + $liStyle = 'background-color:#FFD; '; + break; + case Varien_Convert_Exception::NOTICE: + $img = 'fam_bullet_success.gif'; + $liStyle = 'background-color:#DDF; '; + break; } - } - - if ($showFinished) { - echo ""; - } + $exceptions[] = array( + "style" => $liStyle, + "src" => Mage::getDesign()->getSkinUrl('images/'.$img), + "message" => $e->getMessage(), + "position" => $e->getPosition() + ); } - /* - echo '
  • '; - echo ''; - echo $this->__("Finished profile execution."); - echo '
  • '; - echo ""; - */ - echo ''; + parent::setExceptions($exceptions); + return $exceptions; } } + diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Assigned/Grid.php b/app/code/core/Mage/Adminhtml/Block/Tag/Assigned/Grid.php index 1811ec4af7..dd3e4ba32b 100644 --- a/app/code/core/Mage/Adminhtml/Block/Tag/Assigned/Grid.php +++ b/app/code/core/Mage/Adminhtml/Block/Tag/Assigned/Grid.php @@ -33,6 +33,8 @@ */ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget_Grid { + protected $_currentTagModel; + /** * Set grid params * @@ -40,6 +42,7 @@ class Mage_Adminhtml_Block_Tag_Assigned_Grid extends Mage_Adminhtml_Block_Widget public function __construct() { parent::__construct(); + $this->_currentTagModel = Mage::registry('current_tag'); $this->setId('tag_assigned_product_grid'); $this->setDefaultSort('entity_id'); $this->setDefaultDir('DESC'); @@ -56,7 +59,7 @@ public function __construct() */ protected function _getTagId() { - return Mage::registry('current_tag')->getId(); + return $this->_currentTagModel->getId(); } /** @@ -110,6 +113,7 @@ protected function _prepareCollection() ->addAttributeToSelect('name') ->addAttributeToSelect('attribute_set_id') ->addAttributeToSelect('type_id') + //->addAttributeToFilter('status', array('')) ->joinField('qty', 'cataloginventory/stock_item', 'qty', @@ -266,6 +270,8 @@ public function getGridUrl() */ public function getRelatedProducts() { - return Mage::registry('current_tag')->getRelatedProductIds(); + return $this->_currentTagModel + ->setStatusFilter(Mage_Tag_Model_Tag::STATUS_APPROVED) + ->getRelatedProductIds(); } } diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Customer/Grid.php b/app/code/core/Mage/Adminhtml/Block/Tag/Customer/Grid.php index 971bfff36e..bccef050b2 100644 --- a/app/code/core/Mage/Adminhtml/Block/Tag/Customer/Grid.php +++ b/app/code/core/Mage/Adminhtml/Block/Tag/Customer/Grid.php @@ -113,7 +113,7 @@ protected function _prepareColumns() return parent::_prepareColumns(); } - protected function getRowUrl($row) + public function getRowUrl($row) { return $this->getUrl('*/customer/edit', array('id' => $row->getCustomerId())); } diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Grid/Pending.php b/app/code/core/Mage/Adminhtml/Block/Tag/Grid/Pending.php index 8335e622c0..574bf8469b 100644 --- a/app/code/core/Mage/Adminhtml/Block/Tag/Grid/Pending.php +++ b/app/code/core/Mage/Adminhtml/Block/Tag/Grid/Pending.php @@ -63,24 +63,24 @@ protected function _prepareColumns() $baseUrl = $this->getUrl(); $this->addColumn('name', array( - 'header' => Mage::helper('tag')->__('Tag'), - 'index' => 'name', + 'header' => Mage::helper('tag')->__('Tag'), + 'index' => 'name' )); $this->addColumn('products', array( - 'header' => Mage::helper('tag')->__('Products'), - 'width' => '140px', - 'align' => 'right', - 'index' => 'products', - 'type' => 'number', + 'header' => Mage::helper('tag')->__('Products'), + 'width' => '140px', + 'align' => 'right', + 'index' => 'products', + 'type' => 'number' )); $this->addColumn('customers', array( - 'header' => Mage::helper('tag')->__('Customers'), - 'width' => '140px', - 'align' => 'right', - 'index' => 'customers', - 'type' => 'number', + 'header' => Mage::helper('tag')->__('Customers'), + 'width' => '140px', + 'align' => 'right', + 'index' => 'customers', + 'type' => 'number' )); // Collection for stores filters diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Product/Grid.php b/app/code/core/Mage/Adminhtml/Block/Tag/Product/Grid.php index 2f1f17a947..0451577f2f 100644 --- a/app/code/core/Mage/Adminhtml/Block/Tag/Product/Grid.php +++ b/app/code/core/Mage/Adminhtml/Block/Tag/Product/Grid.php @@ -117,7 +117,7 @@ protected function _addColumnFilterToCollection($column) } } - protected function getRowUrl($row) + public function getRowUrl($row) { return $this->getUrl('*/catalog_product/edit', array('id' => $row->getProductId())); } diff --git a/app/code/core/Mage/Adminhtml/Block/Tag/Tag/Grid.php b/app/code/core/Mage/Adminhtml/Block/Tag/Tag/Grid.php index 9fe7725ef7..d7ea2c9b3e 100644 --- a/app/code/core/Mage/Adminhtml/Block/Tag/Tag/Grid.php +++ b/app/code/core/Mage/Adminhtml/Block/Tag/Tag/Grid.php @@ -70,32 +70,32 @@ protected function _prepareCollection() protected function _prepareColumns() { $this->addColumn('name', array( - 'header' => Mage::helper('tag')->__('Tag'), - 'index' => 'name', + 'header' => Mage::helper('tag')->__('Tag'), + 'index' => 'name', )); $this->addColumn('products', array( - 'header' => Mage::helper('tag')->__('Products'), - 'width' => 140, - 'align' => 'right', - 'index' => 'products', - 'type' => 'number', + 'header' => Mage::helper('tag')->__('Products'), + 'width' => 140, + 'align' => 'right', + 'index' => 'products', + 'type' => 'number', )); $this->addColumn('customers', array( - 'header' => Mage::helper('tag')->__('Customers'), - 'width' => 140, - 'align' => 'right', - 'index' => 'customers', - 'type' => 'number', + 'header' => Mage::helper('tag')->__('Customers'), + 'width' => 140, + 'align' => 'right', + 'index' => 'customers', + 'type' => 'number', )); $this->addColumn('status', array( - 'header' => Mage::helper('tag')->__('Status'), - 'width' => 90, - 'index' => 'status', - 'type' => 'options', - 'options' => $this->helper('tag/data')->getStatusesArray(), + 'header' => Mage::helper('tag')->__('Status'), + 'width' => 90, + 'index' => 'status', + 'type' => 'options', + 'options' => $this->helper('tag/data')->getStatusesArray(), )); if (!Mage::app()->isSingleStoreMode()) { @@ -128,16 +128,16 @@ protected function _prepareMassaction() array_unshift($statuses, array('label'=>'', 'value'=>'')); $this->getMassactionBlock()->addItem('status', array( - 'label'=> Mage::helper('tag')->__('Change status'), - 'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)), - 'additional' => array( - 'visibility' => array( - 'name' => 'status', - 'type' => 'select', - 'class' => 'required-entry', - 'label' => Mage::helper('tag')->__('Status'), - 'values' => $statuses - ) + 'label'=> Mage::helper('tag')->__('Change status'), + 'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)), + 'additional' => array( + 'visibility' => array( + 'name' => 'status', + 'type' => 'select', + 'class' => 'required-entry', + 'label' => Mage::helper('tag')->__('Status'), + 'values' => $statuses + ) ) )); diff --git a/app/code/core/Mage/Adminhtml/Block/Urlrewrite/Edit/Form.php b/app/code/core/Mage/Adminhtml/Block/Urlrewrite/Edit/Form.php index 9baa99480d..7d68424307 100644 --- a/app/code/core/Mage/Adminhtml/Block/Urlrewrite/Edit/Form.php +++ b/app/code/core/Mage/Adminhtml/Block/Urlrewrite/Edit/Form.php @@ -93,12 +93,39 @@ protected function _prepareForm() // get store switcher or a hidden field with its id if (!Mage::app()->isSingleStoreMode()) { + $stores = Mage::getSingleton('adminhtml/system_store')->getStoreValuesForForm(); + + //showing websites that only associated to products + if ($product && $product->getId()) { + $productStores = $product->getStoreIds() ? $product->getStoreIds() : array(); + if (!$productStores) { + $stores = array(); //reset the stores + Mage::getSingleton('adminhtml/session')->addError($this->__('Chosen product does not associated with any website.')); + } + if($stores){ + foreach ($stores as $i => $store) { + if (isset($store['value']) && $store['value']) { + $found = false; + foreach ($store['value'] as $_v) { + if (isset($_v['value']) && in_array($_v['value'],$productStores)) { + $found = true; + break; + } + } + if (!$found) { + $stores[$i]['value'] = array(); + } + } + } + } + } + $element = $fieldset->addField('store_id', 'select', array( 'label' => Mage::helper('adminhtml')->__('Store'), 'title' => Mage::helper('adminhtml')->__('Store'), 'name' => 'store_id', 'required' => true, - 'values' => Mage::getSingleton('adminhtml/system_store')->getStoreValuesForForm(), + 'values' => $stores, 'disabled' => true, 'value' => $formValues['store_id'], )); @@ -107,7 +134,7 @@ protected function _prepareForm() } } else { - $fieldset->addField('store_id', ($model->getId() ? 'hidden' : 'select'), array( + $fieldset->addField('store_id', 'hidden', array( 'name' => 'store_id', 'value' => Mage::app()->getStore(true)->getId() )); diff --git a/app/code/core/Mage/Adminhtml/Block/Widget/Form.php b/app/code/core/Mage/Adminhtml/Block/Widget/Form.php index 82cdb6e615..e46578c585 100644 --- a/app/code/core/Mage/Adminhtml/Block/Widget/Form.php +++ b/app/code/core/Mage/Adminhtml/Block/Widget/Form.php @@ -52,7 +52,7 @@ protected function _construct() $this->setDestElementId('edit_form'); $this->setShowGlobalIcon(false); } - + /** * Preparing global layout * @@ -71,7 +71,7 @@ protected function _prepareLayout() Varien_Data_Form::setFieldsetElementRenderer( $this->getLayout()->createBlock('adminhtml/widget_form_renderer_fieldset_element') ); - + return parent::_prepareLayout(); } @@ -199,9 +199,11 @@ protected function _setFieldset($attributes, $fieldset, $exclude=array()) if ($inputType == 'select' || $inputType == 'multiselect') { $element->setValues($attribute->getSource()->getAllOptions(true, true)); - } elseif ($inputType == 'date') { + } else if ($inputType == 'date') { $element->setImage($this->getSkinUrl('images/grid-cal.gif')); $element->setFormat(Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT)); + } else if ($inputType == 'multiline') { + $element->setLineCount($attribute->getMultilineCount()); } } } diff --git a/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php b/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php index 98824b0b23..c1e648dd44 100644 --- a/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php +++ b/app/code/core/Mage/Adminhtml/Block/Widget/Grid.php @@ -161,6 +161,13 @@ class Mage_Adminhtml_Block_Widget_Grid extends Mage_Adminhtml_Block_Widget */ protected $_exportTypes = array(); + /** + * Rows per page for import + * + * @var int + */ + protected $_exportPageSize = 1000; + /** * Massaction row id field * @@ -786,6 +793,23 @@ public function getRssLists() return empty($this->_rssLists) ? false : $this->_rssLists; } + /** + * Returns url for RSS + * Can be overloaded in descendant classes to perform custom changes to url passed to addRssList() + * + * @param string $url + * @return string + */ + protected function _getRssUrl($url) + { + $urlModel = Mage::getModel('core/url'); + if (Mage::app()->getStore()->getStoreInUrl()) { + // Url in 'admin' store view won't be accessible, so form it in default store view frontend + $urlModel->setStore(Mage::app()->getDefaultStoreView()); + } + return $urlModel->getUrl($url); + } + /** * Add new rss list to grid * @@ -797,7 +821,7 @@ public function addRssList($url, $label) { $this->_rssLists[] = new Varien_Object( array( - 'url' => Mage::getModel('core/url')->getUrl($url), + 'url' => $this->_getRssUrl($url), 'label' => $label ) ); @@ -879,7 +903,7 @@ public function _exportIterateCollection($callback, array $args) while ($break !== true) { $collection = clone $originalCollection; - $collection->setPageSize(1000); + $collection->setPageSize($this->_exportPageSize); $collection->setCurPage($page); $collection->load(); if (is_null($count)) { @@ -1571,4 +1595,17 @@ public function setEmptyCellLabel($label) $this->_emptyCellLabel = $label; return $this; } + + /** + * Return row url for js event handlers + * + * @param Mage_Catalog_Model_Product|Varien_Object + * @return string + */ + public function getRowUrl($item) + { + $res = parent::getRowUrl($item); + return ($res ? $res : '#'); + } + } diff --git a/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Renderer/Country.php b/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Renderer/Country.php index 4eab53f2d9..3e9edadfc5 100644 --- a/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Renderer/Country.php +++ b/app/code/core/Mage/Adminhtml/Block/Widget/Grid/Column/Renderer/Country.php @@ -42,7 +42,7 @@ public function render(Varien_Object $row) if ($data = $row->getData($this->getColumn()->getIndex())) { $name = Mage::app()->getLocale()->getCountryTranslation($data); if (empty($name)) { - $name = $data; + $name = $this->escapeHtml($data); } return $name; } diff --git a/app/code/core/Mage/Adminhtml/Block/Widget/Tab/Interface.php b/app/code/core/Mage/Adminhtml/Block/Widget/Tab/Interface.php index 42e32f4433..c109d267ad 100644 --- a/app/code/core/Mage/Adminhtml/Block/Widget/Tab/Interface.php +++ b/app/code/core/Mage/Adminhtml/Block/Widget/Tab/Interface.php @@ -34,8 +34,31 @@ */ interface Mage_Adminhtml_Block_Widget_Tab_Interface { + /** + * Return Tab label + * + * @return string + */ public function getTabLabel(); + + /** + * Return Tab title + * + * @return string + */ public function getTabTitle(); + + /** + * Can show tab in tabs + * + * @return boolean + */ public function canShowTab(); + + /** + * Tab is hidden + * + * @return boolean + */ public function isHidden(); } diff --git a/app/code/core/Mage/Adminhtml/Controller/Sales/Creditmemo.php b/app/code/core/Mage/Adminhtml/Controller/Sales/Creditmemo.php index db702b3bd0..fcd9326a20 100644 --- a/app/code/core/Mage/Adminhtml/Controller/Sales/Creditmemo.php +++ b/app/code/core/Mage/Adminhtml/Controller/Sales/Creditmemo.php @@ -116,9 +116,6 @@ public function printAction() /** @see Mage_Adminhtml_Sales_Order_InvoiceController */ if ($creditmemoId = $this->getRequest()->getParam('invoice_id')) { // invoice_id?! if ($creditmemo = Mage::getModel('sales/order_creditmemo')->load($creditmemoId)) { - if ($creditmemo->getStoreId()) { - Mage::app()->setCurrentStore($creditmemo->getStoreId()); - } $pdf = Mage::getModel('sales/order_pdf_creditmemo')->getPdf(array($creditmemo)); $this->_prepareDownloadResponse('creditmemo'.Mage::getSingleton('core/date')->date('Y-m-d_H-i-s').'.pdf', $pdf->render(), 'application/pdf'); } diff --git a/app/code/core/Mage/Adminhtml/Controller/Sales/Invoice.php b/app/code/core/Mage/Adminhtml/Controller/Sales/Invoice.php index 92d1e6e7f1..8eb8729118 100644 --- a/app/code/core/Mage/Adminhtml/Controller/Sales/Invoice.php +++ b/app/code/core/Mage/Adminhtml/Controller/Sales/Invoice.php @@ -110,9 +110,6 @@ public function printAction() { if ($invoiceId = $this->getRequest()->getParam('invoice_id')) { if ($invoice = Mage::getModel('sales/order_invoice')->load($invoiceId)) { - if ($invoice->getStoreId()) { - Mage::app()->setCurrentStore($invoice->getStoreId()); - } $pdf = Mage::getModel('sales/order_pdf_invoice')->getPdf(array($invoice)); $this->_prepareDownloadResponse('invoice'.Mage::getSingleton('core/date')->date('Y-m-d_H-i-s').'.pdf', $pdf->render(), 'application/pdf'); } diff --git a/app/code/core/Mage/Adminhtml/Controller/Sales/Shipment.php b/app/code/core/Mage/Adminhtml/Controller/Sales/Shipment.php index bcb76e2c3c..f82e3a08ba 100644 --- a/app/code/core/Mage/Adminhtml/Controller/Sales/Shipment.php +++ b/app/code/core/Mage/Adminhtml/Controller/Sales/Shipment.php @@ -103,9 +103,6 @@ public function printAction() /** @see Mage_Adminhtml_Sales_Order_InvoiceController */ if ($shipmentId = $this->getRequest()->getParam('invoice_id')) { // invoice_id o_0 if ($shipment = Mage::getModel('sales/order_shipment')->load($shipmentId)) { - if ($shipment->getStoreId()) { - Mage::app()->setCurrentStore($shipment->getStoreId()); - } $pdf = Mage::getModel('sales/order_pdf_shipment')->getPdf(array($shipment)); $this->_prepareDownloadResponse('packingslip'.Mage::getSingleton('core/date')->date('Y-m-d_H-i-s').'.pdf', $pdf->render(), 'application/pdf'); } diff --git a/app/code/core/Mage/Adminhtml/Helper/Catalog/Product/Edit/Action/Attribute.php b/app/code/core/Mage/Adminhtml/Helper/Catalog/Product/Edit/Action/Attribute.php index a28c26436d..8907d5555d 100644 --- a/app/code/core/Mage/Adminhtml/Helper/Catalog/Product/Edit/Action/Attribute.php +++ b/app/code/core/Mage/Adminhtml/Helper/Catalog/Product/Edit/Action/Attribute.php @@ -35,27 +35,19 @@ class Mage_Adminhtml_Helper_Catalog_Product_Edit_Action_Attribute extends Mage_Core_Helper_Data { /** - * Selected products for massupdate + * Selected products for mass-update * * @var Mage_Catalog_Model_Entity_Product_Collection */ protected $_products; /** - * Array of products that not available in selected store - * - * @var array - */ - protected $_productsNotInStore; - - /** - * Same attribtes for selected products + * Array of same attributes for selected products * * @var Mage_Eav_Model_Mysql4_Entity_Attribute_Collection */ protected $_attributes; - /** * Excluded from batch update attribute codes * @@ -64,7 +56,8 @@ class Mage_Adminhtml_Helper_Catalog_Product_Edit_Action_Attribute extends Mage_C protected $_excludedAttributes = array('url_key'); /** - * Retrive product collection + * Return product collection with selected product filter + * Product collection didn't load * * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */ @@ -73,22 +66,20 @@ public function getProducts() if (is_null($this->_products)) { $productsIds = $this->getProductIds(); - if(!is_array($productsIds)) { + if (!is_array($productsIds)) { $productsIds = array(0); } $this->_products = Mage::getResourceModel('catalog/product_collection') ->setStoreId($this->getSelectedStoreId()) ->addIdFilter($productsIds); - //->load(); - //->addStoreNamesToResult(); } return $this->_products; } /** - * Retrive selected products ids from post or session + * Return array of selected product ids from post or session * * @return array|null */ @@ -96,7 +87,7 @@ public function getProductIds() { $session = Mage::getSingleton('adminhtml/session'); - if ($this->_getRequest()->isPost() && $this->_getRequest()->getActionName()=='edit') { + if ($this->_getRequest()->isPost() && $this->_getRequest()->getActionName() == 'edit') { $session->setProductIds($this->_getRequest()->getParam('product', null)); } @@ -104,17 +95,17 @@ public function getProductIds() } /** - * Retrive selected store id + * Return selected store id from request * * @return integer */ public function getSelectedStoreId() { - return (int) $this->_getRequest()->getParam('store', 0); + return (int)$this->_getRequest()->getParam('store', Mage_Core_Model_App::ADMIN_STORE_ID); } /** - * Retrive selected products' attribute sets + * Return array of attribute sets by selected products * * @return array */ @@ -124,24 +115,34 @@ public function getProductsSetIds() } /** - * Retrive same attributes for selected products without unique + * Return collection of same attributes for selected products without unique * * @return Mage_Eav_Model_Mysql4_Entity_Attribute_Collection */ public function getAttributes() { if (is_null($this->_attributes)) { - $this->_attributes = $this->getProducts()->getEntity()->getEntityType()->getAttributeCollection() + $this->_attributes = Mage::getSingleton('eav/config') + ->getEntityType('catalog_product') + ->getAttributeCollection() ->addIsNotUniqueFilter() ->setInAllAttributeSetsFilter($this->getProductsSetIds()); - foreach ($this->_excludedAttributes as $attributeCode) { - $this->_attributes->addFieldToFilter('attribute_code', array('neq'=>$attributeCode)); + if ($this->_excludedAttributes) { + $this->_attributes->addFieldToFilter('attribute_code', array('nin' => $this->_excludedAttributes)); } - $this->_attributes->load(); - foreach($this->_attributes as $attribute) { - $attribute->setEntity($this->getProducts()->getEntity()); + // check product type apply to limitation and remove attributes that impossible to change in mass-update + $productTypeIds = $this->getProducts()->getProductTypeIds(); + foreach ($this->_attributes as $attribute) { + /* @var $attribute Mage_Catalog_Model_Entity_Attribute */ + foreach ($productTypeIds as $productTypeId) { + $applyTo = $attribute->getApplyTo(); + if (count($applyTo) > 0 && !in_array($productTypeId, $applyTo)) { + $this->_attributes->removeItemByKey($attribute->getId()); + break; + } + } } } @@ -149,23 +150,13 @@ public function getAttributes() } /** - * Retrive products ids that not available for selected store + * Return product ids that not available for selected store * + * @deprecated since 1.4.1 * @return array */ public function getProductsNotInStoreIds() { - if (is_null($this->_productsNotInStore)) { - $this->_productsNotInStoreIds = array(); - /*foreach ($this->getProducts() as $product) { - $stores = $product->getStores(); - if (!isset($stores[$this->getSelectedStoreId()]) && $this->getSelectedStoreId() != 0) { - $this->_productsNotInStoreIds[] = $product->getId(); - } - }*/ - } - - return $this->_productsNotInStoreIds; + return array(); } - } diff --git a/app/code/core/Mage/Adminhtml/Model/Customer/Renderer/Region.php b/app/code/core/Mage/Adminhtml/Model/Customer/Renderer/Region.php index 54c10adede..8bb8a55938 100644 --- a/app/code/core/Mage/Adminhtml/Model/Customer/Renderer/Region.php +++ b/app/code/core/Mage/Adminhtml/Model/Customer/Renderer/Region.php @@ -72,28 +72,45 @@ public function render(Varien_Data_Form_Element_Abstract $element) break; } } + + // Output two elements - for 'region' and for 'region_id'. + // Two elements are needed later upon form post - to properly set data to address model, + // otherwise old value can be left in region_id attribute and saved to DB. + // Depending on country selected either 'region' (input text) or 'region_id' (selectbox) is visible to user + $regionHtmlName = $element->getName(); + $regionIdHtmlName = str_replace('region', 'region_id', $regionHtmlName); + $regionHtmlId = $element->getHtmlId(); + $regionIdHtmlId = str_replace('region', 'region_id', $regionHtmlId); + if ($regionCollection && $regionCollection->getSize()) { $elementClass = $element->getClass(); - $element->setClass(str_replace('input-text', '', $elementClass)); $html.= ''.$element->getLabelHtml().''; - $html.= 'serialize($htmlAttributes) .'>' . "\n"; foreach ($regionCollection as $region) { - $selected = ($regionId==$region->getId()) ? ' selected="selected"' : ''; - $html.= ''; + $selected = ($regionId == $region->getId()) ? ' selected="selected"' : ''; + $html .= ''; } - $html.= ''; + $html.= '' . "\n"; + + $html .= ''; + + $html.= ''; $element->setClass($elementClass); - } - else { + } else { $element->setClass('input-text'); $html.= ''; $element->setRequired(false); - $html.= 'serialize($htmlAttributes).'/>'."\n"; + $html.= ''; + $html .= 'serialize($htmlAttributes) . "/>" . "\n"; + $html .= ''; + $html .= ''."\n"; } $html.= ''."\n"; return $html; diff --git a/app/code/core/Mage/Adminhtml/Model/Giftmessage/Save.php b/app/code/core/Mage/Adminhtml/Model/Giftmessage/Save.php index b873c05619..b8dfc26866 100644 --- a/app/code/core/Mage/Adminhtml/Model/Giftmessage/Save.php +++ b/app/code/core/Mage/Adminhtml/Model/Giftmessage/Save.php @@ -92,21 +92,21 @@ public function saveAllInOrder() */ protected function _saveOne($entityId, $giftmessage) { $giftmessageModel = Mage::getModel('giftmessage/message'); + $entityType = $this->_getMappedType($giftmessage['type']); - if ($this->_getMappedType($giftmessage['type'])!='quote_item') { - $entityModel = $giftmessageModel->getEntityModelByType($this->_getMappedType($giftmessage['type'])); - } else { - $entityModel = $this->_getQuote()->getItemById($entityId); - } - + switch($entityType) { + case 'quote': + $entityModel = $this->_getQuote(); + break; + case 'quote_item': + $entityModel = $this->_getQuote()->getItemById($entityId); + break; - if ($this->_getMappedType($giftmessage['type'])=='quote') { - $entityModel->setStoreId($this->_getQuote()->getStoreId()); - } - - if ($this->_getMappedType($giftmessage['type'])!='quote_item') { - $entityModel->load($entityId); + default: + $entityModel = $giftmessageModel->getEntityModelByType($entityType) + ->load($entityId); + break; } @@ -122,8 +122,10 @@ protected function _saveOne($entityId, $giftmessage) { $this->_saved = false; } elseif (!$giftmessageModel->isMessageEmpty()) { $giftmessageModel->save(); - $entityModel->setGiftMessageId($giftmessageModel->getId()) - ->save(); + $entityModel->setGiftMessageId($giftmessageModel->getId()); + if($entityType != 'quote') { + $entityModel->save(); + } $this->_saved = true; } diff --git a/app/code/core/Mage/Adminhtml/Model/Observer.php b/app/code/core/Mage/Adminhtml/Model/Observer.php index 48bdd5c0c7..a597842990 100644 --- a/app/code/core/Mage/Adminhtml/Model/Observer.php +++ b/app/code/core/Mage/Adminhtml/Model/Observer.php @@ -65,4 +65,15 @@ public function massactionPrepareKey() } return $this; } + + /** + * Clear result of configuration files access level verification in system cache + * + * @return Mage_Adminhtml_Model_Observer + */ + public function clearCacheConfigurationFilesAccessLevelVerification() + { + Mage::app()->removeCache(Mage_Adminhtml_Block_Notification_Security::VERIFICATION_RESULT_CACHE_KEY); + return $this; + } } diff --git a/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php b/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php index ba8ace1d9b..13c87f248d 100644 --- a/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php +++ b/app/code/core/Mage/Adminhtml/Model/Sales/Order/Create.php @@ -24,9 +24,12 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ + /** * Order create model * + * @category Mage + * @package Mage_Adminhtml * @author Magento Core Team */ class Mage_Adminhtml_Model_Sales_Order_Create extends Varien_Object @@ -44,21 +47,97 @@ class Mage_Adminhtml_Model_Sales_Order_Create extends Varien_Object * @var Mage_Wishlist_Model_Wishlist */ protected $_wishlist; + + /** + * Sales Quote instance + * + * @var Mage_Sales_Model_Quote + */ protected $_cart; + + /** + * Catalog Compare List instance + * + * @var Mage_Catalog_Model_Product_Compare_List + */ protected $_compareList; + /** + * Re-collect quote flag + * + * @var boolean + */ protected $_needCollect; /** + * Re-collect cart flag + * + * @var boolean + */ + protected $_needCollectCart = false; + + /** + * Collect (import) data and validate it flag + * + * @var boolean + */ + protected $_isValidate = false; + + /** + * Customer instance + * * @var Mage_Customer_Model_Customer */ protected $_customer; + /** + * Customer Address Form instance + * + * @var Mage_Customer_Model_Form + */ + protected $_customerAddressForm; + + /** + * Customer Form instance + * + * @var Mage_Customer_Model_Form + */ + protected $_customerForm; + + /** + * Array of validate errors + * + * @var array + */ + protected $_errors = array(); + public function __construct() { $this->_session = Mage::getSingleton('adminhtml/session_quote'); } + /** + * Set validate data in import data flag + * + * @param boolean $flag + * @return Mage_Adminhtml_Model_Sales_Order_Create + */ + public function setIsValidate($flag) + { + $this->_isValidate = (bool)$flag; + return $this; + } + + /** + * Return is validate data in import flag + * + * @return boolean + */ + public function getIsValidate() + { + return $this->_isValidate; + } + /** * Retrieve quote item * @@ -77,7 +156,7 @@ protected function _getQuoteItem($item) } /** - * Initialize data for prise rules + * Initialize data for price rules * * @return Mage_Adminhtml_Model_Sales_Order_Create */ @@ -117,6 +196,7 @@ public function saveQuote() if ($this->_needCollect) { $this->getQuote()->collectTotals(); } + $this->getQuote()->save(); return $this; } @@ -167,6 +247,11 @@ public function initFromOrder(Mage_Sales_Model_Order $order) $this->getSession()->setStoreId($order->getStoreId()); + /** + * Initialize catalog rule data with new session values + */ + $this->initRuleData(); + foreach ($order->getItemsCollection( array_keys(Mage::getConfig()->getNode('adminhtml/sales/order/create/available_product_types')->asArray()), true @@ -420,12 +505,16 @@ public function moveQuoteItem($item, $moveTo, $qty) $product->setSkipCheckRequiredOption(true); $newItem = $this->getQuote()->addProduct($product, $info); + + $this->removeItem($item->getId(), 'cart'); + if (is_string($newItem)) { Mage::throwException($newItem); } $product->unsSkipCheckRequiredOption(); $newItem->checkData(); $newItem->setQty($qty); + $this->_needCollectCart = true; break; case 'cart': if (($cart = $this->getCustomerCart()) && is_null($item->getOptionByCode('additional_options'))) { @@ -440,6 +529,7 @@ public function moveQuoteItem($item, $moveTo, $qty) $info = new Varien_Object( unserialize($info->getValue()) ); + $info->setQty($qty); $info->setOptions($this->_prepareOptionsForRequest($item)); } else { $info = new Varien_Object(array( @@ -454,10 +544,8 @@ public function moveQuoteItem($item, $moveTo, $qty) Mage::throwException($cartItem); } $product->unsSkipCheckRequiredOption(); - $cartItem->setQty($qty); $cartItem->setPrice($item->getProduct()->getPrice()); - $cart->collectTotals() - ->save(); + $this->_needCollectCart = true; } break; case 'wishlist': @@ -502,7 +590,7 @@ public function applySidebarData($data) if ($infobuyRequest === null || !in_array($infobuyRequest->getValue(), $infoBuyRequests)) { $this->moveQuoteItem($item, 'order', $qty); } -// $this->removeItem($itemId, 'cart'); + $this->removeItem($itemId, 'cart'); } } } @@ -697,6 +785,11 @@ public function updateQuoteItems($data) $this->moveQuoteItem($itemId, $info['action'], $itemQty); } } + if ($this->_needCollectCart === true) { + $this->getCustomerCart() + ->collectTotals() + ->save(); + } $this->setRecollect(true); } return $this; @@ -720,6 +813,9 @@ protected function _parseOptions(Mage_Sales_Model_Quote_Item $item, $additionalO foreach (explode("\n", $additionalOptions) as $_additionalOption) { if (strlen(trim($_additionalOption))) { try { + if (strpos($_additionalOption, ':') === false) { + Mage::throwException(Mage::helper('adminhtml')->__('There is an error in one of the option rows.')); + } list($label,$value) = explode(':', $_additionalOption, 2); } catch (Exception $e) { Mage::throwException(Mage::helper('adminhtml')->__('There is an error in one of the option rows.')); @@ -727,7 +823,6 @@ protected function _parseOptions(Mage_Sales_Model_Quote_Item $item, $additionalO $label = trim($label); $value = trim($value); if (empty($value)) { - die($label); continue; } @@ -855,12 +950,94 @@ public function getShippingAddress() return $this->getQuote()->getShippingAddress(); } + /** + * Return Customer (Checkout) Form instance + * + * @return Mage_Customer_Model_Form + */ + protected function _getCustomerForm() + { + if (is_null($this->_customerForm)) { + $this->_customerForm = Mage::getModel('customer/form') + ->setFormCode('adminhtml_checkout') + ->ignoreInvisible(false); + } + return $this->_customerForm; + } + + /** + * Return Customer Address Form instance + * + * @return Mage_Customer_Model_Form + */ + protected function _getCustomerAddressForm() + { + if (is_null($this->_customerAddressForm)) { + $this->_customerAddressForm = Mage::getModel('customer/form') + ->setFormCode('adminhtml_customer_address') + ->ignoreInvisible(false); + } + return $this->_customerAddressForm; + } + + /** + * Set and validate Quote address + * All errors added to _errors + * + * @param Mage_Sales_Model_Quote_Address $address + * @param array $data + * @return Mage_Adminhtml_Model_Sales_Order_Create + */ + protected function _setQuoteAddress(Mage_Sales_Model_Quote_Address $address, array $data) + { + $addressForm = $this->_getCustomerAddressForm() + ->setEntity($address) + ->setEntityType(Mage::getSingleton('eav/config')->getEntityType('customer_address')) + ->setIsAjaxRequest(!$this->getIsValidate()); + + // prepare request + // save original request structure for files + if ($address->getAddressType() == Mage_Sales_Model_Quote_Address::TYPE_SHIPPING) { + $requestData = array('order' => array('shipping_address' => $data)); + $requestScope = 'order/shipping_address'; + } else { + $requestData = array('order' => array('billing_address' => $data)); + $requestScope = 'order/billing_address'; + } + $request = $addressForm->prepareRequest($requestData); + $addressData = $addressForm->extractData($request, $requestScope); + if ($this->getIsValidate()) { + $errors = $addressForm->validateData($addressData); + if ($errors !== true) { + if ($address->getAddressType() == Mage_Sales_Model_Quote_Address::TYPE_SHIPPING) { + $typeName = Mage::helper('adminhtml')->__('Shipping Address: '); + } else { + $typeName = Mage::helper('adminhtml')->__('Billing Address: '); + } + foreach ($errors as $error) { + $this->_errors[] = $typeName . $error; + } + $addressForm->restoreData($addressData); + } else { + $addressForm->compactData($addressData); + } + } else { + $addressForm->restoreData($addressData); + } + + return $this; + } + public function setShippingAddress($address) { if (is_array($address)) { $address['save_in_address_book'] = isset($address['save_in_address_book']) ? (empty($address['save_in_address_book']) ? 0 : 1) : 0; $shippingAddress = Mage::getModel('sales/quote_address') - ->setData($address); + ->setData($address) + ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_SHIPPING); + if (!$this->getQuote()->isVirtual()) { + $this->_setQuoteAddress($shippingAddress, $address); + } $shippingAddress->implodeStreetAddress(); } if ($address instanceof Mage_Sales_Model_Quote_Address) { @@ -900,7 +1077,9 @@ public function setBillingAddress($address) if (is_array($address)) { $address['save_in_address_book'] = isset($address['save_in_address_book']) ? 1 : 0; $billingAddress = Mage::getModel('sales/quote_address') - ->setData($address); + ->setData($address) + ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_BILLING); + $this->_setQuoteAddress($billingAddress, $address); $billingAddress->implodeStreetAddress(); } @@ -970,9 +1149,19 @@ public function applyCoupon($code) public function setAccountData($accountData) { + $customer = $this->getQuote()->getCustomer(); + $form = $this->_getCustomerForm(); + $form->setEntity($customer); + + // emulate request + $request = $form->prepareRequest($accountData); + $data = $form->extractData($request); + $form->restoreData($data); + $data = array(); - foreach ($accountData as $key => $value) { - $data['customer_'.$key] = $value; + foreach ($form->getAttributes() as $attribute) { + $code = sprintf('customer_%s', $attribute->getAttributeCode()); + $data[$code] = $customer->getData($attribute->getAttributeCode()); } if (isset($data['customer_group_id'])) { @@ -1050,6 +1239,37 @@ protected function _customerIsInStore($store) return $customer->isInStore($store); } + /** + * Set and validate Customer data + * + * @param Mage_Customer_Model_Customer $customer + * @return Mage_Adminhtml_Model_Sales_Order_Create + */ + protected function _setCustomerData(Mage_Customer_Model_Customer $customer) + { + $form = $this->_getCustomerForm(); + $form->setEntity($customer); + + // emulate request + $request = $form->prepareRequest(array('order' => $this->getData())); + $data = $form->extractData($request, 'order/account'); + if ($this->getIsValidate()) { + $errors = $form->validateData($data); + if ($errors !== true) { + foreach ($errors as $error) { + $this->_errors[] = $error; + } + $form->restoreData($data); + } else { + $form->compactData($data); + } + } else { + $form->restoreData($data); + } + + return $this; + } + /** * Prepare quote customer */ @@ -1065,8 +1285,6 @@ public function _prepareCustomer() $billingAddress = null; $shippingAddress = null; - $customer->addData($this->_getData('account')); - if ($customer->getId()) { if (!$this->_customerIsInStore($store)) { $customer->setId(null) @@ -1074,6 +1292,7 @@ public function _prepareCustomer() ->setDefaultBilling(null) ->setDefaultShipping(null) ->setPassword($customer->generatePassword()); + $this->_setCustomerData($customer); } if ($this->getBillingAddress()->getSaveInAddressBook()) { $billingAddress = $this->getBillingAddress()->exportCustomerAddress(); @@ -1109,8 +1328,9 @@ public function _prepareCustomer() } else { $customer->addData($this->getBillingAddress()->exportCustomerAddress()->getData()) ->setPassword($customer->generatePassword()) - ->setStore($store) - ->setEmail($this->_getNewCustomerEmail($customer)); + ->setStore($store); + $customer->setEmail($this->_getNewCustomerEmail($customer)); + $this->_setCustomerData($customer); $customerBilling = $this->getBillingAddress()->exportCustomerAddress(); $customerBilling->setIsDefaultBilling(true); @@ -1125,16 +1345,27 @@ public function _prepareCustomer() $customerBilling->setIsDefaultShipping(true); } } + + // set quote customer data to customer + $this->_setCustomerData($customer); + + // set customer to quote and convert customer data to quote $quote->setCustomer($customer); - if (!$customer->getId()) { - $quote->setCustomerId(true); + + // add user defined attributes to quote + $form = $this->_getCustomerForm()->setEntity($customer); + foreach ($form->getUserAttributes() as $attribute) { + $quoteCode = sprintf('customer_%s', $attribute->getAttributeCode()); + $quote->setData($quoteCode, $customer->getData($attribute->getAttributeCode())); } - // we should not change account data for existing customer, so restore it - if ($customer->getId() && is_array($this->_getData('account'))) { - foreach($this->_getData('account') as $key => $value) { - $customer->setData($key, $customer->getOrigData($key)); - } + if ($customer->getId()) { + // we should not change account data for existing customer, so restore it + $this->_getCustomerForm() + ->setEntity($customer) + ->resetEntityData(); + } else { + $quote->setCustomerId(true); } return $this; @@ -1168,15 +1399,14 @@ protected function _prepareQuoteItems() */ public function createOrder() { + $this->_prepareCustomer(); $this->_validate(); $quote = $this->getQuote(); - $this->_prepareCustomer(); $this->_prepareQuoteItems(); if (! $quote->getCustomer()->getId() || ! $quote->getCustomer()->isInStore($this->getSession()->getStore())) { $quote->getCustomer()->sendNewAccountEmail('registered', '', $quote->getStoreId()); } - $service = Mage::getModel('sales/service_quote', $quote); if ($this->getSession()->getOrder()->getId()) { $oldOrder = $this->getSession()->getOrder(); @@ -1191,8 +1421,12 @@ public function createOrder() $quote->setReservedOrderId($orderData['increment_id']); $service->setOrderData($orderData); } - $order = $service->submit(); + $order = $service->submit(); + if (!$quote->getCustomer()->getId() || !$quote->getCustomer()->isInStore($this->getSession()->getStore())) { + $quote->getCustomer()->setCreatedAt($order->getCreatedAt()); + $quote->getCustomer()->save(); + } if ($this->getSession()->getOrder()->getId()) { $oldOrder = $this->getSession()->getOrder(); @@ -1202,11 +1436,9 @@ public function createOrder() ->save(); $order->save(); } - if ($this->getSendConfirmation()) { $order->sendNewOrderEmail(); } - Mage::dispatchEvent('checkout_submit_all_after', array('order' => $order, 'quote' => $quote)); return $order; @@ -1229,38 +1461,37 @@ protected function _validate() } $items = $this->getQuote()->getAllItems(); - $errors = array(); if (count($items) == 0) { - $errors[] = Mage::helper('adminhtml')->__('You need to specify order items.'); + $this->_errors[] = Mage::helper('adminhtml')->__('You need to specify order items.'); } if (!$this->getQuote()->isVirtual()) { if (!$this->getQuote()->getShippingAddress()->getShippingMethod()) { - $errors[] = Mage::helper('adminhtml')->__('Shipping method must be specified.'); + $this->_errors[] = Mage::helper('adminhtml')->__('Shipping method must be specified.'); } } if (!$this->getQuote()->getPayment()->getMethod()) { - $errors[] = Mage::helper('adminhtml')->__('Payment method must be specified.'); + $this->_errors[] = Mage::helper('adminhtml')->__('Payment method must be specified.'); } else { $method = $this->getQuote()->getPayment()->getMethodInstance(); if (!$method) { - $errors[] = Mage::helper('adminhtml')->__('Payment method instance is not available.'); + $this->_errors[] = Mage::helper('adminhtml')->__('Payment method instance is not available.'); } else { if (!$method->isAvailable($this->getQuote())) { - $errors[] = Mage::helper('adminhtml')->__('Payment method is not available.'); + $this->_errors[] = Mage::helper('adminhtml')->__('Payment method is not available.'); } else { try { $method->validate(); } catch (Mage_Core_Exception $e) { - $errors[] = $e->getMessage(); + $this->_errors[] = $e->getMessage(); } } } } - if (!empty($errors)) { - foreach ($errors as $error) { + if (!empty($this->_errors)) { + foreach ($this->_errors as $error) { $this->getSession()->addError($error); } Mage::throwException(''); @@ -1281,6 +1512,9 @@ protected function _getNewCustomerEmail($customer) $host = $this->getSession()->getStore()->getConfig(Mage_Customer_Model_Customer::XML_PATH_DEFAULT_EMAIL_DOMAIN); $account = $customer->getIncrementId() ? $customer->getIncrementId() : time(); $email = $account.'@'. $host; + $account = $this->getData('account'); + $account['email'] = $email; + $this->setData('account', $account); } return $email; } diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Address/Street.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Address/Street.php new file mode 100644 index 0000000000..b6947f0ebe --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Address/Street.php @@ -0,0 +1,83 @@ + + */ +class Mage_Adminhtml_Model_System_Config_Backend_Customer_Address_Street extends Mage_Core_Model_Config_Data +{ + /** + * Actions after save + * + * @return Mage_Adminhtml_Model_System_Config_Backend_Customer_Address_Street + */ + protected function _afterSave() + { + $attribute = Mage::getSingleton('eav/config')->getAttribute('customer_address', 'street'); + $value = $this->getValue(); + switch ($this->getScope()) { + case 'websites': + $website = Mage::app()->getWebsite($this->getWebsiteCode()); + $attribute->setWebsite($website); + $attribute->load($attribute->getId()); + if ($attribute->getData('multiline_count') != $value) { + $attribute->setData('scope_multiline_count', $value); + } + break; + + case 'default': + $attribute->setData('multiline_count', $value); + break; + } + $attribute->save(); + return $this; + } + + /** + * Processing object after delete data + * + * @return Mage_Core_Model_Abstract + */ + protected function _afterDelete() + { + $result = parent::_afterDelete(); + + if ($this->getScope() == 'websites') { + $attribute = Mage::getSingleton('eav/config')->getAttribute('customer_address', 'street'); + $website = Mage::app()->getWebsite($this->getWebsiteCode()); + $attribute->setWebsite($website); + $attribute->load($attribute->getId()); + $attribute->setData('scope_multiline_count', null); + $attribute->save(); + } + + return $result; + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Address.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Address.php new file mode 100644 index 0000000000..5a04e135df --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Address.php @@ -0,0 +1,48 @@ + + */ +class Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Address + extends Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Customer +{ + /** + * Retrieve attribute objects + * + * @return array + */ + protected function _getAttributeObjects() + { + $result = parent::_getAttributeObjects(); + $result[] = Mage::getSingleton('eav/config')->getAttribute('customer_address', $this->_getAttributeCode()); + return $result; + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Customer.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Customer.php new file mode 100644 index 0000000000..4b70a22801 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Customer/Show/Customer.php @@ -0,0 +1,124 @@ + + */ +class Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Customer extends Mage_Core_Model_Config_Data +{ + /** + * Retrieve attribute code + * + * @return string + */ + protected function _getAttributeCode() + { + return str_replace('_show', '', $this->getField()); + } + + /** + * Retrieve attribute objects + * + * @return array + */ + protected function _getAttributeObjects() + { + return array( + Mage::getSingleton('eav/config')->getAttribute('customer', $this->_getAttributeCode()) + ); + } + + /** + * Actions after save + * + * @return Mage_Adminhtml_Model_System_Config_Backend_Customer_Show_Customer + */ + protected function _afterSave() + { + $result = parent::_afterSave(); + + $valueConfig = array( + '' => array('is_required' => 0, 'is_visible' => 0), + 'opt' => array('is_required' => 0, 'is_visible' => 1), + '1' => array('is_required' => 0, 'is_visible' => 1), + 'req' => array('is_required' => 1, 'is_visible' => 1), + ); + + $value = $this->getValue(); + if (isset($valueConfig[$value])) { + $data = $valueConfig[$value]; + } else { + $data = $valueConfig['']; + } + + if ($this->getScope() == 'websites') { + $website = Mage::app()->getWebsite($this->getWebsiteCode()); + $dataFieldPrefix = 'scope_'; + } else { + $website = null; + $dataFieldPrefix = ''; + } + + foreach ($this->_getAttributeObjects() as $attributeObject) { + if ($website) { + $attributeObject->setWebsite($website); + $attributeObject->load($attributeObject->getId()); + } + $attributeObject->setData($dataFieldPrefix . 'is_required', $data['is_required']); + $attributeObject->setData($dataFieldPrefix . 'is_visible', $data['is_visible']); + $attributeObject->save(); + } + + return $result; + } + + /** + * Processing object after delete data + * + * @return Mage_Core_Model_Abstract + */ + protected function _afterDelete() + { + $result = parent::_afterDelete(); + + if ($this->getScope() == 'websites') { + $website = Mage::app()->getWebsite($this->getWebsiteCode()); + foreach ($this->_getAttributeObjects() as $attributeObject) { + $attributeObject->setWebsite($website); + $attributeObject->load($attributeObject->getId()); + $attributeObject->setData('scope_is_required', null); + $attributeObject->setData('scope_is_visible', null); + $attributeObject->save(); + } + } + + return $result; + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image.php index 8eb4c4b42f..92cabc930c 100644 --- a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image.php +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image.php @@ -49,32 +49,7 @@ protected function _beforeSave() if ($_FILES['groups']['tmp_name'][$this->getGroupId()]['fields'][$this->getField()]['value']){ - $fieldConfig = $this->getFieldConfig(); - /* @var $fieldConfig Varien_Simplexml_Element */ - - if (empty($fieldConfig->upload_dir)) { - Mage::throwException(Mage::helper('catalog')->__('The base directory to upload image file is not specified.')); - } - - $uploadDir = (string)$fieldConfig->upload_dir; - - $el = $fieldConfig->descend('upload_dir'); - - /** - * Add scope info - */ - if (!empty($el['scope_info'])) { - $uploadDir = $this->_appendScopeInfo($uploadDir); - } - - /** - * Take root from config - */ - if (!empty($el['config'])) { - $uploadRoot = (string)Mage::getConfig()->getNode((string)$el['config'], $this->getScope(), $this->getScopeId()); - $uploadRoot = Mage::getConfig()->substDistroServerVars($uploadRoot); - $uploadDir = $uploadRoot . '/' . $uploadDir; - } + $uploadDir = $this->_getUploadDir(); try { $file = array(); @@ -90,14 +65,9 @@ protected function _beforeSave() } if ($filename = $uploader->getUploadedFileName()) { - - /** - * Add scope info - */ - if (!empty($el['scope_info'])) { + if ($this->_addWhetherScopeInfo()) { $filename = $this->_prependScopeInfo($filename); } - $this->setValue($filename); } } @@ -105,6 +75,67 @@ protected function _beforeSave() return $this; } + /** + * Makes a decision about whether to add info about the scope. + * + * @return boolean + */ + protected function _addWhetherScopeInfo() + { + $fieldConfig = $this->getFieldConfig(); + $el = $fieldConfig->descend('upload_dir'); + return (!empty($el['scope_info'])); + } + + /** + * Return path to directory for upload file + * + * @return string + * @throw Mage_Core_Exception + */ + protected function _getUploadDir() + { + $fieldConfig = $this->getFieldConfig(); + /* @var $fieldConfig Varien_Simplexml_Element */ + + if (empty($fieldConfig->upload_dir)) { + Mage::throwException(Mage::helper('catalog')->__('The base directory to upload image file is not specified.')); + } + + $uploadDir = (string)$fieldConfig->upload_dir; + + $el = $fieldConfig->descend('upload_dir'); + + /** + * Add scope info + */ + if (!empty($el['scope_info'])) { + $uploadDir = $this->_appendScopeInfo($uploadDir); + } + + /** + * Take root from config + */ + if (!empty($el['config'])) { + $uploadRoot = $this->_getUploadRoot((string)$el['config']); + $uploadDir = $uploadRoot . '/' . $uploadDir; + } + return $uploadDir; + } + + /** + * Return the root part of directory path for uploading + * + * @var string + * @return string + */ + protected function _getUploadRoot($token) + { + $uploadRoot = (string)Mage::getConfig()->getNode($token, $this->getScope(), $this->getScopeId()); + $uploadRoot = Mage::getConfig()->substDistroServerVars($uploadRoot); + return $uploadRoot; + } + /** * Prepend path with scope info * @@ -144,3 +175,4 @@ protected function _getAllowedExtensions() return array('jpg', 'jpeg', 'gif', 'png'); } } + diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image/Favicon.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image/Favicon.php new file mode 100644 index 0000000000..9ce363b925 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Image/Favicon.php @@ -0,0 +1,82 @@ + + */ +class Mage_Adminhtml_Model_System_Config_Backend_Image_Favicon extends Mage_Adminhtml_Model_System_Config_Backend_Image +{ + /** + * The tail part of directory path for uploading + * + */ + const UPLOAD_DIR = 'favicon'; + + /** + * Token for the root part of directory path for uploading + * + */ + const UPLOAD_ROOT = 'system/filesystem/media'; + + /** + * Return path to directory for upload file + * + * @return string + * @throw Mage_Core_Exception + */ + protected function _getUploadDir() + { + $uploadDir = $this->_appendScopeInfo(self::UPLOAD_DIR); + $uploadRoot = $this->_getUploadRoot(self::UPLOAD_ROOT); + $uploadDir = $uploadRoot . '/' . $uploadDir; + return $uploadDir; + } + + /** + * Makes a decision about whether to add info about the scope. + * + * @return boolean + */ + protected function _addWhetherScopeInfo() + { + return true; + } + + /** + * Getter for allowed extensions of uploaded files. + * + * @return array + */ + protected function _getAllowedExtensions() + { + return array('ico', 'png', 'gif', 'jpeg', 'apng', 'svg'); + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Secure.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Secure.php new file mode 100644 index 0000000000..67e492c2b1 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Secure.php @@ -0,0 +1,39 @@ +isValueChanged()) { + Mage::getModel('core/design_package')->cleanMergedJsCss(); + } + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Serialized.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Serialized.php index 8a015313e9..20251059a7 100644 --- a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Serialized.php +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Serialized.php @@ -29,7 +29,8 @@ class Mage_Adminhtml_Model_System_Config_Backend_Serialized extends Mage_Core_Mo protected function _afterLoad() { if (!is_array($this->getValue())) { - $this->setValue(unserialize($this->getValue())); + $value = $this->getValue(); + $this->setValue(empty($value) ? false : unserialize($value)); } } diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Price/Step.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Price/Step.php new file mode 100644 index 0000000000..401f93c42b --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Price/Step.php @@ -0,0 +1,42 @@ + Mage_Catalog_Model_Layer_Filter_Price::RANGE_CALCULATION_AUTO, + 'label' => Mage::helper('adminhtml')->__('Automatic') + ), + array( + 'value' => Mage_Catalog_Model_Layer_Filter_Price::RANGE_CALCULATION_MANUAL, + 'label' => Mage::helper('adminhtml')->__('Manual') + ), + ); + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Shipping/Allowedmethods.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Shipping/Allowedmethods.php index 54f559912f..a074b49544 100644 --- a/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Shipping/Allowedmethods.php +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Shipping/Allowedmethods.php @@ -30,9 +30,6 @@ class Mage_Adminhtml_Model_System_Config_Source_Shipping_Allowedmethods extends Mage_Adminhtml_Model_System_Config_Source_Shipping_Allmethods { - public function toOptionArray() - { - return parent::toOptionArray(true); - } + } diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Web/Redirect.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Web/Redirect.php new file mode 100644 index 0000000000..7812730b21 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Source/Web/Redirect.php @@ -0,0 +1,38 @@ + 0, 'label'=>Mage::helper('adminhtml')->__('No')), + array('value' => 1, 'label'=>Mage::helper('adminhtml')->__('Yes (302 Found)')), + array('value' => 301, 'label'=>Mage::helper('adminhtml')->__('Yes (301 Moved Permanently)')), + ); + } + +} diff --git a/app/code/core/Mage/Adminhtml/controllers/CacheController.php b/app/code/core/Mage/Adminhtml/controllers/CacheController.php index 98769b5ff6..907b36f5fa 100644 --- a/app/code/core/Mage/Adminhtml/controllers/CacheController.php +++ b/app/code/core/Mage/Adminhtml/controllers/CacheController.php @@ -187,6 +187,6 @@ public function cleanImagesAction() */ protected function _isAllowed() { - return Mage::getSingleton('admin/session')->isAllowed('cache'); + return Mage::getSingleton('admin/session')->isAllowed('system/cache'); } } diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php index 767c885268..b571f19187 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/CategoryController.php @@ -272,14 +272,6 @@ public function saveAction() $parentCategory = Mage::getModel('catalog/category')->load($parentId); $category->setPath($parentCategory->getPath()); } - /** - * Check "Use Default Value" checkboxes values - */ - if ($useDefaults = $this->getRequest()->getPost('use_default')) { - foreach ($useDefaults as $attributeCode) { - $category->setData($attributeCode, false); - } - } /** * Process "Use Config Settings" checkboxes @@ -313,7 +305,39 @@ public function saveAction() 'request' => $this->getRequest() )); + /** + * Proceed with $_POST['use_config'] + * set into category model for proccessing through validation + */ + $category->setData("use_post_data_config", $this->getRequest()->getPost('use_config')); + try { + $validate = $category->validate(); + if ($validate !== true) { + foreach ($validate as $code => $error) { + if ($error === true) { + Mage::throwException(Mage::helper('catalog')->__('Attribute "%s" is required.', $category->getResource()->getAttribute($code)->getFrontend()->getLabel())); + } + else { + Mage::throwException($error); + } + } + } + + /** + * Check "Use Default Value" checkboxes values + */ + if ($useDefaults = $this->getRequest()->getPost('use_default')) { + foreach ($useDefaults as $attributeCode) { + $category->setData($attributeCode, false); + } + } + + /** + * Unset $_POST['use_config'] before save + */ + $category->unsetData('use_post_data_config'); + $category->save(); Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('catalog')->__('The category has been saved.')); $refreshTree = 'true'; diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/Action/AttributeController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/Action/AttributeController.php index 614b3023b3..4dd9e3c8ef 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/Action/AttributeController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/Action/AttributeController.php @@ -95,6 +95,11 @@ public function saveAction() $value = null; } $attributesData[$attributeCode] = $value; + } else if ($attribute->getFrontendInput() == 'multiselect') { + if (is_array($value)) { + $value = implode(',', $value); + } + $attributesData[$attributeCode] = $value; } } diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php index 9ca06779f8..d5b398af4c 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/Product/AttributeController.php @@ -78,7 +78,6 @@ public function editAction() $id = $this->getRequest()->getParam('attribute_id'); $model = Mage::getModel('catalog/resource_eav_attribute') ->setEntityTypeId($this->_entityTypeId); - if ($id) { $model->load($id); @@ -108,15 +107,15 @@ public function editAction() $this->_title($id ? $model->getName() : $this->__('New Attribute')); - $this->_addBreadcrumb($id ? Mage::helper('catalog')->__('Edit Product Attribute') : Mage::helper('catalog')->__('New Product Attribute'), $id ? Mage::helper('catalog')->__('Edit Product Attribute') : Mage::helper('catalog')->__('New Product Attribute')) - ->_addContent($this->getLayout()->createBlock('adminhtml/catalog_product_attribute_edit')->setData('action', $this->getUrl('*/catalog_product_attribute/save'))) - ->_addLeft($this->getLayout()->createBlock('adminhtml/catalog_product_attribute_edit_tabs')) - ->_addJs( - $this->getLayout()->createBlock('adminhtml/template') - ->setIsPopup((bool)$this->getRequest()->getParam('popup')) - ->setTemplate('catalog/product/attribute/js.phtml') - ) - ->renderLayout(); + $item = $id ? Mage::helper('catalog')->__('Edit Product Attribute') : Mage::helper('catalog')->__('New Product Attribute'); + + $this->_addBreadcrumb($item, $item); + + $this->getLayout()->getBlock('attribute_edit_js') + ->setIsPopup((bool)$this->getRequest()->getParam('popup')); + + $this->renderLayout(); + } public function validateAction() @@ -143,11 +142,12 @@ public function saveAction() { if ($data = $this->getRequest()->getPost()) { $redirectBack = $this->getRequest()->getParam('back', false); - $model = Mage::getModel('catalog/resource_eav_attribute'); /* @var $model Mage_Catalog_Model_Entity_Attribute */ + $model = Mage::getModel('catalog/resource_eav_attribute'); + /* @var $helper Mage_Catalog_Helper_Product */ + $helper = Mage::helper('catalog/product'); if ($id = $this->getRequest()->getParam('attribute_id')) { - $model->load($id); if (!$model->getId()) { @@ -167,6 +167,12 @@ public function saveAction() $data['attribute_code'] = $model->getAttributeCode(); $data['is_user_defined'] = $model->getIsUserDefined(); $data['frontend_input'] = $model->getFrontendInput(); + } else { + /** + * @todo add to helper and specify all relations for properties + */ + $data['source_model'] = $helper->getAttributeSourceModelByInputType($data['frontend_input']); + $data['backend_model'] = $helper->getAttributeBackendModelByInputType($data['frontend_input']); } if (!isset($data['is_configurable'])) { @@ -192,16 +198,8 @@ public function saveAction() $data['apply_to'] = array(); } - /** - * @todo need specify relations for properties - */ - if (isset($data['frontend_input']) && $data['frontend_input'] == 'multiselect') { - $data['backend_model'] = 'eav/entity_attribute_backend_array'; - } - $model->addData($data); - if (!$id) { $model->setEntityTypeId($this->_entityTypeId); $model->setIsUserDefined(1); diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php index e89b950a1e..e8f683fd7b 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php @@ -474,6 +474,7 @@ public function validateAction() try { $productData = $this->getRequest()->getPost('product'); + if ($productData && !isset($productData['stock_data']['use_config_manage_stock'])) { $productData['stock_data']['use_config_manage_stock'] = 0; } @@ -491,6 +492,18 @@ public function validateAction() if ($productId = $this->getRequest()->getParam('id')) { $product->load($productId); } + + $dateFields = array(); + $attributes = $product->getAttributes(); + foreach ($attributes as $attrKey => $attribute) { + if ($attribute->getBackend()->getType() == 'datetime') { + if (array_key_exists($attrKey, $productData) && $productData[$attrKey] != ''){ + $dateFields[] = $attrKey; + } + } + } + $productData = $this->_filterDates($productData, $dateFields); + $product->addData($productData); $product->validate(); /** @@ -712,8 +725,7 @@ public function saveAction() */ public function duplicateAction() { - $productId = (int) $this->getRequest()->getParam('id'); - $product = Mage::getModel('catalog/product')->load($productId); + $product = $this->_initProduct(); try { $newProduct = $product->duplicate(); $this->_getSession()->addSuccess($this->__('The product has been duplicated.')); @@ -869,6 +881,7 @@ public function massStatusAction() $status = (int)$this->getRequest()->getParam('status'); try { + $this->_validateMassStatus($productIds, $status); Mage::getSingleton('catalog/product_action') ->updateAttributes($productIds, array('status' => $status), $storeId); @@ -879,6 +892,9 @@ public function massStatusAction() catch (Mage_Core_Model_Exception $e) { $this->_getSession()->addError($e->getMessage()); } + catch (Mage_Core_Exception $e) { + $this->_getSession()->addError($e->getMessage()); + } catch (Exception $e) { $this->_getSession()->addException($e, $this->__('An error occurred while updating the product(s) status.')); } @@ -886,6 +902,23 @@ public function massStatusAction() $this->_redirect('*/*/', array('store'=> $storeId)); } + /** + * Validate batch of products before theirs status will be set + * + * @throws Mage_Core_Exception + * @param array $productIds + * @param int $status + * @return void + */ + public function _validateMassStatus(array $productIds, $status) + { + if ($status == Mage_Catalog_Model_Product_Status::STATUS_ENABLED) { + if (!Mage::getModel('catalog/product')->isProductsHasSku($productIds)) { + throw new Mage_Core_Exception($this->__('Some of the processed products have no SKU value. Please fill it.')); + } + } + } + /** * Get tag customer grid * diff --git a/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php b/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php index 82c4bf5eba..c8d97a3891 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Catalog/SearchController.php @@ -75,20 +75,19 @@ public function editAction() Mage::register('current_catalog_search', $model); - $block = $this->getLayout()->createBlock('adminhtml/catalog_search_edit') - ->setData('action', $this->getUrl('*/catalog_search/save')); - $this->_initAction(); $this->_title($id ? $model->getQueryText() : $this->__('New Search')); $this->getLayout()->getBlock('head')->setCanLoadRulesJs(true); + $this->getLayout()->getBlock('catalog_search_edit') + ->setData('action', $this->getUrl('*/catalog_search/save')); + $this - ->_addBreadcrumb($id ? Mage::helper('catalog')->__('Edit Search') : Mage::helper('catalog')->__('New Search'), $id ? Mage::helper('catalog')->__('Edit Search') : Mage::helper('catalog')->__('New Search')) - ->_addContent($block) - ->renderLayout(); + ->_addBreadcrumb($id ? Mage::helper('catalog')->__('Edit Search') : Mage::helper('catalog')->__('New Search'), $id ? Mage::helper('catalog')->__('Edit Search') : Mage::helper('catalog')->__('New Search')); + $this->renderLayout(); } /** @@ -103,6 +102,7 @@ public function saveAction() if ($this->getRequest()->isPost() && $data) { /* @var $model Mage_CatalogSearch_Model_Query */ $model = Mage::getModel('catalogsearch/query'); + // validate query $queryText = $this->getRequest()->getPost('query_text', false); $storeId = $this->getRequest()->getPost('store_id', false); @@ -125,6 +125,7 @@ public function saveAction() $model->addData($data); $model->setIsProcessed(0); $model->save(); + } catch (Mage_Core_Exception $e) { $this->_getSession()->addError($e->getMessage()); $hasError = true; diff --git a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php index 1f2e04202d..e10ce8b105 100644 --- a/app/code/core/Mage/Adminhtml/controllers/CustomerController.php +++ b/app/code/core/Mage/Adminhtml/controllers/CustomerController.php @@ -97,19 +97,47 @@ public function editAction() $this->_initCustomer(); $this->loadLayout(); + /* @var $customer Mage_Customer_Model_Customer */ $customer = Mage::registry('current_customer'); // set entered data if was error when we do save $data = Mage::getSingleton('adminhtml/session')->getCustomerData(true); - if (isset($data['account'])) { - $customer->addData($data['account']); - } - if (isset($data['address']) && is_array($data['address'])) { - foreach ($data['address'] as $addressId => $address) { - $addressModel = Mage::getModel('customer/address')->setData($address) - ->setId($addressId); - $customer->addAddress($addressModel); + // restore data from SESSION + if ($data) { + $request = clone $this->getRequest(); + $request->setParams($data); + + if (isset($data['account'])) { + /* @var $customerForm Mage_Customer_Model_Form */ + $customerForm = Mage::getModel('customer/form'); + $customerForm->setEntity($customer) + ->setFormCode('adminhtml_customer') + ->setIsAjaxRequest(true); + $formData = $customerForm->extractData($request, 'account'); + $customerForm->restoreData($formData); + } + + if (isset($data['address']) && is_array($data['address'])) { + /* @var $addressForm Mage_Customer_Model_Form */ + $addressForm = Mage::getModel('customer/form'); + $addressForm->setFormCode('adminhtml_customer_address'); + + foreach (array_keys($data['address']) as $addressId) { + if ($addressId == '_template_') { + continue; + } + + $address = $customer->getAddressItemById($addressId); + if (!$address) { + $address = Mage::getModel('customer/address'); + $customer->addAddress($address); + } + + $formData = $addressForm->setEntity($address) + ->extractData($request); + $addressForm->restoreData($formData); + } } } @@ -156,87 +184,138 @@ public function deleteAction() */ public function saveAction() { - if ($data = $this->getRequest()->getPost()) { - $data = $this->_filterPostData($data); + $data = $this->getRequest()->getPost(); + if ($data) { $redirectBack = $this->getRequest()->getParam('back', false); $this->_initCustomer('customer_id'); - /** @var Mage_Customer_Model_Customer */ + + /* @var $customer Mage_Customer_Model_Customer */ $customer = Mage::registry('current_customer'); - // Prepare customer saving data - if (isset($data['account'])) { - if (isset($data['account']['email'])) { - $data['account']['email'] = trim($data['account']['email']); + + /* @var $customerForm Mage_Customer_Model_Form */ + $customerForm = Mage::getModel('customer/form'); + $customerForm->setEntity($customer) + ->setFormCode('adminhtml_customer') + ->ignoreInvisible(false) + ; + + $formData = $customerForm->extractData($this->getRequest(), 'account'); + $errors = $customerForm->validateData($formData); + if ($errors !== true) { + foreach ($errors as $error) { + $this->_getSession()->addError($error); } - $customer->addData($data['account']); + $this->_getSession()->setCustomerData($data); + $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array('id' => $customer->getId()))); + return; } + + $customerForm->compactData($formData); + // unset template data if (isset($data['address']['_template_'])) { unset($data['address']['_template_']); } $modifiedAddresses = array(); + if (!empty($data['address'])) { + /* @var $addressForm Mage_Customer_Model_Form */ + $addressForm = Mage::getModel('customer/form'); + $addressForm->setFormCode('adminhtml_customer_address')->ignoreInvisible(false); + + foreach (array_keys($data['address']) as $index) { + $address = $customer->getAddressItemById($index); + if (!$address) { + $address = Mage::getModel('customer/address'); + } + + $requestScope = sprintf('address/%s', $index); + $formData = $addressForm->setEntity($address) + ->extractData($this->getRequest(), $requestScope); + $errors = $addressForm->validateData($formData); + if ($errors !== true) { + foreach ($errors as $error) { + $this->_getSession()->addError($error); + } + $this->_getSession()->setCustomerData($data); + $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array( + 'id' => $customer->getId()) + )); + return; + } + + $addressForm->compactData($formData); + + // Set post_index for detect default billing and shipping addresses + $address->setPostIndex($index); - if (! empty($data['address'])) { - foreach ($data['address'] as $index => $addressData) { - if (($address = $customer->getAddressItemById($index))) { - $addressId = $index; - $modifiedAddresses[] = $index; + if ($address->getId()) { + $modifiedAddresses[] = $address->getId(); } else { - $address = Mage::getModel('customer/address'); - $addressId = null; $customer->addAddress($address); } - - $address->setData($addressData) - ->setId($addressId) - ->setPostIndex($index); // We need set post_index for detect default addresses } } + + // default billing and shipping + if (isset($data['account']['default_billing'])) { + $customer->setData('default_billing', $data['account']['default_billing']); + } + if (isset($data['account']['default_shipping'])) { + $customer->setData('default_shipping', $data['account']['default_shipping']); + } + // not modified customer addresses mark for delete foreach ($customer->getAddressesCollection() as $customerAddress) { - if ($customerAddress->getId() && ! in_array($customerAddress->getId(), $modifiedAddresses)) { + if ($customerAddress->getId() && !in_array($customerAddress->getId(), $modifiedAddresses)) { $customerAddress->setData('_deleted', true); } } - if(isset($data['subscription'])) { + if (isset($data['subscription'])) { $customer->setIsSubscribed(true); } else { $customer->setIsSubscribed(false); } - $isNewCustomer = !$customer->getId(); - try { - if ($customer->getPassword() == 'auto') { - $sendPassToEmail = true; - $customer->setPassword($customer->generatePassword()); - } + if (isset($data['account']['sendemail_store_id'])) { + $customer->setSendemailStoreId($data['account']['sendemail_store_id']); + } + $isNewCustomer = $customer->isObjectNew(); + try { + $sendPassToEmail = false; // force new customer active if ($isNewCustomer) { + $customer->setPassword($data['account']['password']); $customer->setForceConfirmed(true); + if ($customer->getPassword() == 'auto') { + $sendPassToEmail = true; + $customer->setPassword($customer->generatePassword()); + } } - Mage::dispatchEvent('adminhtml_customer_prepare_save', - array('customer' => $customer, 'request' => $this->getRequest()) - ); + Mage::dispatchEvent('adminhtml_customer_prepare_save', array( + 'customer' => $customer, + 'request' => $this->getRequest() + )); $customer->save(); + // send welcome email - if ($customer->getWebsiteId() && ($customer->hasData('sendemail') || isset($sendPassToEmail))) { + if ($customer->getWebsiteId() && (!empty($data['account']['sendemail']) || $sendPassToEmail)) { $storeId = $customer->getSendemailStoreId(); if ($isNewCustomer) { $customer->sendNewAccountEmail('registered', '', $storeId); } // confirm not confirmed customer - elseif ((!$customer->getConfirmation())) { + else if ((!$customer->getConfirmation())) { $customer->sendNewAccountEmail('confirmed', '', $storeId); } } - // TODO? Send confirmation link, if deactivating account - - if ($newPassword = $customer->getNewPassword()) { + if (!empty($data['account']['new_password'])) { + $newPassword = $data['account']['new_password']; if ($newPassword == 'auto') { $newPassword = $customer->generatePassword(); } @@ -244,10 +323,13 @@ public function saveAction() $customer->sendPasswordReminderEmail(); } - Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('The customer has been saved.')); - Mage::dispatchEvent('adminhtml_customer_save_after', - array('customer' => $customer, 'request' => $this->getRequest()) + Mage::getSingleton('adminhtml/session')->addSuccess( + Mage::helper('adminhtml')->__('The customer has been saved.') ); + Mage::dispatchEvent('adminhtml_customer_save_after', array( + 'customer' => $customer, + 'request' => $this->getRequest() + )); if ($redirectBack) { $this->_redirect('*/*/edit', array( @@ -256,10 +338,14 @@ public function saveAction() )); return; } - } - catch (Exception $e){ - Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); - Mage::getSingleton('adminhtml/session')->setCustomerData($data); + } catch (Mage_Core_Exception $e) { + $this->_getSession()->addError($e->getMessage()); + $this->_getSession()->setCustomerData($data); + $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array('id' => $customer->getId()))); + } catch (Exception $e) { + $this->_getSession()->addException($e, + Mage::helper('adminhtml')->__('An error occurred while saving the customer.')); + $this->_getSession()->setCustomerData($data); $this->getResponse()->setRedirect($this->getUrl('*/customer/edit', array('id'=>$customer->getId()))); return; } @@ -382,7 +468,7 @@ public function cartAction() ->setWebsite(Mage::app()->getWebsite($websiteId)) ->loadByCustomer(Mage::registry('current_customer')); $item = $quote->getItemById($deleteItemId); - if ($item->getId()) { + if ($item && $item->getId()) { $quote->removeItem($deleteItemId); $quote->collectTotals()->save(); } @@ -456,40 +542,85 @@ public function tagGridAction() public function validateAction() { - $response = new Varien_Object(); + $response = new Varien_Object(); $response->setError(0); - $websiteId = Mage::app()->getStore()->getWebsiteId(); - $accountData = $this->getRequest()->getPost('account'); - + $websiteId = Mage::app()->getStore()->getWebsiteId(); + $accountData = $this->getRequest()->getPost('account'); $customer = Mage::getModel('customer/customer'); - if ($id = $this->getRequest()->getParam('id')) { - $customer->load($id); + $customerId = $this->getRequest()->getParam('id'); + if ($customerId) { + $customer->load($customerId); $websiteId = $customer->getWebsiteId(); - } - if (isset($accountData['website_id'])) { + } else if (isset($accountData['website_id'])) { $websiteId = $accountData['website_id']; } - # Checking if we received email. If not - ERROR - if( !($accountData['email']) ) { + /* @var $customerForm Mage_Customer_Model_Form */ + $customerForm = Mage::getModel('customer/form'); + $customerForm->setEntity($customer) + ->setFormCode('adminhtml_customer') + ->setIsAjaxRequest(true) + ->ignoreInvisible(false) + ; + + $data = $customerForm->extractData($this->getRequest(), 'account'); + $errors = $customerForm->validateData($data); + if ($errors !== true) { + foreach ($errors as $error) { + $this->_getSession()->addError($error); + } $response->setError(1); - Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__("Please fill in 'email' field.")); - $this->_initLayoutMessages('adminhtml/session'); - $response->setMessage($this->getLayout()->getMessagesBlock()->getGroupedHtml()); - } else { + } + + # additional validate email + if (!$response->getError()) { # Trying to load customer with the same email and return error message # if customer with the same email address exisits $checkCustomer = Mage::getModel('customer/customer') ->setWebsiteId($websiteId); $checkCustomer->loadByEmail($accountData['email']); - if( $checkCustomer->getId() && ($checkCustomer->getId() != $customer->getId()) ) { + if ($checkCustomer->getId() && ($checkCustomer->getId() != $customer->getId())) { $response->setError(1); - Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__('Customer with the same email already exists.')); - $this->_initLayoutMessages('adminhtml/session'); - $response->setMessage($this->getLayout()->getMessagesBlock()->getGroupedHtml()); + $this->_getSession()->addError( + Mage::helper('adminhtml')->__('Customer with the same email already exists.') + ); + } + } + + $addressesData = $this->getRequest()->getParam('address'); + if (is_array($addressesData)) { + /* @var $addressForm Mage_Customer_Model_Form */ + $addressForm = Mage::getModel('customer/form'); + $addressForm->setFormCode('adminhtml_customer_address')->ignoreInvisible(false); + foreach (array_keys($addressesData) as $index) { + if ($index == '_template_') { + continue; + } + $address = $customer->getAddressItemById($index); + if (!$address) { + $address = Mage::getModel('customer/address'); + } + + $requestScope = sprintf('address/%s', $index); + $formData = $addressForm->setEntity($address) + ->extractData($this->getRequest(), $requestScope); + + $errors = $addressForm->validateData($formData); + if ($errors !== true) { + foreach ($errors as $error) { + $this->_getSession()->addError($error); + } + $response->setError(1); + } } } + + if ($response->getError()) { + $this->_initLayoutMessages('adminhtml/session'); + $response->setMessage($this->getLayout()->getMessagesBlock()->getGroupedHtml()); + } + $this->getResponse()->setBody($response->toJson()); } @@ -594,6 +725,76 @@ public function massAssignGroupAction() $this->_redirect('*/*/index'); } + public function viewfileAction() + { + $file = null; + $plain = false; + if ($this->getRequest()->getParam('file')) { + // download file + $file = Mage::helper('core')->urlDecode($this->getRequest()->getParam('file')); + } else if ($this->getRequest()->getParam('image')) { + // show plain image + $file = Mage::helper('core')->urlDecode($this->getRequest()->getParam('image')); + $plain = true; + } else { + return $this->norouteAction(); + } + + $path = Mage::getBaseDir('media') . DS . 'customer'; + + $ioFile = new Varien_Io_File(); + $ioFile->open(array('path' => $path)); + $fileName = $ioFile->getCleanPath($path . $file); + $path = $ioFile->getCleanPath($path); + + if (!$ioFile->fileExists($fileName) || strpos($fileName, $path) !== 0) { + return $this->norouteAction(); + } + + if ($plain) { + $extension = pathinfo($fileName, PATHINFO_EXTENSION); + switch (strtolower($extension)) { + case 'gif': + $contentType = 'image/gif'; + break; + case 'jpg': + $contentType = 'image/jpeg'; + break; + case 'png': + $contentType = 'image/png'; + break; + default: + $contentType = 'application/octet-stream'; + break; + } + + $ioFile->streamOpen($fileName, 'r'); + $contentLength = $ioFile->streamStat('size'); + $contentModify = $ioFile->streamStat('mtime'); + + $this->getResponse() + ->setHttpResponseCode(200) + ->setHeader('Pragma', 'public', true) + ->setHeader('Content-type', $contentType, true) + ->setHeader('Content-Length', $contentLength) + ->setHeader('Last-Modified', date('r', $contentModify)) + ->clearBody(); + $this->getResponse()->sendHeaders(); + + while (false !== ($buffer = $ioFile->streamRead())) { + echo $buffer; + } + } else { + $name = pathinfo($fileName, PATHINFO_BASENAME); + $this->_prepareDownloadResponse($name, array( + 'type' => 'filename', + 'value' => $fileName + )); + } + + exit(); + } + protected function _isAllowed() { return Mage::getSingleton('admin/session')->isAllowed('customer/manage'); diff --git a/app/code/core/Mage/Adminhtml/controllers/Extensions/CustomController.php b/app/code/core/Mage/Adminhtml/controllers/Extensions/CustomController.php index 6116bdb608..349ee7e6db 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Extensions/CustomController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Extensions/CustomController.php @@ -165,7 +165,7 @@ public function createAction() $this->_redirect('*/*'); #$this->_forward('reset'); } else { - $session->addError($result->getMessage()); + $session->addError(/*$result->getMessage()*/'Error'); $this->_redirect('*/*'); } } diff --git a/app/code/core/Mage/Adminhtml/controllers/Newsletter/QueueController.php b/app/code/core/Mage/Adminhtml/controllers/Newsletter/QueueController.php index 9943c22fa5..a278f42e94 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Newsletter/QueueController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Newsletter/QueueController.php @@ -58,6 +58,15 @@ public function indexAction() $this->renderLayout(); } + /** + * Preview Newsletter template + */ + public function previewAction() + { + $this->loadLayout('newsletter_queue_preview'); + $this->renderLayout(); + } + /** * Queue list Ajax action */ @@ -157,12 +166,14 @@ public function editAction() $this->_title($this->__('Newsletter'))->_title($this->__('Newsletter Queue')); Mage::register('current_queue', Mage::getSingleton('newsletter/queue')); + $id = $this->getRequest()->getParam('id'); $templateId = $this->getRequest()->getParam('template_id'); + if ($id) { $queue = Mage::registry('current_queue')->load($id); } elseif ($templateId) { - $template = Mage::getModel('newsletter/template')->load($templateId)->preprocess(); + $template = Mage::getModel('newsletter/template')->load($templateId); $queue = Mage::registry('current_queue')->setTemplateId($template->getId()); } @@ -172,12 +183,12 @@ public function editAction() $this->_setActiveMenu('newsletter/queue'); - $this->_addBreadcrumb(Mage::helper('newsletter')->__('Newsletter Queue'), Mage::helper('newsletter')->__('Newsletter Queue'), $this->getUrl('*/newsletter_queue')); - $this->_addBreadcrumb(Mage::helper('newsletter')->__('Edit Queue'), Mage::helper('newsletter')->__('Edit Queue')); - - $this->_addContent( - $this->getLayout()->createBlock('adminhtml/newsletter_queue_edit', 'queue.edit') + $this->_addBreadcrumb( + Mage::helper('newsletter')->__('Newsletter Queue'), + Mage::helper('newsletter')->__('Newsletter Queue'), + $this->getUrl('*/newsletter_queue') ); + $this->_addBreadcrumb(Mage::helper('newsletter')->__('Edit Queue'), Mage::helper('newsletter')->__('Edit Queue')); $this->renderLayout(); } @@ -185,62 +196,48 @@ public function editAction() public function saveAction() { try { - // create new queue from template, if specified + /* @var $queue Mage_Newsletter_Model_Queue */ + $queue = Mage::getModel('newsletter/queue'); + $templateId = $this->getRequest()->getParam('template_id'); if ($templateId) { + /* @var $template Mage_Newsletter_Model_Template */ $template = Mage::getModel('newsletter/template')->load($templateId); + if (!$template->getId() || $template->getIsSystem()) { Mage::throwException($this->__('Wrong newsletter template.')); } - $template->preprocess(); - $queue = Mage::getModel('newsletter/queue') - ->setTemplateId($template->getId()) + + $queue->setTemplateId($template->getId()) ->setQueueStatus(Mage_Newsletter_Model_Queue::STATUS_NEVER); - $template->save(); - } - else { - $queue = Mage::getSingleton('newsletter/queue') - ->load($this->getRequest()->getParam('id')); + } else { + $queue->load($this->getRequest()->getParam('id')); } if (!in_array($queue->getQueueStatus(), - array(Mage_Newsletter_Model_Queue::STATUS_NEVER, - Mage_Newsletter_Model_Queue::STATUS_PAUSE))) { - $this->_redirect('*/*'); + array(Mage_Newsletter_Model_Queue::STATUS_NEVER, + Mage_Newsletter_Model_Queue::STATUS_PAUSE)) + ) { + $this->_redirect('*/*'); return; } - $format = Mage::app()->getLocale()->getDateTimeFormat( - Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM - ); - - if ($queue->getQueueStatus()==Mage_Newsletter_Model_Queue::STATUS_NEVER) { - if ($this->getRequest()->getParam('start_at')) { - $date = Mage::app()->getLocale()->date($this->getRequest()->getParam('start_at'), $format); - $time = $date->getTimestamp(); - $queue->setQueueStartAt( - Mage::getModel('core/date')->gmtDate(null, $time) - ); - } else { - $queue->setQueueStartAt(null); - } + if ($queue->getQueueStatus() == Mage_Newsletter_Model_Queue::STATUS_NEVER) { + $queue->setQueueStartAtByString($this->getRequest()->getParam('start_at')); } - $queue->setStores($this->getRequest()->getParam('stores', array())); - - $queue->addTemplateData($queue); - $queue->getTemplate() - ->setTemplateSubject($this->getRequest()->getParam('subject')) - ->setTemplateSenderName($this->getRequest()->getParam('sender_name')) - ->setTemplateSenderEmail($this->getRequest()->getParam('sender_email')) - ->setTemplateTextPreprocessed($this->getRequest()->getParam('text')); + $queue->setStores($this->getRequest()->getParam('stores', array())) + ->setNewsletterSubject($this->getRequest()->getParam('subject')) + ->setNewsletterSenderName($this->getRequest()->getParam('sender_name')) + ->setNewsletterSenderEmail($this->getRequest()->getParam('sender_email')) + ->setNewsletterText($this->getRequest()->getParam('text')) + ->setNewsletterStyles($this->getRequest()->getParam('styles')); if ($queue->getQueueStatus() == Mage_Newsletter_Model_Queue::STATUS_PAUSE && $this->getRequest()->getParam('_resume', false)) { $queue->setQueueStatus(Mage_Newsletter_Model_Queue::STATUS_SENDING); } - $queue->setSaveTemplateFlag(true); $queue->save(); $this->_redirect('*/*'); } @@ -249,8 +246,7 @@ public function saveAction() $id = $this->getRequest()->getParam('id'); if ($id) { $this->_redirect('*/*/edit', array('id' => $id)); - } - else { + } else { $this->_redirectReferer(); } } diff --git a/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php b/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php index b6f92abb05..6da6cd70be 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Newsletter/TemplateController.php @@ -32,13 +32,34 @@ */ class Mage_Adminhtml_Newsletter_TemplateController extends Mage_Adminhtml_Controller_Action { + /** + * Check is allowed access + * + * @return bool + */ + protected function _isAllowed () + { + return Mage::getSingleton('admin/session') + ->isAllowed('newsletter/template'); + } + + /** + * Set title of page + * + * @return Mage_Adminhtml_Newsletter_TemplateController + */ + protected function _setTitle() + { + return $this->_title($this->__('Newsletter'))->_title($this->__('Newsletter Templates')); + } + /** * View Templates list * */ public function indexAction () { - $this->_title($this->__('Newsletter'))->_title($this->__('Newsletter Templates')); + $this->_setTitle(); if ($this->getRequest()->getQuery('ajax')) { $this->_forward('grid'); @@ -64,7 +85,7 @@ public function gridAction () } /** - * Create new Nesletter Template + * Create new Newsletter Template * */ public function newAction () @@ -78,7 +99,7 @@ public function newAction () */ public function editAction () { - $this->_title($this->__('Newsletter'))->_title($this->__('Newsletter Templates')); + $this->_setTitle(); $model = Mage::getModel('newsletter/template'); if ($id = $this->getRequest()->getParam('id')) { @@ -116,7 +137,17 @@ public function editAction () } /** - * Save Nesletter Template + * Drop Newsletter Template + * + */ + public function dropAction () + { + $this->loadLayout('newsletter_template_preview'); + $this->renderLayout(); + } + + /** + * Save Newsletter Template * */ public function saveAction () @@ -194,18 +225,19 @@ public function deleteAction () */ public function previewAction () { - $this->loadLayout('preview'); - $this->renderLayout(); - } + $this->_setTitle(); + $this->loadLayout(); - /** - * Check is allowed access - * - * @return bool - */ - protected function _isAllowed () - { - return Mage::getSingleton('admin/session') - ->isAllowed('newsletter/template'); + $data = $this->getRequest()->getParams(); + if (empty($data) || !isset($data['id'])) { + $this->_forward('noRoute'); + return $this; + } + + // set default value for selected store + $data['preview_store_id'] = Mage::app()->getDefaultStoreView()->getId(); + + $this->getLayout()->getBlock('preview_form')->setFormData($data); + $this->renderLayout(); } } diff --git a/app/code/core/Mage/Adminhtml/controllers/Permissions/RoleController.php b/app/code/core/Mage/Adminhtml/controllers/Permissions/RoleController.php index 6854b00ad5..ee3264541a 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Permissions/RoleController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Permissions/RoleController.php @@ -203,7 +203,7 @@ public function saveRoleAction() } $rid = $role->getId(); - Mage::getSingleton('adminhtml/session')->addSuccess($this->__('The role has beensuccessfully saved.')); + Mage::getSingleton('adminhtml/session')->addSuccess($this->__('The role has been successfully saved.')); } catch (Mage_Core_Exception $e) { Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); } catch (Exception $e) { diff --git a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreateController.php b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreateController.php index fbb7cd0a92..8b9bd880c4 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreateController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreateController.php @@ -127,6 +127,11 @@ protected function _processData() $this->_getOrderCreateModel()->importPostData($data); } + /** + * Initialize catalog rule data + */ + $this->_getOrderCreateModel()->initRuleData(); + /** * init first billing address, need for virtual products */ @@ -217,7 +222,6 @@ protected function _processData() Mage::dispatchEvent('adminhtml_sales_order_create_process_data', $eventData); $this->_getOrderCreateModel() - ->initRuleData() ->saveQuote(); if ($paymentData = $this->getRequest()->getPost('payment')) { @@ -265,10 +269,10 @@ protected function _processData() public function indexAction() { $this->_title($this->__('Sales'))->_title($this->__('Orders'))->_title($this->__('New Order')); + $this->_initSession(); $this->loadLayout(); - $this->_initSession() - ->_setActiveMenu('sales/order') + $this->_setActiveMenu('sales/order') ->renderLayout(); } @@ -381,6 +385,7 @@ public function saveAction() } $order = $this->_getOrderCreateModel() + ->setIsValidate(true) ->importPostData($this->getRequest()->getPost('order')) ->createOrder(); diff --git a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreditmemoController.php b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreditmemoController.php index b296887489..948e2a4191 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreditmemoController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/CreditmemoController.php @@ -39,6 +39,10 @@ class Mage_Adminhtml_Sales_Order_CreditmemoController extends Mage_Adminhtml_Con protected function _getItemData() { $data = $this->getRequest()->getParam('creditmemo'); + if (!$data) { + $data = Mage::getSingleton('adminhtml/session')->getFormData(true); + } + if (isset($data['items'])) { $qtys = $data['items']; } else { @@ -281,7 +285,7 @@ public function saveAction() $comment = ''; if (!empty($data['comment_text'])) { - $creditmemo->addComment($data['comment_text'], isset($data['comment_customer_notify'])); + $creditmemo->addComment($data['comment_text'], isset($data['comment_customer_notify']), isset($data['is_visible_on_front'])); if (isset($data['comment_customer_notify'])) { $comment = $data['comment_text']; } @@ -312,9 +316,10 @@ public function saveAction() } } catch (Mage_Core_Exception $e) { $this->_getSession()->addError($e->getMessage()); + Mage::getSingleton('adminhtml/session')->setFormData($data); } catch (Exception $e) { Mage::logException($e); - $this->_getSession()->addError($this->__('Cannot save the cedit memo.')); + $this->_getSession()->addError($this->__('Cannot save the credit memo.')); } $this->_redirect('*/*/new', array('_current' => true)); } @@ -376,7 +381,7 @@ public function addCommentAction() Mage::throwException($this->__('The Comment Text field cannot be empty.')); } $creditmemo = $this->_initCreditmemo(); - $creditmemo->addComment($data['comment'], isset($data['is_customer_notified'])); + $creditmemo->addComment($data['comment'], isset($data['is_customer_notified']), isset($data['is_visible_on_front'])); $creditmemo->_hasDataChanges = true; $creditmemo->save(); $creditmemo->sendUpdateEmail(!empty($data['is_customer_notified']), $data['comment']); diff --git a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/InvoiceController.php b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/InvoiceController.php index 54cdce157c..17ac29ed41 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/InvoiceController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/InvoiceController.php @@ -62,6 +62,10 @@ protected function _initInvoice($update = false) $orderId = $this->getRequest()->getParam('order_id'); if ($invoiceId) { $invoice = Mage::getModel('sales/order_invoice')->load($invoiceId); + if (!$invoice->getId()) { + $this->_getSession()->addError($this->__('The invoice no longer exists.')); + return false; + } } elseif ($orderId) { $order = Mage::getModel('sales/order')->load($orderId); /** @@ -193,6 +197,11 @@ public function updateQtyAction() { try { $invoice = $this->_initInvoice(true); + // Save invoice comment text in current invoice object in order to display it in corresponding view + $invoiceRawData = $this->getRequest()->getParam('invoice'); + $invoiceRawCommentText = $invoiceRawData['comment_text']; + $invoice->setCommentText($invoiceRawCommentText); + $this->loadLayout(); $response = $this->getLayout()->getBlock('order_items')->toHtml(); } catch (Mage_Core_Exception $e) { @@ -233,7 +242,7 @@ public function saveAction() } if (!empty($data['comment_text'])) { - $invoice->addComment($data['comment_text'], isset($data['comment_customer_notify'])); + $invoice->addComment($data['comment_text'], isset($data['comment_customer_notify']), isset($data['is_visible_on_front'])); } $invoice->register(); @@ -371,7 +380,7 @@ public function addCommentAction() Mage::throwException($this->__('The Comment Text field cannot be empty.')); } $invoice = $this->_initInvoice(); - $invoice->addComment($data['comment'], isset($data['is_customer_notified'])); + $invoice->addComment($data['comment'], isset($data['is_customer_notified']), isset($data['is_visible_on_front'])); $invoice->sendUpdateEmail(!empty($data['is_customer_notified']), $data['comment']); $invoice->_hasDataChanges = true; $invoice->save(); diff --git a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.php b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.php index a20cab036f..ef1b0a06c6 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.php @@ -91,6 +91,9 @@ protected function _initShipment() $tracks = $this->getRequest()->getPost('tracking'); if ($tracks) { foreach ($tracks as $data) { + if (empty($data['number'])) { + Mage::throwException($this->__('Tracking number cannot be empty.')); + } $track = Mage::getModel('sales/order_shipment_track') ->addData($data); $shipment->addTrack($track); @@ -184,7 +187,7 @@ public function saveAction() $comment = ''; if (!empty($data['comment_text'])) { - $shipment->addComment($data['comment_text'], isset($data['comment_customer_notify'])); + $shipment->addComment($data['comment_text'], isset($data['comment_customer_notify']), isset($data['is_visible_on_front'])); if (isset($data['comment_customer_notify'])) { $comment = $data['comment_text']; } @@ -380,12 +383,12 @@ public function addCommentAction() Mage::throwException($this->__('Comment text field cannot be empty.')); } $shipment = $this->_initShipment(); - $shipment->addComment($data['comment'], isset($data['is_customer_notified'])); + $shipment->addComment($data['comment'], isset($data['is_customer_notified']), isset($data['is_visible_on_front'])); $shipment->sendUpdateEmail(!empty($data['is_customer_notified']), $data['comment']); $shipment->_hasDataChanges = true; $shipment->save(); - $this->loadLayout(); + $this->loadLayout(false); $response = $this->getLayout()->getBlock('shipment_comments')->toHtml(); } catch (Mage_Core_Exception $e) { $response = array( diff --git a/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php b/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php index 5fed284738..fe14a08288 100644 --- a/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php +++ b/app/code/core/Mage/Adminhtml/controllers/Sales/OrderController.php @@ -447,6 +447,9 @@ public function massPrintAction() $document = $this->getRequest()->getPost('document'); } + /** + * Print invoices for selected orders + */ public function pdfinvoicesAction(){ $orderIds = $this->getRequest()->getPost('order_ids'); $flag = false; @@ -471,12 +474,13 @@ public function pdfinvoicesAction(){ $this->_getSession()->addError($this->__('There are no printable documents related to selected orders.')); $this->_redirect('*/*/'); } - } $this->_redirect('*/*/'); - } + /** + * Print shipments for selected orders + */ public function pdfshipmentsAction(){ $orderIds = $this->getRequest()->getPost('order_ids'); $flag = false; @@ -505,6 +509,9 @@ public function pdfshipmentsAction(){ $this->_redirect('*/*/'); } + /** + * Print creditmemos for selected orders + */ public function pdfcreditmemosAction(){ $orderIds = $this->getRequest()->getPost('order_ids'); $flag = false; @@ -533,6 +540,9 @@ public function pdfcreditmemosAction(){ $this->_redirect('*/*/'); } + /** + * Print all documents for selected orders + */ public function pdfdocsAction(){ $orderIds = $this->getRequest()->getPost('order_ids'); $flag = false; @@ -610,6 +620,11 @@ public function voidPaymentAction() $this->_redirect('*/*/view', array('order_id' => $order->getId())); } + /** + * Acl check for admin + * + * @return bool + */ protected function _isAllowed() { if ($this->getRequest()->getActionName() == 'view') { diff --git a/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php b/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php index 28e30a7b8d..d42749c59f 100644 --- a/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php +++ b/app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php @@ -195,68 +195,29 @@ public function stateAction() } /** - * Enter description here... + * Export shipping table rates in csv format * */ public function exportTableratesAction() { - $websiteModel = Mage::app()->getWebsite($this->getRequest()->getParam('website')); - + $fileName = 'tablerates.csv'; + /** @var $gridBlock Mage_Adminhtml_Block_Shipping_Carrier_Tablerate_Grid */ + $gridBlock = $this->getLayout()->createBlock('adminhtml/shipping_carrier_tablerate_grid'); + $website = Mage::app()->getWebsite($this->getRequest()->getParam('website')); if ($this->getRequest()->getParam('conditionName')) { $conditionName = $this->getRequest()->getParam('conditionName'); } else { - $conditionName = $websiteModel->getConfig('carriers/tablerate/condition_name'); + $conditionName = $website->getConfig('carriers/tablerate/condition_name'); } - - $tableratesCollection = Mage::getResourceModel('shipping/carrier_tablerate_collection'); - /* @var $tableratesCollection Mage_Shipping_Model_Mysql4_Carrier_Tablerate_Collection */ - $tableratesCollection->setConditionFilter($conditionName); - $tableratesCollection->setWebsiteFilter($websiteModel->getId()); - $tableratesCollection->load(); - - $csv = ''; - - $conditionName = Mage::getModel('shipping/carrier_tablerate')->getCode('condition_name_short', $conditionName); - - $csvHeader = array('"'.Mage::helper('adminhtml')->__('Country').'"', '"'.Mage::helper('adminhtml')->__('Region/State').'"', '"'.Mage::helper('adminhtml')->__('Zip/Postal Code').'"', '"'.$conditionName.'"', '"'.Mage::helper('adminhtml')->__('Shipping Price').'"'); - $csv .= implode(',', $csvHeader)."\n"; - - foreach ($tableratesCollection->getItems() as $item) { - if ($item->getData('dest_country') == '') { - $country = '*'; - } else { - $country = $item->getData('dest_country'); - } - if ($item->getData('dest_region') == '') { - $region = '*'; - } else { - $region = $item->getData('dest_region'); - } - if ($item->getData('dest_zip') == '') { - $zip = '*'; - } else { - $zip = $item->getData('dest_zip'); - } - - $csvData = array($country, $region, $zip, $item->getData('condition_value'), $item->getData('price')); - foreach ($csvData as $cell) { - $cell = '"'.str_replace('"', '""', $cell).'"'; - } - $csv .= implode(',', $csvData)."\n"; - } - - header('Pragma: public'); - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - - header("Content-type: application/octet-stream"); - header("Content-disposition: attachment; filename=tablerates.csv"); - echo $csv; - exit; + $gridBlock->setWebsiteId($website->getId())->setConditionName($conditionName); + $content = $gridBlock->getCsvFile(); + $this->_prepareDownloadResponse($fileName, $content); } /** - * Enter description here... + * Check is allow modify system configuration * + * @return bool */ protected function _isAllowed() { diff --git a/app/code/core/Mage/Adminhtml/controllers/System/Convert/GuiController.php b/app/code/core/Mage/Adminhtml/controllers/System/Convert/GuiController.php index 3f7b96366e..2598ef8107 100644 --- a/app/code/core/Mage/Adminhtml/controllers/System/Convert/GuiController.php +++ b/app/code/core/Mage/Adminhtml/controllers/System/Convert/GuiController.php @@ -130,7 +130,6 @@ public function downloadAction() } $this->_initProfile(); $profile = Mage::registry('current_convert_profile'); - } protected function _isAllowed() diff --git a/app/code/core/Mage/Adminhtml/controllers/System/Convert/ProfileController.php b/app/code/core/Mage/Adminhtml/controllers/System/Convert/ProfileController.php index b5917128b4..fb35e73154 100644 --- a/app/code/core/Mage/Adminhtml/controllers/System/Convert/ProfileController.php +++ b/app/code/core/Mage/Adminhtml/controllers/System/Convert/ProfileController.php @@ -33,7 +33,6 @@ */ class Mage_Adminhtml_System_Convert_ProfileController extends Mage_Adminhtml_Controller_Action { - protected function _initProfile($idFieldName = 'id') { $this->_title($this->__('System')) @@ -200,17 +199,8 @@ public function saveAction() public function runAction() { $this->_initProfile(); - #$this->loadLayout(); - - #$this->_setActiveMenu('system/convert'); - - #$this->_addContent( - # $this->getLayout()->createBlock('adminhtml/system_convert_profile_run') - #); - $this->getResponse()->setBody($this->getLayout()->createBlock('adminhtml/system_convert_profile_run')->toHtml()); - $this->getResponse()->sendResponse(); - - #$this->renderLayout(); + $this->loadLayout(); + $this->renderLayout(); } public function batchRunAction() @@ -322,3 +312,4 @@ protected function _isAllowed() return Mage::getSingleton('admin/session')->isAllowed('admin/system/convert/profiles'); } } + diff --git a/app/code/core/Mage/Adminhtml/controllers/UrlrewriteController.php b/app/code/core/Mage/Adminhtml/controllers/UrlrewriteController.php index 32e5e1e28f..1e2fb75a9e 100644 --- a/app/code/core/Mage/Adminhtml/controllers/UrlrewriteController.php +++ b/app/code/core/Mage/Adminhtml/controllers/UrlrewriteController.php @@ -125,11 +125,16 @@ public function saveAction() // set basic urlrewrite data $model = Mage::registry('current_urlrewrite'); + // Validate request path + $requestPath = $this->getRequest()->getParam('request_path'); + Mage::helper('core/url_rewrite')->validateRequestPath($requestPath); + + // Proceed and save request $model->setIdPath($this->getRequest()->getParam('id_path')) ->setTargetPath($this->getRequest()->getParam('target_path')) ->setOptions($this->getRequest()->getParam('options')) ->setDescription($this->getRequest()->getParam('description')) - ->setRequestPath($this->getRequest()->getParam('request_path')); + ->setRequestPath($requestPath); if (!$model->getId()) { $model->setIsSystem(0); @@ -156,6 +161,9 @@ public function saveAction() if (in_array($model->getOptions(), array('R', 'RP'))) { $rewrite = Mage::getResourceModel('catalog/url') ->getRewriteByIdPath($idPath, $model->getStoreId()); + if (!$rewrite) { + Mage::throwException('Chosen product does not associated with the chosen store.'); + } if($rewrite->getId() && $rewrite->getId() != $model->getId()) { $model->setIdPath($idPath); $model->setTargetPath($rewrite->getRequestPath()); diff --git a/app/code/core/Mage/Adminhtml/etc/adminhtml.xml b/app/code/core/Mage/Adminhtml/etc/adminhtml.xml index c700705b51..4c4000cabd 100644 --- a/app/code/core/Mage/Adminhtml/etc/adminhtml.xml +++ b/app/code/core/Mage/Adminhtml/etc/adminhtml.xml @@ -240,22 +240,23 @@ - - Cache Management - Magento Connect + 80 Magento Connect Manager - 0 + adminhtml/extensions_local Package Extensions - 5 + adminhtml/extensions_custom + + Cache Management + diff --git a/app/code/core/Mage/Adminhtml/etc/config.xml b/app/code/core/Mage/Adminhtml/etc/config.xml index 7361ea5ef6..3023a8d41f 100644 --- a/app/code/core/Mage/Adminhtml/etc/config.xml +++ b/app/code/core/Mage/Adminhtml/etc/config.xml @@ -70,6 +70,14 @@ + + + + adminhtml/observer + clearCacheConfigurationFilesAccessLevelVerification + + + @@ -163,6 +171,9 @@ system_emails_forgot_email_template general + + 1 + diff --git a/app/code/core/Mage/Api/Model/Mysql4/Acl.php b/app/code/core/Mage/Api/Model/Mysql4/Acl.php index d4564cc9cf..54546c05c6 100644 --- a/app/code/core/Mage/Api/Model/Mysql4/Acl.php +++ b/app/code/core/Mage/Api/Model/Mysql4/Acl.php @@ -60,7 +60,7 @@ function loadAcl() $rolesArr = $this->_getReadAdapter()->fetchAll( $this->_getReadAdapter()->select() ->from($this->getTable('role')) - ->order('tree_level') + ->order(array('tree_level', 'role_type')) ); $this->loadRoles($acl, $rolesArr); diff --git a/app/code/core/Mage/Api/Model/Server/Adapter/Soap.php b/app/code/core/Mage/Api/Model/Server/Adapter/Soap.php index ab8af1a924..f16bdb756c 100644 --- a/app/code/core/Mage/Api/Model/Server/Adapter/Soap.php +++ b/app/code/core/Mage/Api/Model/Server/Adapter/Soap.php @@ -94,8 +94,9 @@ public function getController() */ public function run() { - $urlModel = Mage::getModel('core/url') - ->setUseSession(false); + + $apiConfigCharset = Mage::getStoreConfig("api/config/charset"); + if ($this->getController()->getRequest()->getParam('wsdl') !== null) { // Generating wsdl content from template $io = new Varien_Io_File(); @@ -112,27 +113,45 @@ public function run() } $wsdlConfig->setUrl( - htmlspecialchars($urlModel->getUrl('*/*/*', array('_query'=>$queryParams))) + htmlspecialchars(Mage::getUrl('*/*/*', array('_query'=>$queryParams) )) ); $wsdlConfig->setName('Magento'); $wsdlConfig->setHandler($this->getHandler()); $template->setVariables(array('wsdl'=>$wsdlConfig)); - $this->getController()->getResponse() - ->setHeader('Content-Type','text/xml') - ->setBody($template->filter($wsdlContent)); - } elseif ($this->_extensionLoaded()) { - $this->_soap = new SoapServer($urlModel->getUrl('*/*/*', array('wsdl'=>1))); - use_soap_error_handler(false); - $this->_soap->setClass($this->getHandler()); - $this->getController()->getResponse() - ->setHeader('Content-Type', 'text/xml') - ->setBody($this->_soap->handle()); + $this->getController()->getResponse() + ->clearHeaders() + ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset) + ->setBody( + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '', + $template->filter($wsdlContent) + ) + ); } else { - $this->fault('0', 'Unable to load Soap extension on the server'); + try { + $this->_instantiateServer(); + + $this->getController()->getResponse() + ->clearHeaders() + ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset) + ->setBody( + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '', + $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; } @@ -169,4 +188,59 @@ protected function _extensionLoaded() return class_exists('SoapServer', false); } -} // Class Mage_Api_Model_Server_Adapter_Soap End + /** + * Transform wsdl url if $_SERVER["PHP_AUTH_USER"] is set + * + * @param array + * @return String + */ + protected function getWsdlUrl($params = null, $withAuth = true) + { + $urlModel = Mage::getModel('core/url') + ->setUseSession(false); + + $wsdlUrl = ($params !== null)? $urlModel->getUrl('*/*/*', $params) : $urlModel->getUrl('*/*/*'); + + if( $withAuth ) { + $phpAuthUser = $this->getController()->getRequest()->getServer('PHP_AUTH_USER', false); + $phpAuthPw = $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'); + 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/Xmlrpc.php b/app/code/core/Mage/Api/Model/Server/Adapter/Xmlrpc.php index e178838762..445e827198 100644 --- a/app/code/core/Mage/Api/Model/Server/Adapter/Xmlrpc.php +++ b/app/code/core/Mage/Api/Model/Server/Adapter/Xmlrpc.php @@ -94,10 +94,14 @@ public function getController() */ public function run() { + $apiConfigCharset = Mage::getStoreConfig("api/config/charset"); + $this->_xmlRpc = new Zend_XmlRpc_Server(); - $this->_xmlRpc->setClass($this->getHandler()); + $this->_xmlRpc->setEncoding($apiConfigCharset) + ->setClass($this->getHandler()); $this->getController()->getResponse() - ->setHeader('Content-Type', 'text/xml') + ->clearHeaders() + ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset) ->setBody($this->_xmlRpc->handle()); return $this; } diff --git a/app/code/core/Mage/Api/Model/Server/Handler/Abstract.php b/app/code/core/Mage/Api/Model/Server/Handler/Abstract.php index ba1bc1c57c..f6e76f8ccd 100644 --- a/app/code/core/Mage/Api/Model/Server/Handler/Abstract.php +++ b/app/code/core/Mage/Api/Model/Server/Handler/Abstract.php @@ -436,6 +436,11 @@ public function multiCall($sessionId, array $calls = array(), $options = array() public function resources($sessionId) { $this->_startSession($sessionId); + + if (!$this->_getSession()->isLoggedIn($sessionId)) { + return $this->_fault('session_expired'); + } + $resources = array(); $resourcesAlias = array(); @@ -497,6 +502,10 @@ 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(); diff --git a/app/code/core/Mage/Api/Model/Server/V2/Adapter/Soap.php b/app/code/core/Mage/Api/Model/Server/V2/Adapter/Soap.php index 0504552b38..59b5006cad 100644 --- a/app/code/core/Mage/Api/Model/Server/V2/Adapter/Soap.php +++ b/app/code/core/Mage/Api/Model/Server/V2/Adapter/Soap.php @@ -41,28 +41,43 @@ class Mage_Api_Model_Server_V2_Adapter_Soap extends Mage_Api_Model_Server_Adapte */ public function run() { - $urlModel = Mage::getModel('core/url') - ->setUseSession(false); - if ($this->getController()->getRequest()->getParam('wsdl')) { + $apiConfigCharset = Mage::getStoreConfig("api/config/charset"); + + if ($this->getController()->getRequest()->getParam('wsdl') !== null) { $wsdlConfig = Mage::getModel('api/wsdl_config'); $wsdlConfig->setHandler($this->getHandler()) ->init(); $this->getController()->getResponse() - ->setHeader('Content-Type','text/xml') - ->setBody($wsdlConfig->getWsdlContent()); - } elseif ($this->_extensionLoaded()) { - $this->_soap = new SoapServer($urlModel->getUrl('*/*/*', array('wsdl'=>1))); - use_soap_error_handler(false); - $this->_soap->setClass($this->getHandler()); - $this->getController()->getResponse() - ->setHeader('Content-Type', 'text/xml') - ->setBody($this->_soap->handle()); - + ->clearHeaders() + ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset) + ->setBody( + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '', + $wsdlConfig->getWsdlContent() + ) + ); } else { - $this->fault('0', 'Unable to load Soap extension on the server'); + try { + $this->_instantiateServer(); + + $this->getController()->getResponse() + ->clearHeaders() + ->setHeader('Content-Type','text/xml; charset='.$apiConfigCharset) + ->setBody( + preg_replace( + '/<\?xml version="([^\"]+)"([^\>]+)>/i', + '', + $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/User.php b/app/code/core/Mage/Api/Model/User.php index bf332a547b..885bdf05ef 100644 --- a/app/code/core/Mage/Api/Model/User.php +++ b/app/code/core/Mage/Api/Model/User.php @@ -111,7 +111,7 @@ public function userExists() } public function getCollection() { - return Mage::getResourceModel('admin/user_collection'); + return Mage::getResourceModel('api/user_collection'); } public function getName($separator=' ') diff --git a/app/code/core/Mage/Api/etc/config.xml b/app/code/core/Mage/Api/etc/config.xml index a8226412af..c69798774a 100644 --- a/app/code/core/Mage/Api/etc/config.xml +++ b/app/code/core/Mage/Api/etc/config.xml @@ -119,6 +119,7 @@ + UTF-8 3600 diff --git a/app/code/core/Mage/Api/etc/system.xml b/app/code/core/Mage/Api/etc/system.xml index c85f89a123..5008afc78c 100644 --- a/app/code/core/Mage/Api/etc/system.xml +++ b/app/code/core/Mage/Api/etc/system.xml @@ -44,10 +44,18 @@ 1 1 + + + text + 10 + 1 + 1 + 1 + text - 1 + 20 1 1 1 diff --git a/app/code/core/Mage/Api/etc/wsdl.xml b/app/code/core/Mage/Api/etc/wsdl.xml index 99229a333c..6b24d0d9a3 100644 --- a/app/code/core/Mage/Api/etc/wsdl.xml +++ b/app/code/core/Mage/Api/etc/wsdl.xml @@ -4,7 +4,7 @@ name="{{var wsdl.name}}" targetNamespace="urn:{{var wsdl.name}}"> - + 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 33e4cd4b9f..01fa16624f 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 @@ -33,21 +33,39 @@ */ class Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selection extends Mage_Adminhtml_Block_Widget { + /** + * Initialize bundle option selection block + */ public function __construct() { $this->setTemplate('bundle/product/edit/bundle/option/selection.phtml'); } + /** + * Return field id + * + * @return string + */ public function getFieldId() { return 'bundle_selection'; } + /** + * Return field name + * + * @return string + */ public function getFieldName() { return 'bundle_selections'; } + /** + * Prepare block layout + * + * @return Mage_Bundle_Block_Adminhtml_Catalog_Product_Edit_Tab_Bundle_Option_Selection + */ protected function _prepareLayout() { $this->setChild('selection_delete_button', @@ -58,15 +76,24 @@ protected function _prepareLayout() 'on_click' => 'bSelection.remove(event)' )) ); - return parent::_prepareLayout(); } + /** + * Retrieve delete button html + * + * @return string + */ public function getSelectionDeleteButtonHtml() { return $this->getChildHtml('selection_delete_button'); } + /** + * Retrieve price type select html + * + * @return string + */ public function getPriceTypeSelectHtml() { $select = $this->getLayout()->createBlock('adminhtml/html_select') @@ -80,6 +107,11 @@ public function getPriceTypeSelectHtml() return $select->getHtml(); } + /** + * Retrieve qty type select html + * + * @return string + */ public function getQtyTypeSelectHtml() { $select = $this->getLayout()->createBlock('adminhtml/html_select') @@ -93,8 +125,43 @@ public function getQtyTypeSelectHtml() return $select->getHtml(); } + /** + * Return search url + * + * @return string + */ public function getSelectionSearchUrl() { return $this->getUrl('bundle/selection/search'); } + + /** + * Check if used website scope price + * + * @return string + */ + public function isUsedWebsitePrice() + { + return !Mage::helper('catalog')->isPriceGlobal() && Mage::registry('product')->getStoreId(); + } + + /** + * Retrieve price scope checkbox html + * + * @return string + */ + public function getCheckboxScopeHtml() + { + $checkboxHtml = ''; + if ($this->isUsedWebsitePrice()) { + $id = $this->getFieldId().'_{{index}}_price_scope'; + $name = $this->getFieldName().'[{{parentIndex}}][{{index}}][default_price_scope]'; + $class = 'bundle-option-price-scope-checkbox'; + $label = Mage::helper('bundle')->__('Use Default Value'); + + $checkboxHtml = ''; + $checkboxHtml .= ''; + } + return $checkboxHtml; + } } diff --git a/app/code/core/Mage/Bundle/Block/Checkout/Cart/Item/Renderer.php b/app/code/core/Mage/Bundle/Block/Checkout/Cart/Item/Renderer.php index 0426c9b48f..b491e37ca1 100644 --- a/app/code/core/Mage/Bundle/Block/Checkout/Cart/Item/Renderer.php +++ b/app/code/core/Mage/Bundle/Block/Checkout/Cart/Item/Renderer.php @@ -70,7 +70,11 @@ protected function _getBundleOptions($useCache = true) $bundleOptions = $optionsCollection->appendSelections($selectionsCollection, true); foreach ($bundleOptions as $bundleOption) { if ($bundleOption->getSelections()) { - $option = array('label' => $bundleOption->getTitle(), "value" => array()); + $option = array( + 'label' => $bundleOption->getTitle(), + 'value' => array() + ); + $bundleSelections = $bundleOption->getSelections(); foreach ($bundleSelections as $bundleSelection) { @@ -81,6 +85,7 @@ protected function _getBundleOptions($useCache = true) } } } + return $options; } @@ -114,8 +119,46 @@ protected function _getSelectionQty($selectionId) return 0; } + /** + * Overloaded method for getting list of bundle options + * Caches result in quote item, because it can be used in cart 'recent view' and on same page in cart checkout + * + * @return array + */ public function getOptionList() { - return array_merge($this->_getBundleOptions(), parent::getOptionList()); + $item = $this->getItem(); + $optionList = $item->getBlockOptionList(); + if ($optionList === null) { + $optionList = array_merge($this->_getBundleOptions(), parent::getOptionList()); + $item->setBlockOptionList($optionList); + } + + return $optionList; + } + + /** + * Return cart backorder messages + * + * @return array + */ + public function getMessages() + { + $messages = $this->getData('messages'); + if (is_null($messages)) { + $messages = array(); + } + $options = $this->getItem()->getQtyOptions(); + + foreach ($options as $option) { + if ($option->getMessage()) { + $messages[] = array( + 'text' => $option->getMessage(), + 'type' => ($this->getItem()->getHasError()) ? 'error' : 'notice' + ); + } + } + + return $messages; } } diff --git a/app/code/core/Mage/Bundle/Model/Mysql4/Indexer/Price.php b/app/code/core/Mage/Bundle/Model/Mysql4/Indexer/Price.php index caac5ec726..6c0e7a8e9c 100644 --- a/app/code/core/Mage/Bundle/Model/Mysql4/Indexer/Price.php +++ b/app/code/core/Mage/Bundle/Model/Mysql4/Indexer/Price.php @@ -302,14 +302,21 @@ protected function _calculateBundleSelectionPrice($priceType) $write = $this->_getWriteAdapter(); if ($priceType == Mage_Bundle_Model_Product_Price::PRICE_TYPE_FIXED) { - $priceExpr = new Zend_Db_Expr("IF(bs.selection_price_type = 1, " - . "ROUND(i.price * (bs.selection_price_value / 100), 4), IF(i.special_price > 0, " - . "ROUND(bs.selection_price_value * (i.special_price / 100), 4), bs.selection_price_value)) " - . "* bs.selection_qty"); - $tierExpr = new Zend_Db_Expr("IF(i.base_tier IS NOT NULL, IF(bs.selection_price_type = 1, " - . "ROUND(i.base_tier - (i.base_tier * (bs.selection_price_value / 100)), 4), IF(i.tier_percent > 0, " - . "ROUND(bs.selection_price_value - (bs.selection_price_value * (i.tier_percent / 100)), 4), " - . "bs.selection_price_value)) * bs.selection_qty, NULL)"); + $priceExpr = new Zend_Db_Expr("IF(IF(bsp.selection_price_type IS NULL, bs.selection_price_type, " + . "bsp.selection_price_type) = 1, " + . "ROUND(i.price * (IF(bsp.selection_price_value IS NULL, bs.selection_price_value, " + . "bsp.selection_price_value) / 100), 4), IF(i.special_price > 0, " + . "ROUND(IF(bsp.selection_price_value IS NULL, bs.selection_price_value, bsp.selection_price_value) " + . "* (i.special_price / 100), 4), IF(bsp.selection_price_value IS NULL, bs.selection_price_value, " + . "bsp.selection_price_value))) * bs.selection_qty"); + $tierExpr = new Zend_Db_Expr("IF(i.base_tier IS NOT NULL, IF(IF(bsp.selection_price_type IS NULL, " + . "bs.selection_price_type, bsp.selection_price_type) = 1, " + . "ROUND(i.base_tier - (i.base_tier * (IF(bsp.selection_price_value IS NULL, bs.selection_price_value, " + . "bsp.selection_price_value) / 100)), 4), IF(i.tier_percent > 0, " + . "ROUND(IF(bsp.selection_price_value IS NULL, bs.selection_price_value, bsp.selection_price_value) " + . "- (IF(bsp.selection_price_value IS NULL, bs.selection_price_value, bsp.selection_price_value) " + . "* (i.tier_percent / 100)), 4), IF(bsp.selection_price_value IS NULL, bs.selection_price_value, " + . "bsp.selection_price_value))) * bs.selection_qty, NULL)"); } else { $priceExpr = new Zend_Db_Expr("IF(i.special_price > 0, ROUND(idx.min_price * (i.special_price / 100), 4), " . "idx.min_price) * bs.selection_qty"); @@ -329,6 +336,10 @@ protected function _calculateBundleSelectionPrice($priceType) array('bs' => $this->getTable('bundle/selection')), 'bs.option_id = bo.option_id', array('selection_id')) + ->joinLeft( + array('bsp' => $this->getTable('bundle/selection_price')), + 'bs.selection_id = bsp.selection_id AND bsp.website_id = i.website_id', + array('')) ->join( array('idx' => $this->getIdxTable()), 'bs.product_id = idx.entity_id AND i.customer_group_id = idx.customer_group_id' diff --git a/app/code/core/Mage/Bundle/Model/Mysql4/Option/Collection.php b/app/code/core/Mage/Bundle/Model/Mysql4/Option/Collection.php index 66fd46f68c..0496b002d2 100644 --- a/app/code/core/Mage/Bundle/Model/Mysql4/Option/Collection.php +++ b/app/code/core/Mage/Bundle/Model/Mysql4/Option/Collection.php @@ -33,6 +33,13 @@ */ class Mage_Bundle_Model_Mysql4_Option_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract { + /** + * All item ids cache + * + * @var array + */ + protected $_itemIds; + protected $_selectionsAppended = false; protected function _construct() { @@ -126,4 +133,27 @@ public function setIdFilter($ids) return $this; } + /** + * Reset all item ids cache + * + * @return Mage_Bundle_Model_Mysql4_Option_Collection + */ + public function resetAllIds() + { + $this->_itemIds = null; + return $this; + } + + /** + * Retrive all ids for collection + * + * @return array + */ + public function getAllIds() + { + if (is_null($this->_itemIds)) { + $this->_itemIds = parent::getAllIds(); + } + return $this->_itemIds; + } } diff --git a/app/code/core/Mage/Bundle/Model/Mysql4/Selection.php b/app/code/core/Mage/Bundle/Model/Mysql4/Selection.php index b914b180a8..523d60b8b6 100644 --- a/app/code/core/Mage/Bundle/Model/Mysql4/Selection.php +++ b/app/code/core/Mage/Bundle/Model/Mysql4/Selection.php @@ -175,4 +175,32 @@ public function getParentIdsByChild($childId) return $adapter->fetchCol($select); } + + /** + * Save bundle item price per website + * + * @param Mage_Bundle_Model_Selection $item + */ + public function saveSelectionPrice($item) + { + if ($item->getDefaultPriceScope()) { + $this->_getWriteAdapter()->delete($this->getTable('bundle/selection_price'), + array( + 'selection_id = ?' => $item->getSelectionId(), + 'website_id = ?' => $item->getWebsiteId() + )); + } else { + $values = array( + 'selection_id' => $item->getSelectionId(), + 'website_id' => $item->getWebsiteId(), + 'selection_price_type' => $item->getSelectionPriceType(), + 'selection_price_value' => $item->getSelectionPriceValue() + ); + $this->_getWriteAdapter()->insertOnDuplicate( + $this->getTable('bundle/selection_price'), + $values, + array('selection_price_type', 'selection_price_value') + ); + } + } } diff --git a/app/code/core/Mage/Bundle/Model/Mysql4/Selection/Collection.php b/app/code/core/Mage/Bundle/Model/Mysql4/Selection/Collection.php index 7c61379d8a..52505adf79 100644 --- a/app/code/core/Mage/Bundle/Model/Mysql4/Selection/Collection.php +++ b/app/code/core/Mage/Bundle/Model/Mysql4/Selection/Collection.php @@ -36,6 +36,10 @@ class Mage_Bundle_Model_Mysql4_Selection_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection { protected $_selectionTable; + + /** + * Initialize collection + */ protected function _construct() { parent::_construct(); @@ -43,6 +47,9 @@ protected function _construct() $this->_selectionTable = $this->getTable('bundle/selection'); } + /** + * Initialize collection select + */ protected function _initSelect() { parent::_initSelect(); @@ -52,6 +59,29 @@ protected function _initSelect() ); } + /** + * Join website scope prices to collection, override default prices + * + * @return Mage_Bundle_Model_Mysql4_Selection_Collection + */ + public function joinPrices($websiteId) + { + $this->getSelect()->joinLeft(array('price' => $this->getTable('bundle/selection_price')), + 'selection.selection_id = price.selection_id AND price.website_id = ' . $websiteId, + array( + 'selection_price_type' => 'IFNULL(price.selection_price_type, selection.selection_price_type)', + 'selection_price_value' => 'IFNULL(price.selection_price_value, selection.selection_price_value)', + 'price_scope' => 'price.website_id' + ) + ); + return $this; + } + + /** + * Apply option ids filter to collection + * + * @return Mage_Bundle_Model_Mysql4_Selection_Collection + */ public function setOptionIdsFilter($optionIds) { if (!empty($optionIds)) { @@ -60,6 +90,11 @@ public function setOptionIdsFilter($optionIds) return $this; } + /** + * Apply selection ids filter to collection + * + * @return Mage_Bundle_Model_Mysql4_Selection_Collection + */ public function setSelectionIdsFilter($selectionIds) { if (!empty($selectionIds)) { @@ -68,6 +103,11 @@ public function setSelectionIdsFilter($selectionIds) return $this; } + /** + * Set position order + * + * @return Mage_Bundle_Model_Mysql4_Selection_Collection + */ public function setPositionOrder() { $this->getSelect()->order('selection.position asc') diff --git a/app/code/core/Mage/Bundle/Model/Product/Price.php b/app/code/core/Mage/Bundle/Model/Product/Price.php index 3bde7e9bfa..5d02916273 100644 --- a/app/code/core/Mage/Bundle/Model/Product/Price.php +++ b/app/code/core/Mage/Bundle/Model/Product/Price.php @@ -85,6 +85,11 @@ public function getFinalPrice($qty=null, $product) $customOption = $product->getCustomOption('bundle_selection_ids'); $selectionIds = unserialize($customOption->getValue()); $selections = $product->getTypeInstance(true)->getSelectionsByIds($selectionIds, $product); + $selections->addTierPriceData(); + Mage::dispatchEvent('prepare_catalog_product_collection_prices', array( + 'collection' => $selections, + 'store_id' => $product->getStoreId(), + )); foreach ($selections->getItems() as $selection) { if ($selection->isSalable()) { $selectionQty = $product->getCustomOption('selection_qty_' . $selection->getSelectionId()); @@ -197,11 +202,6 @@ public function getPrices($product, $which = null) $minimalPrice = $minPriceFounded; } - if ($product->getPriceType() == self::PRICE_TYPE_DYNAMIC) { - $minimalPrice = $this->_applySpecialPrice($product, $minimalPrice); - $maximalPrice = $this->_applySpecialPrice($product, $maximalPrice); - } - $customOptions = $product->getOptions(); if ($product->getPriceType() == self::PRICE_TYPE_FIXED && $customOptions) { @@ -262,7 +262,7 @@ public function getMinimalPrice($product) */ public function getMaximalPrice($product) { - return $this->getPrice($product, 'max'); + return $this->getPrices($product, 'max'); } /** diff --git a/app/code/core/Mage/Bundle/Model/Product/Type.php b/app/code/core/Mage/Bundle/Model/Product/Type.php index c9a80271e1..f190c50374 100644 --- a/app/code/core/Mage/Bundle/Model/Product/Type.php +++ b/app/code/core/Mage/Bundle/Model/Product/Type.php @@ -210,19 +210,27 @@ public function isVirtual($product = null) public function beforeSave($product = null) { parent::beforeSave($product); + $product = $this->getProduct($product); + + // If bundle product has dynamic weight, than delete weight attribute + if (!$product->getData('weight_type') && $product->hasData('weight')) { + $product->setData('weight', false); + } - $this->getProduct($product)->canAffectOptions(false); + $product->canAffectOptions(false); - if ($this->getProduct($product)->getCanSaveBundleSelections()) { - $this->getProduct($product)->canAffectOptions(true); - if ($selections = $this->getProduct($product)->getBundleSelectionsData()) { + if ($product->getCanSaveBundleSelections()) { + $product->canAffectOptions(true); + $selections = $product->getBundleSelectionsData(); + if ($selections) { if (!empty($selections)) { - if ($options = $this->getProduct($product)->getBundleOptionsData()) { + $options = $product->getBundleOptionsData(); + if ($options) { foreach ($options as $option) { if (empty($option['delete']) || 1 != (int)$option['delete']) { - $this->getProduct($product)->setTypeHasOptions(true); + $product->setTypeHasOptions(true); if (1 == (int)$option['required']) { - $this->getProduct($product)->setTypeHasRequiredOptions(true); + $product->setTypeHasRequiredOptions(true); break; } } @@ -361,15 +369,22 @@ public function getSelectionsCollection($optionIds, $product = null) $keyOptionIds = (is_array($optionIds) ? implode('_', $optionIds) : ''); $key = $this->_keySelectionsCollection . $keyOptionIds; if (!$this->getProduct($product)->hasData($key)) { + $storeId = $this->getProduct($product)->getStoreId(); $selectionsCollection = Mage::getResourceModel('bundle/selection_collection') ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes()) ->setFlag('require_stock_items', true) ->setFlag('product_children', true) ->setPositionOrder() ->addStoreFilter($this->getStoreFilter($product)) + ->setStoreId($storeId) ->addFilterByRequiredOptions() ->setOptionIdsFilter($optionIds); + if (!Mage::helper('catalog')->isPriceGlobal() && $storeId) { + $websiteId = Mage::app()->getStore($storeId)->getWebsiteId(); + $selectionsCollection->joinPrices($websiteId); + } + $this->getProduct($product)->setData($key, $selectionsCollection); } return $this->getProduct($product)->getData($key); @@ -679,13 +694,20 @@ public function getSelectionsByIds($selectionIds, $product = null) $usedSelectionsIds = $this->getProduct($product)->getData($this->_keyUsedSelectionsIds); if (!$usedSelections || serialize($usedSelectionsIds) != serialize($selectionIds)) { + $storeId = $this->getProduct($product)->getStoreId(); $usedSelections = Mage::getResourceModel('bundle/selection_collection') ->addAttributeToSelect('*') ->setFlag('require_stock_items', true) ->addStoreFilter($this->getStoreFilter($product)) + ->setStoreId($storeId) ->setPositionOrder() ->addFilterByRequiredOptions() ->setSelectionIdsFilter($selectionIds); + + if (!Mage::helper('catalog')->isPriceGlobal() && $storeId) { + $websiteId = Mage::app()->getStore($storeId)->getWebsiteId(); + $usedSelections->joinPrices($websiteId); + } $this->getProduct($product)->setData($this->_keyUsedSelections, $usedSelections); $this->getProduct($product)->setData($this->_keyUsedSelectionsIds, $selectionIds); } diff --git a/app/code/core/Mage/Bundle/Model/Selection.php b/app/code/core/Mage/Bundle/Model/Selection.php index c58a9a2b59..32f6660e78 100644 --- a/app/code/core/Mage/Bundle/Model/Selection.php +++ b/app/code/core/Mage/Bundle/Model/Selection.php @@ -33,9 +33,32 @@ */ class Mage_Bundle_Model_Selection extends Mage_Core_Model_Abstract { + /** + * Initialize resource model + */ protected function _construct() { $this->_init('bundle/selection'); parent::_construct(); } + + /** + * Processing object before save data + * + * @return Mage_Bundle_Model_Selection + */ + protected function _beforeSave() + { + $storeId = Mage::registry('product')->getStoreId(); + if (!Mage::helper('catalog')->isPriceGlobal() && $storeId) { + $this->setWebsiteId(Mage::app()->getStore($storeId)->getWebsiteId()); + $this->getResource()->saveSelectionPrice($this); + + if (!$this->getDefaultPriceScope()) { + $this->unsSelectionPriceValue(); + $this->unsSelectionPriceType(); + } + } + parent::_beforeSave(); + } } diff --git a/app/code/core/Mage/Bundle/etc/config.xml b/app/code/core/Mage/Bundle/etc/config.xml index ecb5cbbbed..b325647f13 100644 --- a/app/code/core/Mage/Bundle/etc/config.xml +++ b/app/code/core/Mage/Bundle/etc/config.xml @@ -28,7 +28,7 @@ - 0.1.12 + 0.1.13 @@ -49,6 +49,9 @@ catalog_product_bundle_selection
    + + catalog_product_bundle_selection_price
    +
    catalog_product_bundle_price_index
    diff --git a/app/code/core/Mage/Bundle/sql/bundle_setup/mysql4-upgrade-0.1.12-0.1.13.php b/app/code/core/Mage/Bundle/sql/bundle_setup/mysql4-upgrade-0.1.12-0.1.13.php new file mode 100644 index 0000000000..1380bf2d51 --- /dev/null +++ b/app/code/core/Mage/Bundle/sql/bundle_setup/mysql4-upgrade-0.1.12-0.1.13.php @@ -0,0 +1,54 @@ +run(" +CREATE TABLE {$this->getTable('bundle/selection_price')} ( + `selection_id` int(10) unsigned NOT NULL, + `website_id` smallint(5) unsigned NOT NULL, + `selection_price_type` tinyint(1) unsigned NOT NULL default '0', + `selection_price_value` decimal(12,4) NOT NULL default '0.0000', + PRIMARY KEY (`selection_id`, `website_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +"); + +$installer->getConnection()->addConstraint( + 'FK_BUNDLE_PRICE_SELECTION_ID', + $this->getTable('bundle/selection_price'), + 'selection_id', + $this->getTable('bundle/selection'), + 'selection_id' +); + +$installer->getConnection()->addConstraint( + 'FK_BUNDLE_PRICE_SELECTION_WEBSITE', + $this->getTable('bundle/selection_price'), + 'website_id', + $this->getTable('core_website'), + 'website_id' +); diff --git a/app/code/core/Mage/Catalog/Block/Breadcrumbs.php b/app/code/core/Mage/Catalog/Block/Breadcrumbs.php index 400f11794d..7928f8e739 100644 --- a/app/code/core/Mage/Catalog/Block/Breadcrumbs.php +++ b/app/code/core/Mage/Catalog/Block/Breadcrumbs.php @@ -26,10 +26,8 @@ /** * Catalog breadcrumbs * - * @package Mage - * @subpackage Mage_Catalog - * @copyright Varien (c) 2007 (http://www.varien.com) - * @license http://www.opensource.org/licenses/osl-3.0.php + * @category Mage + * @package Mage_Catalog * @author Magento Core Team */ class Mage_Catalog_Block_Breadcrumbs extends Mage_Core_Block_Template diff --git a/app/code/core/Mage/Catalog/Block/Layer/Filter/Price.php b/app/code/core/Mage/Catalog/Block/Layer/Filter/Price.php index a066661c1e..a8cd8ed7c3 100644 --- a/app/code/core/Mage/Catalog/Block/Layer/Filter/Price.php +++ b/app/code/core/Mage/Catalog/Block/Layer/Filter/Price.php @@ -40,6 +40,7 @@ class Mage_Catalog_Block_Layer_Filter_Price extends Mage_Catalog_Block_Layer_Fil public function __construct() { parent::__construct(); + $this->_filterModelName = 'catalog/layer_filter_price'; } diff --git a/app/code/core/Mage/Catalog/Block/Layer/View.php b/app/code/core/Mage/Catalog/Block/Layer/View.php index c7d9a570fc..1d777507d5 100644 --- a/app/code/core/Mage/Catalog/Block/Layer/View.php +++ b/app/code/core/Mage/Catalog/Block/Layer/View.php @@ -33,9 +33,68 @@ */ class Mage_Catalog_Block_Layer_View extends Mage_Core_Block_Template { + /** + * State block name + * + * @var string + */ + protected $_stateBlockName; + + /** + * Category Block Name + * + * @var string + */ + protected $_categoryBlockName; + + /** + * Attribute Filter Block Name + * + * @var string + */ + protected $_attributeFilterBlockName; + + /** + * Price Filter Block Name + * + * @var string + */ + protected $_priceFilterBlockName; + + /** + * Decimal Filter Block Name + * + * @var string + */ + protected $_decimalFilterBlockName; + + /** + * Internal constructor + */ + protected function _construct() + { + parent::_construct(); + + $this->_initBlocks(); + } + + /** + * Initialize blocks names + */ + protected function _initBlocks() + { + $this->_stateBlockName = 'catalog/layer_state'; + $this->_categoryBlockName = 'catalog/layer_filter_category'; + $this->_attributeFilterBlockName = 'catalog/layer_filter_attribute'; + $this->_priceFilterBlockName = 'catalog/layer_filter_price'; + $this->_decimalFilterBlockName = 'catalog/layer_filter_decimal'; + } + /** * Get attribute filter block name * + * @deprecated after 1.4.1.0 + * * @return string */ protected function _getAttributeFilterBlockName() @@ -50,26 +109,29 @@ protected function _getAttributeFilterBlockName() */ protected function _prepareLayout() { - $stateBlock = $this->getLayout()->createBlock('catalog/layer_state') + $stateBlock = $this->getLayout()->createBlock($this->_stateBlockName) ->setLayer($this->getLayer()); - $categryBlock = $this->getLayout()->createBlock('catalog/layer_filter_category') + $categoryBlock = $this->getLayout()->createBlock($this->_categoryBlockName) ->setLayer($this->getLayer()) ->init(); $this->setChild('layer_state', $stateBlock); - $this->setChild('category_filter', $categryBlock); + $this->setChild('category_filter', $categoryBlock); $filterableAttributes = $this->_getFilterableAttributes(); foreach ($filterableAttributes as $attribute) { - $filterBlockName = $this->_getAttributeFilterBlockName(); if ($attribute->getAttributeCode() == 'price') { - $filterBlockName = 'catalog/layer_filter_price'; - } else if ($attribute->getBackendType() == 'decimal') { - $filterBlockName = 'catalog/layer_filter_decimal'; + $filterBlockName = $this->_priceFilterBlockName; + } + elseif ($attribute->getBackendType() == 'decimal') { + $filterBlockName = $this->_decimalFilterBlockName; + } + else { + $filterBlockName = $this->_attributeFilterBlockName; } - $this->setChild($attribute->getAttributeCode().'_filter', + $this->setChild($attribute->getAttributeCode() . '_filter', $this->getLayout()->createBlock($filterBlockName) ->setLayer($this->getLayer()) ->setAttributeModel($attribute) @@ -77,6 +139,7 @@ protected function _prepareLayout() } $this->getLayer()->apply(); + return parent::_prepareLayout(); } @@ -102,6 +165,7 @@ protected function _getFilterableAttributes() $attributes = $this->getLayer()->getFilterableAttributes(); $this->setData('_filterable_attributes', $attributes); } + return $attributes; } @@ -129,7 +193,7 @@ public function getFilters() $filterableAttributes = $this->_getFilterableAttributes(); foreach ($filterableAttributes as $attribute) { - $filters[] = $this->getChild($attribute->getAttributeCode().'_filter'); + $filters[] = $this->getChild($attribute->getAttributeCode() . '_filter'); } return $filters; @@ -157,6 +221,7 @@ public function canShowOptions() return true; } } + return false; } diff --git a/app/code/core/Mage/Catalog/Block/Navigation.php b/app/code/core/Mage/Catalog/Block/Navigation.php index cc7925f1ba..17e423862c 100644 --- a/app/code/core/Mage/Catalog/Block/Navigation.php +++ b/app/code/core/Mage/Catalog/Block/Navigation.php @@ -58,15 +58,25 @@ protected function _construct() */ public function getCacheKeyInfo() { - return array( + $shortCacheId = array( 'CATALOG_NAVIGATION', Mage::app()->getStore()->getId(), Mage::getDesign()->getPackageName(), Mage::getDesign()->getTheme('template'), Mage::getSingleton('customer/session')->getCustomerGroupId(), 'template' => $this->getTemplate(), - $this->getCurrenCategoryKey() + 'name' => $this->getNameInLayout() ); + $cacheId = $shortCacheId; + + $shortCacheId = array_values($shortCacheId); + $shortCacheId = implode('|', $shortCacheId); + $shortCacheId = md5($shortCacheId); + + $cacheId['category_path'] = $this->getCurrenCategoryKey(); + $cacheId['short_cache_id'] = $shortCacheId; + + return $cacheId; } public function getCurrenCategoryKey() @@ -219,14 +229,14 @@ protected function _renderCategoryMenuItemHtml($category, $level = 0, $isLast = $classes = array(); $classes[] = 'level' . $level; $classes[] = 'nav-' . $this->_getItemPosition($level); + if ($this->isCategoryActive($category)) { + $classes[] = 'active'; + } $linkClass = ''; if ($isOutermost && $outermostItemClass) { $classes[] = $outermostItemClass; $linkClass = ' class="'.$outermostItemClass.'"'; } - if ($this->isCategoryActive($category)) { - $classes[] = 'active'; - } if ($isFirst) { $classes[] = 'first'; } diff --git a/app/code/core/Mage/Catalog/Block/Product/Abstract.php b/app/code/core/Mage/Catalog/Block/Product/Abstract.php index 2dc3eb5b6d..e0033b619a 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Abstract.php +++ b/app/code/core/Mage/Catalog/Block/Product/Abstract.php @@ -301,7 +301,8 @@ protected function _addProductAttributesAndPrices(Mage_Catalog_Model_Resource_Ea ->addMinimalPrice() ->addFinalPrice() ->addTaxPercents() - ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes()); + ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes()) + ->addUrlRewrite(); } /** @@ -440,6 +441,17 @@ public function getPageLayout() return $this->helper('page/layout')->getCurrentPageLayout(); } + /** + * Check whether the price can be shown for the specified product + * + * @param Mage_Catalog_Model_Product $product + * @return bool + */ + public function getCanShowProductPrice($product) + { + return $product->getCanShowPrice() !== false; + } + /** * If exists price template block, retrieve price blocks from it * diff --git a/app/code/core/Mage/Catalog/Block/Product/Compare/List.php b/app/code/core/Mage/Catalog/Block/Product/Compare/List.php index 939e6652a0..987610ccd9 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Compare/List.php +++ b/app/code/core/Mage/Catalog/Block/Product/Compare/List.php @@ -145,7 +145,7 @@ public function getAttributes() public function getProductAttributeValue($product, $attribute) { if (!$product->hasData($attribute->getAttributeCode())) { - return ' '; + return Mage::helper('catalog')->__('N/A'); } if ($attribute->getSourceModel() || in_array($attribute->getFrontendInput(), array('select','boolean','multiselect'))) { @@ -155,7 +155,7 @@ public function getProductAttributeValue($product, $attribute) else { $value = $product->getData($attribute->getAttributeCode()); } - return $value ? $value : ' '; + return ((string)$value == '') ? Mage::helper('catalog')->__('No') : $value; } /** diff --git a/app/code/core/Mage/Catalog/Block/Product/List.php b/app/code/core/Mage/Catalog/Block/Product/List.php index 5cb7d8df3d..4fbc86254f 100644 --- a/app/code/core/Mage/Catalog/Block/Product/List.php +++ b/app/code/core/Mage/Catalog/Block/Product/List.php @@ -56,7 +56,7 @@ class Mage_Catalog_Block_Product_List extends Mage_Catalog_Block_Product_Abstrac protected function _getProductCollection() { if (is_null($this->_productCollection)) { - $layer = Mage::getSingleton('catalog/layer'); + $layer = $this->getLayer(); /* @var $layer Mage_Catalog_Model_Layer */ if ($this->getShowRootCategory()) { $this->setCategoryId(Mage::app()->getStore()->getRootCategoryId()); @@ -91,9 +91,24 @@ protected function _getProductCollection() $layer->setCurrentCategory($origCategory); } } + return $this->_productCollection; } + /** + * Get catalog layer model + * + * @return Mage_Catalog_Model_Layer + */ + public function getLayer() + { + $layer = Mage::registry('current_layer'); + if ($layer) { + return $layer; + } + return Mage::getSingleton('catalog/layer'); + } + /** * Retrieve loaded category collection * @@ -148,7 +163,7 @@ protected function _beforeToHtml() $this->setChild('toolbar', $toolbar); Mage::dispatchEvent('catalog_block_product_list_collection', array( - 'collection'=>$this->_getProductCollection(), + 'collection' => $this->_getProductCollection() )); $this->_getProductCollection()->load(); @@ -172,6 +187,16 @@ public function getToolbarBlock() return $block; } + /** + * Retrieve additional blocks html + * + * @return string + */ + public function getAdditionalHtml() + { + return $this->getChildHtml('additional'); + } + /** * Retrieve list toolbar HTML * @@ -231,7 +256,6 @@ public function prepareSortableFieldsByCategory($category) { } } - return $this; } } diff --git a/app/code/core/Mage/Catalog/Block/Product/New.php b/app/code/core/Mage/Catalog/Block/Product/New.php index 12c6edc090..439789c73f 100644 --- a/app/code/core/Mage/Catalog/Block/Product/New.php +++ b/app/code/core/Mage/Catalog/Block/Product/New.php @@ -43,6 +43,13 @@ class Mage_Catalog_Block_Product_New extends Mage_Catalog_Block_Product_Abstract protected function _construct() { parent::_construct(); + + $this->addColumnCountLayoutDepend('empty', 6) + ->addColumnCountLayoutDepend('one_column', 5) + ->addColumnCountLayoutDepend('two_columns_left', 4) + ->addColumnCountLayoutDepend('two_columns_right', 4) + ->addColumnCountLayoutDepend('three_columns', 3); + $this->addData(array( 'cache_lifetime' => 86400, 'cache_tags' => array(Mage_Catalog_Model_Product::CACHE_TAG), diff --git a/app/code/core/Mage/Catalog/Block/Product/Price.php b/app/code/core/Mage/Catalog/Block/Product/Price.php index 8705c55257..b1a2d57866 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Price.php +++ b/app/code/core/Mage/Catalog/Block/Product/Price.php @@ -97,4 +97,17 @@ public function getTierPrices($product = null) return $res; } + + /** + * Prevent displaying if the price is not available + * + * @return string + */ + protected function _toHtml() + { + if (!$this->getProduct() || $this->getProduct()->getCanShowPrice() === false) { + return ''; + } + return parent::_toHtml(); + } } diff --git a/app/code/core/Mage/Catalog/Block/Product/View/Attributes.php b/app/code/core/Mage/Catalog/Block/Product/View/Attributes.php index 3046359459..1c0bea03c2 100644 --- a/app/code/core/Mage/Catalog/Block/Product/View/Attributes.php +++ b/app/code/core/Mage/Catalog/Block/Product/View/Attributes.php @@ -59,21 +59,25 @@ public function getAdditionalData(array $excludeAttr = array()) foreach ($attributes as $attribute) { // if ($attribute->getIsVisibleOnFront() && $attribute->getIsUserDefined() && !in_array($attribute->getAttributeCode(), $excludeAttr)) { if ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)) { - $value = $attribute->getFrontend()->getValue($product); + if (!$product->hasData($attribute->getAttributeCode())) { + $value = Mage::helper('catalog')->__('N/A'); + } + elseif ((string)$value == '') { + $value = Mage::helper('catalog')->__('No'); + } + // TODO this is temporary skipping eco taxes - if (is_string($value)) { - if (strlen($value) && $product->hasData($attribute->getAttributeCode())) { - if ($attribute->getFrontendInput() == 'price') { - $value = Mage::app()->getStore()->convertPrice($value,true); - } - $data[$attribute->getAttributeCode()] = array( - 'label' => $attribute->getStoreLabel(), - 'value' => $value, - 'code' => $attribute->getAttributeCode() - ); + if (is_string($value) && strlen($value)) { + if ($attribute->getFrontendInput() == 'price') { + $value = Mage::app()->getStore()->convertPrice($value,true); } + $data[$attribute->getAttributeCode()] = array( + 'label' => $attribute->getStoreLabel(), + 'value' => $value, + 'code' => $attribute->getAttributeCode() + ); } } } diff --git a/app/code/core/Mage/Catalog/Block/Product/View/Type/Configurable.php b/app/code/core/Mage/Catalog/Block/Product/View/Type/Configurable.php index 18c467a3a5..ed65c987fd 100644 --- a/app/code/core/Mage/Catalog/Block/Product/View/Type/Configurable.php +++ b/app/code/core/Mage/Catalog/Block/Product/View/Type/Configurable.php @@ -116,14 +116,21 @@ public function getJsonConfig() if(!$this->_validateAttributeValue($attributeId, $value, $options)) { continue; } + $this->getProduct()->setConfigurablePrice($this->_preparePrice($value['pricing_value'], $value['is_percent'])); + Mage::dispatchEvent( + 'catalog_product_type_configurable_price', + array('product' => $this->getProduct()) + ); + $configurablePrice = $this->getProduct()->getConfigurablePrice(); $info['options'][] = array( - 'id' => $value['value_index'], - 'label' => $value['label'], - 'price' => $this->_preparePrice($value['pricing_value'], $value['is_percent']), - 'products' => isset($options[$attributeId][$value['value_index']]) ? $options[$attributeId][$value['value_index']] : array(), + 'id' => $value['value_index'], + 'label' => $value['label'], + 'price' => $configurablePrice, + 'oldPrice' => $this->_preparePrice($value['pricing_value'], $value['is_percent']), + 'products' => isset($options[$attributeId][$value['value_index']]) ? $options[$attributeId][$value['value_index']] : array(), ); - $optionPrices[] = $this->_preparePrice($value['pricing_value'], $value['is_percent']); + $optionPrices[] = $configurablePrice; //$this->_registerAdditionalJsPrice($value['pricing_value'], $value['is_percent']); } } @@ -208,7 +215,7 @@ protected function _validateAttributeInfo(&$info) protected function _preparePrice($price, $isPercent=false) { if ($isPercent && !empty($price)) { - $price = $this->getProduct()->getFinalPrice()*$price/100; + $price = $this->getProduct()->getPrice()*$price/100; } return $this->_registerJsPrice($this->_convertPrice($price, true)); diff --git a/app/code/core/Mage/Catalog/Block/Product/Widget/New.php b/app/code/core/Mage/Catalog/Block/Product/Widget/New.php index 42ec65b011..d2f4125257 100644 --- a/app/code/core/Mage/Catalog/Block/Product/Widget/New.php +++ b/app/code/core/Mage/Catalog/Block/Product/Widget/New.php @@ -42,10 +42,7 @@ class Mage_Catalog_Block_Product_Widget_New protected function _construct() { parent::_construct(); - $this->addColumnCountLayoutDepend('one_column', 5) - ->addColumnCountLayoutDepend('two_columns_left', 4) - ->addColumnCountLayoutDepend('two_columns_right', 4) - ->addColumnCountLayoutDepend('three_columns', 3); + $this->addPriceBlockType('bundle', 'bundle/catalog_product_price', 'bundle/catalog/product/price.phtml'); } diff --git a/app/code/core/Mage/Catalog/Block/Widget/Link.php b/app/code/core/Mage/Catalog/Block/Widget/Link.php index 7d5acd3552..989aa2b62e 100644 --- a/app/code/core/Mage/Catalog/Block/Widget/Link.php +++ b/app/code/core/Mage/Catalog/Block/Widget/Link.php @@ -65,7 +65,13 @@ class Mage_Catalog_Block_Widget_Link public function getHref() { if (!$this->_href) { - $store = Mage::app()->getStore(); + + if($this->hasStoreId()) { + $store = Mage::app()->getStore($this->getStoreId()); + } else { + $store = Mage::app()->getStore(); + } + /* @var $store Mage_Core_Model_Store */ $href = ""; if ($this->getData('id_path')) { @@ -80,6 +86,11 @@ public function getHref() $this->_href = $store->getUrl('', array('_direct' => $href)); } + if(strpos($this->_href, "___store") === false){ + $symbol = (strpos($this->_href, "?") === false) ? "?" : "&"; + $this->_href = $this->_href . $symbol . "___store=" . $store->getCode(); + } + return $this->_href; } diff --git a/app/code/core/Mage/Catalog/Helper/Output.php b/app/code/core/Mage/Catalog/Helper/Output.php index aba5f0142b..3dcb223d8a 100644 --- a/app/code/core/Mage/Catalog/Helper/Output.php +++ b/app/code/core/Mage/Catalog/Helper/Output.php @@ -122,7 +122,9 @@ public function productAttribute($product, $attributeHtml, $attributeName) $attribute = Mage::getSingleton('eav/config')->getAttribute('catalog_product', $attributeName); if ($attribute && $attribute->getId() && ($attribute->getFrontendInput() != 'media_image') && (!$attribute->getIsHtmlAllowedOnFront() && !$attribute->getIsWysiwygEnabled())) { - $attributeHtml = $this->htmlEscape($attributeHtml); + if ($attribute->getFrontendInput() != 'price') { + $attributeHtml = $this->escapeHtml($attributeHtml); + } if ($attribute->getFrontendInput() == 'textarea') { $attributeHtml = nl2br($attributeHtml); } @@ -132,10 +134,12 @@ public function productAttribute($product, $attributeHtml, $attributeName) $attributeHtml = $this->_getTemplateProcessor()->filter($attributeHtml); } } + $attributeHtml = $this->process('productAttribute', $attributeHtml, array( 'product' => $product, 'attribute' => $attributeName )); + return $attributeHtml; } @@ -153,7 +157,7 @@ public function categoryAttribute($category, $attributeHtml, $attributeName) if ($attribute && ($attribute->getFrontendInput() != 'image') && (!$attribute->getIsHtmlAllowedOnFront() && !$attribute->getIsWysiwygEnabled())) { - $attributeHtml = $this->htmlEscape($attributeHtml); + $attributeHtml = $this->escapeHtml($attributeHtml); } if ($attribute->getIsHtmlAllowedOnFront() && $attribute->getIsWysiwygEnabled()) { if (Mage::helper('catalog')->isUrlDirectivesParsingAllowed()) { diff --git a/app/code/core/Mage/Catalog/Helper/Product.php b/app/code/core/Mage/Catalog/Helper/Product.php index 14a7512dbf..4bb195bb77 100644 --- a/app/code/core/Mage/Catalog/Helper/Product.php +++ b/app/code/core/Mage/Catalog/Helper/Product.php @@ -199,4 +199,64 @@ public function canUseCanonicalTag($store = null) { return Mage::getStoreConfig(self::XML_PATH_USE_PRODUCT_CANONICAL_TAG, $store); } + + /** + * Return information array of product attribute input types + * Only a small number of settings returned, so we won't break anything in current dataflow + * As soon as development process goes on we need to add there all possible settings + * + * @param string $inputType + * @return array + */ + public function getAttributeInputTypes($inputType = null) + { + /** + * @todo specify there all relations for properties depending on input type + */ + $inputTypes = array( + 'multiselect' => array( + 'backend_model' => 'eav/entity_attribute_backend_array' + ), + 'boolean' => array( + 'source_model' => 'eav/entity_attribute_source_boolean' + ) + ); + + if (is_null($inputType)) { + return $inputTypes; + } else if (isset($inputTypes[$inputType])) { + return $inputTypes[$inputType]; + } + return array(); + } + + /** + * Return default attribute backend model by input type + * + * @param string $inputType + * @return string|null + */ + public function getAttributeBackendModelByInputType($inputType) + { + $inputTypes = $this->getAttributeInputTypes(); + if (!empty($inputTypes[$inputType]['backend_model'])) { + return $inputTypes[$inputType]['backend_model']; + } + return null; + } + + /** + * Return default attribute source model by input type + * + * @param string $inputType + * @return string|null + */ + public function getAttributeSourceModelByInputType($inputType) + { + $inputTypes = $this->getAttributeInputTypes(); + if (!empty($inputTypes[$inputType]['source_model'])) { + return $inputTypes[$inputType]['source_model']; + } + return null; + } } diff --git a/app/code/core/Mage/Catalog/Model/Abstract.php b/app/code/core/Mage/Catalog/Model/Abstract.php index 885daaebf4..c86ca4b138 100644 --- a/app/code/core/Mage/Catalog/Model/Abstract.php +++ b/app/code/core/Mage/Catalog/Model/Abstract.php @@ -49,6 +49,13 @@ abstract class Mage_Catalog_Model_Abstract extends Mage_Core_Model_Abstract */ protected $_defaultValues = array(); + /** + * This array contains codes of attributes which have value in current store + * + * @var array + */ + protected $_storeValuesFlags = array(); + /** * Locked attributes * @@ -264,6 +271,30 @@ public function getAttributeDefaultValue($attributeCode) return array_key_exists($attributeCode, $this->_defaultValues) ? $this->_defaultValues[$attributeCode] : false; } + /** + * Set attribute code flag if attribute has value in current store and does not use + * value of default store as value + * + * @param string $attributeCode + * @return Mage_Catalog_Model_Abstract + */ + public function setExistsStoreValueFlag($attributeCode) + { + $this->_storeValuesFlags[$attributeCode] = true; + return $this; + } + + /** + * Check if object attribute has value in current store + * + * @param string $attributeCode + * @return bool + */ + public function getExistsStoreValueFlag($attributeCode) + { + return array_key_exists($attributeCode, $this->_storeValuesFlags); + } + /** * Before save unlock attributes * diff --git a/app/code/core/Mage/Catalog/Model/Category.php b/app/code/core/Mage/Catalog/Model/Category.php index 153f4da64b..e5e4d915c6 100644 --- a/app/code/core/Mage/Catalog/Model/Category.php +++ b/app/code/core/Mage/Catalog/Model/Category.php @@ -96,11 +96,11 @@ class Mage_Catalog_Model_Category extends Mage_Catalog_Model_Abstract */ private $_designAttributes = array( 'custom_design', - 'custom_design_apply', 'custom_design_from', 'custom_design_to', 'page_layout', - 'custom_layout_update' + 'custom_layout_update', + 'custom_apply_to_products' ); /** @@ -182,6 +182,11 @@ public function getTreeModelInstance() */ public function move($parentId, $afterCategoryId) { + /** + * Setting affected category ids for third party engine index refresh + */ + $this->setMovedCategoryId($this->getId()); + /** * Validate new parent category id. (category model is used for backward * compatibility in event params) @@ -220,7 +225,9 @@ public function move($parentId, $afterCategoryId) Mage::dispatchEvent('catalog_category_tree_move_after', $eventParams); $this->_getResource()->commit(); + // Set data for indexer $this->setAffectedCategoryIds(array($this->getId(), $this->getParentId(), $parentId)); + $moveComplete = true; } catch (Exception $e) { $this->_getResource()->rollBack(); @@ -407,6 +414,7 @@ public function getUrl() if ($this->hasData('request_path') && $this->getRequestPath() != '') { $this->setData('url', $this->getUrlInstance()->getDirectUrl($this->getRequestPath())); + Varien_Profiler::stop('REWRITE: '.__METHOD__); return $this->getData('url'); } @@ -486,7 +494,8 @@ public function getImageUrl() */ public function getUrlPath() { - if ($path = $this->getData('url_path')) { + $path = $this->getData('url_path'); + if ($path) { return $path; } @@ -509,7 +518,10 @@ public function getUrlPath() */ public function getParentCategory() { - return Mage::getModel('catalog/category')->load($this->getParentId()); + if (!$this->hasData('parent_category')) { + $this->setData('parent_category', Mage::getModel('catalog/category')->load($this->getParentId())); + } + return $this->_getData('parent_category'); } /** @@ -582,7 +594,7 @@ private function _getAttribute($attributeCode) /** * Get all children categories IDs * - * @param boolean $asArray return resul as array instead of comma-separated list of IDs + * @param boolean $asArray return result as array instead of comma-separated list of IDs * @return array|string */ public function getAllChildren($asArray = false) @@ -819,6 +831,16 @@ public function getChildrenCategories() return $this->getResource()->getChildrenCategories($this); } + /** + * Return parent category of current category with own custom design settings + * + * @return Mage_Catalog_Model_Category + */ + public function getParentDesignCategory() + { + return $this->getResource()->getParentDesignCategory($this); + } + /** * Check category is in Root Category list * diff --git a/app/code/core/Mage/Catalog/Model/Category/Api.php b/app/code/core/Mage/Catalog/Model/Category/Api.php index 6734aa4ec9..45aa064b73 100644 --- a/app/code/core/Mage/Catalog/Model/Category/Api.php +++ b/app/code/core/Mage/Catalog/Model/Category/Api.php @@ -54,9 +54,20 @@ public function level($website = null, $store = null, $categoryId = null) if (null !== $website) { try { $website = Mage::app()->getWebsite($website); - foreach ($website->getStores() as $store) { - /* @var $store Mage_Core_Model_Store */ - $ids[] = $store->getRootCategoryId(); + 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()); @@ -81,7 +92,7 @@ public function level($website = null, $store = null, $categoryId = null) } // load all root categories else { - $ids = Mage_Catalog_Model_Category::TREE_ROOT_ID; + $ids = (null === $categoryId)? Mage_Catalog_Model_Category::TREE_ROOT_ID : $categoryId; } $collection = Mage::getModel('catalog/category')->getCollection() @@ -333,30 +344,18 @@ public function move($categoryId, $parentId, $afterId = null) $category = $this->_initCategory($categoryId); $parent_category = $this->_initCategory($parentId); - $tree = Mage::getResourceModel('catalog/category_tree') - ->load(); - - $node = $tree->getNodeById($category->getId()); - $newParentNode = $tree->getNodeById($parent_category->getId()); - - if (!$node || !$node->getId()) { - $this->_fault('not_exists'); - } - // if $afterId is null - move category to the down if ($afterId === null && $parent_category->hasChildren()) { $parentChildren = $parent_category->getChildren(); $afterId = array_pop(explode(',', $parentChildren)); } - $prevNode = $tree->getNodeById($afterId); - - if (!$prevNode || !$prevNode->getId()) { - $prevNode = null; + 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 { - $tree->move($node, $newParentNode, $prevNode); + $category->move($parentId, $afterId); } catch (Mage_Core_Exception $e) { $this->_fault('not_moved', $e->getMessage()); } 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 aa8c60d366..bd8ead0102 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 @@ -62,7 +62,9 @@ public function afterSave($object) $object->setData($this->getAttribute()->getName(), $uploader->getUploadedFileName()); $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName()); } catch (Exception $e) { - Mage::logException($e); + if ($e->getCode() != Varien_File_Uploader::TMP_NAME_EMPTY) { + Mage::logException($e); + } /** @TODO ??? */ return; } diff --git a/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Sortby.php b/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Sortby.php index 7a8921fb46..7012aab682 100644 --- a/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Sortby.php +++ b/app/code/core/Mage/Catalog/Model/Category/Attribute/Backend/Sortby.php @@ -43,23 +43,51 @@ class Mage_Catalog_Model_Category_Attribute_Backend_Sortby */ public function validate($object) { - if (!parent::validate($object)) { - return false; + $attributeCode = $this->getAttribute()->getName(); + $postDataConfig = ($object->getData('use_post_data_config'))? $object->getData('use_post_data_config') : array(); + + $isUseConfig = false; + if ($postDataConfig) { + $isUseConfig = in_array($attributeCode, $postDataConfig); + } + + if ($this->getAttribute()->getIsRequired()) { + $attributeValue = $object->getData($attributeCode); + if ($this->getAttribute()->isValueEmpty($attributeValue)) { + if (is_array($attributeValue) && count($attributeValue)>0) { + } else { + if(!$isUseConfig) { + return false; + } + } + } } - $attributeCode = $this->getAttribute()->getName(); + if ($this->getAttribute()->getIsUnique()) { + if (!$this->getAttribute()->getEntity()->checkAttributeUniqueValue($this->getAttribute(), $object)) { + $label = $this->getAttribute()->getFrontend()->getLabel(); + Mage::throwException(Mage::helper('eav')->__('The value of attribute "%s" must be unique.', $label)); + } + } + if ($attributeCode == 'default_sort_by') { if ($available = $object->getData('available_sort_by')) { if (!is_array($available)) { $available = explode(',', $available); } - if (!in_array($object->getData($attributeCode), $available)) { + $data = (!in_array('default_sort_by', $postDataConfig))? $object->getData($attributeCode): + Mage::getStoreConfig("catalog/frontend/default_sort_by"); + if (!in_array($data, $available)) { + Mage::throwException(Mage::helper('eav')->__('Default Product Listing Sort by not exists on Available Product Listing Sort By')); + } + } else { + if (!in_array('available_sort_by', $postDataConfig)) { Mage::throwException(Mage::helper('eav')->__('Default Product Listing Sort by not exists on Available Product Listing Sort By')); } } } - return true; + return true; } /** diff --git a/app/code/core/Mage/Catalog/Model/Category/Indexer/Product.php b/app/code/core/Mage/Catalog/Model/Category/Indexer/Product.php index 627df87f68..a1d669d287 100644 --- a/app/code/core/Mage/Catalog/Model/Category/Indexer/Product.php +++ b/app/code/core/Mage/Catalog/Model/Category/Indexer/Product.php @@ -93,7 +93,7 @@ public function getDescription() */ public function matchEvent(Mage_Index_Model_Event $event) { - $data = $event->getNewData(); + $data = $event->getNewData(); $resultKey = 'catalog_category_product_match_result'; if (isset($data[$resultKey])) { return $data[$resultKey]; diff --git a/app/code/core/Mage/Catalog/Model/Convert/Adapter/Product.php b/app/code/core/Mage/Catalog/Model/Convert/Adapter/Product.php index 760cc78ade..d557a378f3 100644 --- a/app/code/core/Mage/Catalog/Model/Convert/Adapter/Product.php +++ b/app/code/core/Mage/Catalog/Model/Convert/Adapter/Product.php @@ -95,7 +95,7 @@ public function load() { $attrFilterArray = array(); $attrFilterArray ['name'] = 'like'; - $attrFilterArray ['sku'] = 'like'; + $attrFilterArray ['sku'] = 'startsWith'; $attrFilterArray ['type'] = 'eq'; $attrFilterArray ['attribute_set'] = 'eq'; $attrFilterArray ['visibility'] = 'eq'; @@ -597,7 +597,7 @@ public function saveRow(array $importData) if (isset($importData['websites'])) { $websiteIds = $product->getWebsiteIds(); - if (!is_array($websiteIds)) { + if (!is_array($websiteIds) || !$store->getId()) { $websiteIds = array(); } $websiteCodes = explode(',', $importData['websites']); @@ -621,6 +621,9 @@ public function saveRow(array $importData) if (in_array($field, $this->_imageFields)) { continue; } + if (is_null($value)) { + continue; + } $attribute = $this->getAttribute($field); if (!$attribute) { diff --git a/app/code/core/Mage/Catalog/Model/Convert/Parser/Product.php b/app/code/core/Mage/Catalog/Model/Convert/Parser/Product.php index 81dca4941e..b60fe7e14c 100644 --- a/app/code/core/Mage/Catalog/Model/Convert/Parser/Product.php +++ b/app/code/core/Mage/Catalog/Model/Convert/Parser/Product.php @@ -389,7 +389,6 @@ public function unparse() foreach ($entityIds as $i => $entityId) { $product = $this->getProductModel() - ->reset() ->setStoreId($this->getStoreId()) ->load($entityId); $this->setProductTypeInstance($product); @@ -473,6 +472,7 @@ public function unparse() ->setBatchData($row) ->setStatus(1) ->save(); + $product->reset(); } return $this; diff --git a/app/code/core/Mage/Catalog/Model/Design.php b/app/code/core/Mage/Catalog/Model/Design.php index ee2cead4ff..ec032a302c 100644 --- a/app/code/core/Mage/Catalog/Model/Design.php +++ b/app/code/core/Mage/Catalog/Model/Design.php @@ -38,8 +38,8 @@ class Mage_Catalog_Model_Design extends Mage_Core_Model_Abstract const APPLY_FOR_CATEGORY = 2; /** + * @deprecated after 1.4.1.0 * Category / Custom Design / Apply To constants - * */ const CATEGORY_APPLY_CATEGORY_AND_PRODUCT_RECURSIVE = 1; const CATEGORY_APPLY_CATEGORY_ONLY = 2; @@ -49,6 +49,8 @@ class Mage_Catalog_Model_Design extends Mage_Core_Model_Abstract /** * Apply design from catalog object * + * @deprecated after 1.4.2.0-beta1 + * * @param array|Mage_Catalog_Model_Category|Mage_Catalog_Model_Product $object * @param int $calledFrom * @return Mage_Catalog_Model_Design @@ -62,7 +64,7 @@ public function applyDesign($object, $calledFrom = 0) if (Mage::helper('catalog/category_flat')->isEnabled()) { $this->_applyDesign($object, $calledFrom); } else { - $this->_applyDesignRecursively($object, $calledFrom); + $this->_inheritDesign($object, $calledFrom); } return $this; @@ -81,9 +83,27 @@ protected function _apply($package, $theme) ->setTheme($theme); } + /** + * Apply custom design + * + * @param string $design + */ + public function applyCustomDesign($design) + { + $designInfo = explode('/', $design); + if (count($designInfo) != 2) { + return false; + } + $package = $designInfo[0]; + $theme = $designInfo[1]; + $this->_apply($package, $theme); + } + /** * Check is allow apply for * + * @deprecated after 1.4.1.0 + * * @param int $applyForObject * @param int $applyTo * @param int $pass @@ -92,6 +112,7 @@ protected function _apply($package, $theme) protected function _isApplyFor($applyForObject, $applyTo, $pass = 0) { $hasError = false; + if ($pass == 0) { switch ($applyForObject) { case self::APPLY_FOR_CATEGORY: @@ -134,12 +155,15 @@ protected function _isApplyFor($applyForObject, $applyTo, $pass = 0) break; } } + return !$hasError; } /** * Check and apply design * + * @deprecated after 1.4.2.0-beta1 + * * @param string $design * @param array $date */ @@ -167,18 +191,72 @@ protected function _isApplyDesign($design, array $date) return false; } + /** + * Recursively apply design + * + * @deprecated after 1.4.2.0-beta1 + * + * @param Varien_Object $object + * @param int $calledFrom + * + * @return Mage_Catalog_Model_Design + */ + protected function _inheritDesign($object, $calledFrom = 0) + { + $useParentSettings = false; + if ($object instanceof Mage_Catalog_Model_Product) { + $category = $object->getCategory(); + + if ($category && $category->getId()) { + return $this->_inheritDesign($category, $calledFrom); + } + } + elseif ($object instanceof Mage_Catalog_Model_Category) { + $category = $object->getParentCategory(); + + $useParentSettings = $object->getCustomUseParentSettings(); + if ($useParentSettings) { + if ($category && + $category->getId() && + $category->getLevel() > 1 && + $category->getId() != Mage_Catalog_Model_Category::TREE_ROOT_ID) { + return $this->_inheritDesign($category, $calledFrom); + } + } + + if ($calledFrom == self::APPLY_FOR_PRODUCT) { + $applyToProducts = $object->getCustomApplyToProducts(); + if (!$applyToProducts) { + return $this; + } + } + } + + if (!$useParentSettings) { + $design = $object->getCustomDesign(); + $date = $object->getCustomDesignDate(); + $this->_isApplyDesign($design, $date); + } + + return $this; + } + /** * Apply design recursively (if using EAV) * + * @deprecated after 1.4.1.0 + * * @param Varien_Object $object * @param int $calledFrom + * @param int $pass + * * @return Mage_Catalog_Model_Design */ protected function _applyDesignRecursively($object, $calledFrom = 0, $pass = 0) { - $design = $object->getCustomDesign(); - $date = $object->getCustomDesignDate(); - $applyTo = $object->getCustomDesignApply(); + $design = $object->getCustomDesign(); + $date = $object->getCustomDesignDate(); + $applyTo = $object->getCustomDesignApply(); $checkAndApply = $this->_isApplyFor($calledFrom, $applyTo, $pass) && $this->_isApplyDesign($design, $date); @@ -197,7 +275,7 @@ protected function _applyDesignRecursively($object, $calledFrom = 0, $pass = 0) $category = $object->getParentCategory(); } - if ($category && $category->getId()){ + if ($category && $category->getId()) { $this->_applyDesignRecursively($category, $calledFrom, $pass); } @@ -205,12 +283,7 @@ protected function _applyDesignRecursively($object, $calledFrom = 0, $pass = 0) } /** - * Apply design (if using Flat Category) - * - * @param Varien_Object|array $designUpdateData - * @param int $calledFrom - * @param bool $loaded - * @return Mage_Catalog_Model_Design + * @deprecated after 1.4.2.0-beta1 */ protected function _applyDesign($designUpdateData, $calledFrom = 0, $loaded = false, $pass = 0) { @@ -221,9 +294,9 @@ protected function _applyDesign($designUpdateData, $calledFrom = 0, $loaded = fa $objects = &$designUpdateData; } foreach ($objects as $object) { - $design = $object->getCustomDesign(); - $date = $object->getCustomDesignDate(); - $applyTo = $object->getCustomDesignApply(); + $design = $object->getCustomDesign(); + $date = $object->getCustomDesignDate(); + $applyTo = $object->getCustomDesignApply(); $checkAndApply = $this->_isApplyFor($calledFrom, $applyTo, $pass) && $this->_isApplyDesign($design, $date); @@ -255,4 +328,78 @@ protected function _applyDesign($designUpdateData, $calledFrom = 0, $loaded = fa } return $this; } + + /** + * Get custom layout settings + * + * @param Mage_Catalog_Model_Category|Mage_Catalog_Model_Product $object + * @return Varien_Object + */ + public function getDesignSettings($object) + { + if ($object instanceof Mage_Catalog_Model_Product) { + $currentCategory = $object->getCategory(); + } else { + $currentCategory = $object; + } + + $category = null; + if ($currentCategory) { + $category = $currentCategory->getParentDesignCategory($currentCategory); + } + + if ($object instanceof Mage_Catalog_Model_Product) { + if ($category && $category->getCustomApplyToProducts()) { + return $this->_mergeSettings($this->_extractSettings($category), $this->_extractSettings($object)); + } else { + return $this->_extractSettings($object); + } + } else { + return $this->_extractSettings($category); + } + } + + /** + * Extract custom layout settings from category or product object + * + * @param Mage_Catalog_Model_Category|Mage_Catalog_Model_Product $object + * @return Varien_Object + */ + protected function _extractSettings($object) + { + $settings = new Varien_Object; + if (!$object) { + return $settings; + } + $date = $object->getCustomDesignDate(); + if (array_key_exists('from', $date) && array_key_exists('to', $date) + && Mage::app()->getLocale()->isStoreDateInInterval(null, $date['from'], $date['to'])) { + $settings->setCustomDesign($object->getCustomDesign()) + ->setPageLayout($object->getPageLayout()) + ->setLayoutUpdates((array)$object->getCustomLayoutUpdate()); + } + return $settings; + } + + /** + * Merge custom design settings + * + * @param Varien_Object $categorySettings + * @param Varien_Object $productSettings + * @return Varien_Object + */ + protected function _mergeSettings($categorySettings, $productSettings) + { + if ($productSettings->getCustomDesign()) { + $categorySettings->setCustomDesign($productSettings->getCustomDesign()); + } + if ($productSettings->getPageLayout()) { + $categorySettings->setPageLayout($productSettings->getPageLayout()); + } + if ($productSettings->getLayoutUpdates()) { + $update = array_merge($categorySettings->getLayoutUpdates(), $productSettings->getLayoutUpdates()); + $categorySettings->setLayoutUpdates($update); + } + return $categorySettings; + } } diff --git a/app/code/core/Mage/Catalog/Model/Indexer/Url.php b/app/code/core/Mage/Catalog/Model/Indexer/Url.php index 141d8dc86b..b17f5c6f0c 100644 --- a/app/code/core/Mage/Catalog/Model/Indexer/Url.php +++ b/app/code/core/Mage/Catalog/Model/Indexer/Url.php @@ -31,7 +31,7 @@ * - Category save (changed assigned products list, category move, changed url key) * - Store save (new store creation, changed store group) - require reindex all data * - Store group save (changed root category or group website) - require reindex all data - * - Seo config saettings change - require reindex all data + * - Seo config settings change - require reindex all data */ class Mage_Catalog_Model_Indexer_Url extends Mage_Index_Model_Indexer_Abstract { @@ -220,19 +220,21 @@ protected function _processEvent(Mage_Index_Model_Event $event) } $urlModel = Mage::getSingleton('catalog/url'); - + // Force rewrites history saving $dataObject = $event->getDataObject(); if ($dataObject instanceof Varien_Object && $dataObject->hasData('save_rewrites_history')) { $urlModel->setShouldSaveRewritesHistory($dataObject->getData('save_rewrites_history')); } - + if(isset($data['rewrite_product_ids'])) { + $urlModel->clearStoreInvalidRewrites(); // Maybe some products were moved or removed from website foreach ($data['rewrite_product_ids'] as $productId) { $urlModel->refreshProductRewrite($productId); } } if (isset($data['rewrite_category_ids'])) { + $urlModel->clearStoreInvalidRewrites(); // Maybe some categories were moved foreach ($data['rewrite_category_ids'] as $categoryId) { $urlModel->refreshCategoryRewrite($categoryId); } diff --git a/app/code/core/Mage/Catalog/Model/Layer.php b/app/code/core/Mage/Catalog/Model/Layer.php index cecfc9ae00..07e53d50f2 100644 --- a/app/code/core/Mage/Catalog/Model/Layer.php +++ b/app/code/core/Mage/Catalog/Model/Layer.php @@ -67,9 +67,10 @@ public function getStateKey() { if ($this->_stateKey === null) { $this->_stateKey = 'STORE_'.Mage::app()->getStore()->getId() - . '_CAT_'.$this->getCurrentCategory()->getId() + . '_CAT_' . $this->getCurrentCategory()->getId() . '_CUSTGROUP_' . Mage::getSingleton('customer/session')->getCustomerGroupId(); } + return $this->_stateKey; } @@ -84,6 +85,7 @@ public function getStateTags(array $additionalTags = array()) $additionalTags = array_merge($additionalTags, array( Mage_Catalog_Model_Category::CACHE_TAG.$this->getCurrentCategory()->getId() )); + return $additionalTags; } @@ -96,8 +98,7 @@ public function getProductCollection() { if (isset($this->_productCollections[$this->getCurrentCategory()->getId()])) { $collection = $this->_productCollections[$this->getCurrentCategory()->getId()]; - } - else { + } else { $collection = $this->getCurrentCategory()->getProductCollection(); $this->prepareProductCollection($collection); $this->_productCollections[$this->getCurrentCategory()->getId()] = $collection; @@ -114,17 +115,16 @@ public function getProductCollection() */ public function prepareProductCollection($collection) { - $attributes = Mage::getSingleton('catalog/config') - ->getProductAttributes(); - $collection->addAttributeToSelect($attributes) + $collection + ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes()) ->addMinimalPrice() ->addFinalPrice() ->addTaxPercents() //->addStoreFilter() - ; + ->addUrlRewrite($this->getCurrentCategory()->getId()); + Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($collection); Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($collection); - $collection->addUrlRewrite($this->getCurrentCategory()->getId()); return $this; } @@ -141,12 +141,13 @@ public function apply() { $stateSuffix = ''; foreach ($this->getState()->getFilters() as $filterItem) { - $stateSuffix.= '_'.$filterItem->getFilter()->getRequestVar() + $stateSuffix .= '_' . $filterItem->getFilter()->getRequestVar() . '_' . $filterItem->getValueString(); } if (!empty($stateSuffix)) { $this->_stateKey = $this->getStateKey().$stateSuffix; } + return $this; } @@ -168,6 +169,7 @@ public function getCurrentCategory() $this->setData('current_category', $category); } } + return $category; } @@ -273,6 +275,7 @@ public function getState() $this->setData('state', $state); Varien_Profiler::stop(__METHOD__); } + return $state; } @@ -290,6 +293,7 @@ protected function _getSetIds() $setIds = $this->getProductCollection()->getSetIds(); $this->getAggregator()->saveCacheData($setIds, $key, $this->getStateTags()); } + return $setIds; } } diff --git a/app/code/core/Mage/Catalog/Model/Layer/Filter/Category.php b/app/code/core/Mage/Catalog/Model/Layer/Filter/Category.php index 6c878622d9..747f0a6dfb 100644 --- a/app/code/core/Mage/Catalog/Model/Layer/Filter/Category.php +++ b/app/code/core/Mage/Catalog/Model/Layer/Filter/Category.php @@ -86,7 +86,14 @@ public function getResetValue() public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) { $filter = (int) $request->getParam($this->getRequestVar()); + if (!$filter) { + return $this; + } $this->_categoryId = $filter; + + $category = $this->getCategory(); + Mage::register('current_category_filter', $category); + $this->_appliedCategory = Mage::getModel('catalog/category') ->setStoreId(Mage::app()->getStore()->getId()) ->load($filter); diff --git a/app/code/core/Mage/Catalog/Model/Layer/Filter/Decimal.php b/app/code/core/Mage/Catalog/Model/Layer/Filter/Decimal.php index 261f7023af..875017c189 100644 --- a/app/code/core/Mage/Catalog/Model/Layer/Filter/Decimal.php +++ b/app/code/core/Mage/Catalog/Model/Layer/Filter/Decimal.php @@ -171,18 +171,18 @@ public function getMinValue() public function getRange() { $range = $this->getData('range'); - if (is_null($range)) { - $max = $this->getMaxValue(); + if (!$range) { + $maxValue = $this->getMaxValue(); $index = 1; do { - $range = pow(10, (strlen(floor($max)) - $index)); + $range = pow(10, (strlen(floor($maxValue)) - $index)); $items = $this->getRangeItemCounts($range); - $index ++; + $index++; } - while($range > self::MIN_RANGE_POWER && count($items) < 2); - + while ($range > self::MIN_RANGE_POWER && count($items) < 2); $this->setData('range', $range); } + return $range; } diff --git a/app/code/core/Mage/Catalog/Model/Layer/Filter/Price.php b/app/code/core/Mage/Catalog/Model/Layer/Filter/Price.php index 1128981a2f..a8d83a717f 100644 --- a/app/code/core/Mage/Catalog/Model/Layer/Filter/Price.php +++ b/app/code/core/Mage/Catalog/Model/Layer/Filter/Price.php @@ -33,6 +33,11 @@ */ class Mage_Catalog_Model_Layer_Filter_Price extends Mage_Catalog_Model_Layer_Filter_Abstract { + const XML_PATH_RANGE_CALCULATION = 'catalog/layered_navigation/price_range_calculation'; + const XML_PATH_RANGE_STEP = 'catalog/layered_navigation/price_range_step'; + + const RANGE_CALCULATION_AUTO = 'auto'; + const RANGE_CALCULATION_MANUAL = 'manual'; const MIN_RANGE_POWER = 10; /** @@ -73,18 +78,37 @@ protected function _getResource() public function getPriceRange() { $range = $this->getData('price_range'); - if (is_null($range)) { + if (!$range) { + $currentCategory = Mage::registry('current_category_filter'); + if ($currentCategory) { + $range = $currentCategory->getFilterPriceRange(); + } else { + $range = $this->getLayer()->getCurrentCategory()->getFilterPriceRange(); + } + $maxPrice = $this->getMaxPriceInt(); - $index = 1; - do { - $range = pow(10, (strlen(floor($maxPrice))-$index)); - $items = $this->getRangeItemCounts($range); - $index++; + if (!$range) { + $calculation = Mage::app()->getStore()->getConfig(self::XML_PATH_RANGE_CALCULATION); + if ($calculation == self::RANGE_CALCULATION_AUTO) { + $index = 1; + do { + $range = pow(10, (strlen(floor($maxPrice)) - $index)); + $items = $this->getRangeItemCounts($range); + $index++; + } + while($range > self::MIN_RANGE_POWER && count($items) < 2); + } else { + $range = Mage::app()->getStore()->getConfig(self::XML_PATH_RANGE_STEP); + } + } + + while (ceil($maxPrice / $range) > 25) { + $range *= 10; } - while($range>self::MIN_RANGE_POWER && count($items)<2); $this->setData('price_range', $range); } + return $range; } @@ -138,7 +162,7 @@ protected function _renderItemLabel($range, $value) /** * Get price aggreagation data cache key - * + * @deprecated after 1.4 * @return string */ protected function _getCacheKey() @@ -161,34 +185,27 @@ protected function _getCacheKey() */ protected function _getItemsData() { - $key = $this->_getCacheKey(); - - $data = $this->getLayer()->getAggregator()->getCacheData($key); - if ($data === null) { - $range = $this->getPriceRange(); - $dbRanges = $this->getRangeItemCounts($range); - $data = array(); - - foreach ($dbRanges as $index=>$count) { - $data[] = array( - 'label' => $this->_renderItemLabel($range, $index), - 'value' => $index . ',' . $range, - 'count' => $count, - ); - } + $range = $this->getPriceRange(); + $dbRanges = $this->getRangeItemCounts($range); + $data = array(); - $tags = array( - Mage_Catalog_Model_Product_Type_Price::CACHE_TAG, + foreach ($dbRanges as $index=>$count) { + $data[] = array( + 'label' => $this->_renderItemLabel($range, $index), + 'value' => $index . ',' . $range, + 'count' => $count, ); - $tags = $this->getLayer()->getStateTags($tags); - $this->getLayer()->getAggregator()->saveCacheData($data, $key, $tags); } + return $data; } /** * Apply price range filter to collection * + * @param Zend_Controller_Request_Abstract $request + * @param $filterBlock + * * @return Mage_Catalog_Model_Layer_Filter_Price */ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) @@ -211,7 +228,7 @@ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) if ((int)$index && (int)$range) { $this->setPriceRange((int)$range); - $this->_getResource()->applyFilterToCollection($this, $range, $index); + $this->_applyToCollection($range, $index); $this->getLayer()->getState()->addFilter( $this->_createItem($this->_renderItemLabel($range, $index), $filter) ); @@ -221,6 +238,19 @@ public function apply(Zend_Controller_Request_Abstract $request, $filterBlock) return $this; } + /** + * Apply filter value to product collection based on filter range and selected value + * + * @param int $range + * @param int $index + * @return Mage_Catalog_Model_Layer_Filter_Price + */ + protected function _applyToCollection($range, $index) + { + $this->_getResource()->applyFilterToCollection($this, $range, $index); + return $this; + } + /** * Retrieve active customer group id * diff --git a/app/code/core/Mage/Catalog/Model/Product.php b/app/code/core/Mage/Catalog/Model/Product.php index 920538d1a6..f107db734b 100644 --- a/app/code/core/Mage/Catalog/Model/Product.php +++ b/app/code/core/Mage/Catalog/Model/Product.php @@ -152,7 +152,7 @@ public function getUrlModel() * Validate Product Data * * @todo implement full validation process with errors returning which are ignoring now - * + * * @return Mage_Catalog_Model_Product */ public function validate() @@ -648,6 +648,19 @@ public function getFormatedPrice() return $this->getPriceModel()->getFormatedPrice($this); } + /** + * Sets final price of product + * + * This func is equal to magic 'setFinalPrice()', but added as a separate func, because in cart with bundle products it's called + * very often in Item->getProduct(). So removing chaing of magic with more cpu consuming algorithms gives nice optimization boost. + * + * @return array + */ + public function setFinalPrice($price) + { + $this->_data['final_price'] = $price; + } + /** * Get product final price * @@ -1188,7 +1201,7 @@ public function isSalable() 'product' => $this )); - $salable = $this->getTypeInstance(true)->isSalable($this); + $salable = $this->isAvailable(); $object = new Varien_Object(array( 'product' => $this, @@ -1201,6 +1214,16 @@ public function isSalable() return $object->getIsSalable(); } + /** + * Check whether the product type or stock allows to purchase the product + * + * @return bool + */ + public function isAvailable() + { + return $this->getTypeInstance(true)->isSalable($this); + } + /** * Check is a virtual product * Data helper wraper @@ -1645,6 +1668,12 @@ protected function _substractQtyFromQuotes() */ public function reset() { + foreach ($this->_data as $data){ + if (is_object($data) && method_exists($data, 'reset')){ + $data->reset(); + } + } + $this->setData(array()); $this->setOrigData(); $this->_customOptions = array(); @@ -1673,4 +1702,24 @@ public function getCacheIdTags() } return $tags; } + + /** + * Check for empty SKU on each product + * + * @param array $productIds + * @return boolean|null + */ + public function isProductsHasSku(array $productIds) + { + $products = $this->_getResource()->getProductsSku($productIds); + if (count($products)) { + foreach ($products as $product) { + if (empty($product['sku'])) { + return false; + } + } + return true; + } + return null; + } } diff --git a/app/code/core/Mage/Catalog/Model/Product/Api.php b/app/code/core/Mage/Catalog/Model/Product/Api.php index 1613eab2d6..4af35ff11c 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Api.php +++ b/app/code/core/Mage/Catalog/Model/Product/Api.php @@ -267,6 +267,8 @@ protected function _prepareDataForSave ($product, $productData) if (isset($productData['stock_data']) && is_array($productData['stock_data'])) { $product->setStockData($productData['stock_data']); + } else { + $product->setStockData(array('use_config_manage_stock' => 0)); } if (isset($productData['tier_price']) && is_array($productData['tier_price'])) { diff --git a/app/code/core/Mage/Catalog/Model/Product/Api/V2.php b/app/code/core/Mage/Catalog/Model/Product/Api/V2.php index 10009a1134..59db16024b 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Api/V2.php +++ b/app/code/core/Mage/Catalog/Model/Product/Api/V2.php @@ -308,8 +308,10 @@ protected function _prepareDataForSave ($product, $productData) foreach ($productData->stock_data as $key => $value) { $_stockData[$key] = $value; } - $product->setStockData($_stockData); + } else { + $_stockData = array('use_config_manage_stock' => 0); } + $product->setStockData($_stockData); if (property_exists($productData, 'tier_price')) { $tierPrices = Mage::getModel('catalog/product_attribute_tierprice_api_V2')->prepareTierPrices($product, $productData->tier_price); 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 22dbdfd55f..2406ec6791 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 @@ -113,7 +113,7 @@ public function beforeSave($object) } - + $clearImages = array(); $newImages = array(); $existImages = array(); @@ -148,7 +148,7 @@ public function beforeSave($object) foreach ($object->getMediaAttributes() as $mediaAttribute) { $mediaAttrCode = $mediaAttribute->getAttributeCode(); $attrData = $object->getData($mediaAttrCode); - + if (in_array($attrData, $clearImages)) { $object->setData($mediaAttrCode, false); } @@ -256,9 +256,8 @@ public function addImage(Mage_Catalog_Model_Product $product, $file, $mediaAttri $dispretionPath = Varien_File_Uploader::getDispretionPath($fileName); $fileName = $dispretionPath . DS . $fileName; - $fileName = $dispretionPath . DS - . Varien_File_Uploader::getNewFileName($this->_getConfig()->getTmpMediaPath($fileName)); - + $fileName = $this->_getNotDuplicatedFilename($fileName, $dispretionPath); + $ioAdapter = new Varien_Io_File(); $ioAdapter->setAllowCreateFolders(true); $distanationDirectory = dirname($this->_getConfig()->getTmpMediaPath($fileName)); @@ -556,4 +555,29 @@ public function duplicate($object) return $this; } + + /** + * Get filename which is not duplicated with other files in media temporary and media directories + * + * @param String $fileName + * @param String $dispretionPath + * @return String + */ + protected function _getNotDuplicatedFilename($fileName, $dispretionPath) + { + $fileMediaName = $dispretionPath . DS + . Varien_File_Uploader::getNewFileName($this->_getConfig()->getMediaPath($fileName)); + $fileTmpMediaName = $dispretionPath . DS + . Varien_File_Uploader::getNewFileName($this->_getConfig()->getTmpMediaPath($fileName)); + + if ($fileMediaName != $fileTmpMediaName) { + if ($fileMediaName != $fileName) { + return $this->_getNotDuplicatedFileName($fileMediaName, $dispretionPath); + } elseif ($fileTmpMediaName != $fileName) { + return $this->_getNotDuplicatedFilename($fileTmpMediaName, $dispretionPath); + } + } + + return $fileMediaName; + } } // Class Mage_Catalog_Model_Product_Attribute_Backend_Media End diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Tierprice.php index 451c325e0f..9d054e046d 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -152,6 +152,37 @@ public function validate($object) return true; } + /** + * Prepare tier prices data for website + * + * @param array $priceData + * @param string $productTypeId + * @param int $websiteId + * @return array + */ + public function preparePriceData(array $priceData, $productTypeId, $websiteId) + { + $rates = $this->_getWebsiteRates(); + $data = array(); + $price = Mage::getSingleton('catalog/product_type')->priceFactory($productTypeId); + foreach ($priceData as $v) { + $key = join('-', array($v['cust_group'], $v['price_qty'])); + if ($v['website_id'] == $websiteId) { + $data[$key] = $v; + $data[$key]['website_price'] = $v['price']; + } else if ($v['website_id'] == 0 && !isset($data[$key])) { + $data[$key] = $v; + $data[$key]['website_id'] = $websiteId; + if ($price->isTierPriceFixed()) { + $data[$key]['price'] = $v['price'] * $rates[$websiteId]['rate']; + $data[$key]['website_price'] = $v['price'] * $rates[$websiteId]['rate']; + } + } + } + + return $data; + } + /** * Assign tier prices to product data * @@ -177,24 +208,7 @@ public function afterLoad($object) } if (!$object->getData('_edit_mode') && $websiteId) { - $rates = $this->_getWebsiteRates(); - - $full = $data; - $data = array(); - foreach ($full as $v) { - $key = join('-', array($v['cust_group'], $v['price_qty'])); - if ($v['website_id'] == $websiteId) { - $data[$key] = $v; - $data[$key]['website_price'] = $v['price']; - } else if ($v['website_id'] == 0 && !isset($data[$key])) { - $data[$key] = $v; - $data[$key]['website_id'] = $websiteId; - if ($object->getPriceModel()->isTierPriceFixed()) { - $data[$key]['price'] = $v['price'] * $rates[$websiteId]['rate']; - $data[$key]['website_price'] = $v['price'] * $rates[$websiteId]['rate']; - } - } - } + $data = $this->preparePriceData($data, $object->getTypeId(), $websiteId); } $object->setData($this->getAttribute()->getName(), $data); 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 index 2a2e68dccc..ee9ea5503e 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api.php +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Media/Api.php @@ -114,6 +114,8 @@ public function info($productId, $file, $store = null, $identifierType = null) */ public function create($productId, $data, $store = null, $identifierType = null) { + $data = $this->_prepareImageData($data); + $product = $this->_initProduct($productId, $store, $identifierType); $gallery = $this->_getGalleryAttribute($product); @@ -189,6 +191,8 @@ public function create($productId, $data, $store = null, $identifierType = null) */ public function update($productId, $file, $data, $store = null, $identifierType = null) { + $data = $this->_prepareImageData($data); + $product = $this->_initProduct($productId, $store, $identifierType); $gallery = $this->_getGalleryAttribute($product); @@ -196,6 +200,29 @@ public function update($productId, $file, $data, $store = null, $identifierType 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('catalog')->__('Invalid image type.')); + } + + $fileContent = @base64_decode($data['file']['content'], true); + if (!$fileContent) { + $this->_fault('data_invalid', Mage::helper('catalog')->__('Image content is not valid base64 data.')); + } + + unset($data['file']['content']); + + $ioAdapter = new Varien_Io_File(); + try { + $fileName = Mage::getBaseDir('media'). DS . 'catalog' . DS . 'product' . $file; + $ioAdapter->open(array('path'=>dirname($fileName))); + $ioAdapter->write(basename($fileName), $fileContent, 0666); + + } catch(Exception $e) { + $this->_fault('not_created', Mage::helper('catalog')->__('Can\'t create image.')); + } + } $gallery->getBackend()->updateImage($product, $file, $data); @@ -290,6 +317,17 @@ public function types($setId) 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 * 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 index cd18d91945..a280df54c1 100644 --- 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 @@ -41,144 +41,13 @@ class Mage_Catalog_Model_Product_Attribute_Media_Api_V2 extends Mage_Catalog_Mod */ protected function _prepareImageData($data) { - $_imageData = array(); - if (isset($data->label)) { - $_imageData['label'] = $data->label; + if( !is_object($data) ) { + return parent::_prepareImageData($data); } - if (isset($data->position)) { - $_imageData['position'] = $data->position; + $_imageData = get_object_vars($data); + if( isset($data->file) && is_object($data->file) ) { + $_imageData['file'] = get_object_vars($data->file); } - if (isset($data->disabled)) { - $_imageData['disabled'] = $data->disabled; - } - if (isset($data->exclude)) { - $_imageData['exclude'] = $data->exclude; - } - return $_imageData; - } - - /** - * Create new image for product and return image filename - * - * @param int|string $productId - * @param array $data - * @param string|int $store - * @return string - */ - public function create($productId, $data, $store = null, $identifierType = null) - { - $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('catalog')->__('The image is not specified.')); - } - - if (!isset($this->_mimeTypes[$data->file->mime])) { - $this->_fault('data_invalid', Mage::helper('catalog')->__('Invalid image type.')); - } - - $fileContent = @base64_decode($data->file->content, true); - if (!$fileContent) { - $this->_fault('data_invalid', Mage::helper('catalog')->__('The image contents is not valid base64 data.')); - } - - unset($data->file->content); - - $tmpDirectory = Mage::getBaseDir('var') . DS . 'api' . DS . $this->_getSession()->getSessionId(); - - 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); - - // Adding image to gallery - $file = $gallery->getBackend()->addImage( - $product, - $tmpDirectory . DS . $fileName, - null, - true - ); - - // Remove temporary directory - $ioAdapter->rmdir($tmpDirectory, true); - - $_imageData = $this->_prepareImageData($data); - - $gallery->getBackend()->updateImage($product, $file, $_imageData); - - 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('catalog')->__('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) - { - $product = $this->_initProduct($productId, $store, $identifierType); - - $gallery = $this->_getGalleryAttribute($product); - - if (!$gallery->getBackend()->getImage($product, $file)) { - $this->_fault('not_exists'); - } - - $_imageData = $this->_prepareImageData($data); - - $gallery->getBackend()->updateImage($product, $file, $_imageData); - - 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; + return parent::_prepareImageData($_imageData); } } diff --git a/app/code/core/Mage/Catalog/Model/Product/Attribute/Source/Layout.php b/app/code/core/Mage/Catalog/Model/Product/Attribute/Source/Layout.php index 0240d0d3f6..d343f32312 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Attribute/Source/Layout.php +++ b/app/code/core/Mage/Catalog/Model/Product/Attribute/Source/Layout.php @@ -37,7 +37,7 @@ public function getAllOptions() { if (!$this->_options) { $this->_options = Mage::getSingleton('page/source_layout')->toOptionArray(); - array_unshift($this->_options, array('value'=>'', 'label'=>Mage::helper('catalog')->__('No layout updates.'))); + array_unshift($this->_options, array('value'=>'', 'label'=>Mage::helper('catalog')->__('No layout updates'))); } return $this->_options; } diff --git a/app/code/core/Mage/Catalog/Model/Product/Indexer/Price.php b/app/code/core/Mage/Catalog/Model/Product/Indexer/Price.php index dc7c34e7a1..59718dd0e2 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Indexer/Price.php +++ b/app/code/core/Mage/Catalog/Model/Product/Indexer/Price.php @@ -23,7 +23,6 @@ * @copyright Copyright (c) 2010 Magento 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_Indexer_Price extends Mage_Index_Model_Indexer_Abstract { /** @@ -95,7 +94,8 @@ protected function _getDependentAttributes() 'special_to_date', 'tax_class_id', 'status', - 'required_options' + 'required_options', + 'force_reindex_required' ); } diff --git a/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php b/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php index 1199907e26..1ee2ba47bf 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php +++ b/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php @@ -33,6 +33,12 @@ */ class Mage_Catalog_Model_Product_Option_Type_File extends Mage_Catalog_Model_Product_Option_Type_Default { + /** + * Url for custom option download controller + * @var string + */ + protected $_customOptionDownloadUrl = 'sales/download/downloadCustomOption'; + public function isCustomizedView() { return true; @@ -67,11 +73,13 @@ public function validateUserValue($values) $this->setIsValid(true); $option = $this->getOption(); - // Set option value from request (Admin/Front reorders) if (isset($values[$option->getId()]) && is_array($values[$option->getId()])) { if (isset($values[$option->getId()]['order_path'])) { - $orderFileFullPath = Mage::getBaseDir() . $values[$option->getId()]['order_path']; + $relPath = $this->getUseQuotePath() + ? $values[$option->getId()]['quote_path'] + : $values[$option->getId()]['order_path']; + $orderFileFullPath = Mage::getBaseDir() . $relPath; } else { $this->setUserValue(null); return $this; @@ -272,13 +280,14 @@ public function getFormattedOptionValue($optionValue) try { $value = unserialize($optionValue); - $value['url'] = array( - 'route' => 'sales/download/downloadCustomOption', - 'params' => array( + $customOptionUrlParams = $this->getCustomOptionUrlParams() + ? $this->getCustomOptionUrlParams() + : array( 'id' => $this->getQuoteItemOption()->getId(), 'key' => $value['secret_key'] - ) - ); + ); + + $value['url'] = array('route' => $this->_customOptionDownloadUrl, 'params' => $customOptionUrlParams); $this->_formattedOptionValue = $this->_getOptionHtml($value); $this->getQuoteItemOption()->setValue(serialize($value)); @@ -452,6 +461,18 @@ public function getOrderTargetDir($relative = false) return $this->getTargetDir($relative) . DS . 'order'; } + /** + * Set url to custom option download controller + * + * @param string $url + * @return Mage_Catalog_Model_Product_Option_Type_File + */ + public function setCustomOptionDownloadUrl($url) + { + $this->_customOptionDownloadUrl = $url; + return $this; + } + /** * Directory structure initializing */ diff --git a/app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php b/app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php index ac0f272db2..7ba5441657 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php +++ b/app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php @@ -458,6 +458,25 @@ public function save($product = null) return $this; } + /** + * Remove don't applicable attributes data + * + * @param Mage_Catalog_Model_Product $product + */ + protected function _removeNotApplicableAttributes($product = null) + { + $product = $this->getProduct($product); + $eavConfig = Mage::getSingleton('eav/config'); + $entityType = $product->getResource()->getEntityType(); + foreach ($eavConfig->getEntityAttributeCodes($entityType, $product) as $attributeCode) { + $attribute = $eavConfig->getAttribute($entityType, $attributeCode); + $applyTo = $attribute->getApplyTo(); + if (is_array($applyTo) && count($applyTo) > 0 && !in_array($product->getTypeId(), $applyTo)) { + $product->unsetData($attribute->getAttributeCode()); + } + } + } + /** * Before save type related data * @@ -466,6 +485,7 @@ public function save($product = null) */ public function beforeSave($product = null) { + $this->_removeNotApplicableAttributes($product); $this->getProduct($product)->canAffectOptions(true); return $this; } @@ -500,8 +520,26 @@ public function canUseQtyDecimals() */ public function getSku($product = null) { - $skuDelimiter = '-'; $sku = $this->getProduct($product)->getData('sku'); + if ($this->getProduct($product)->getCustomOption('option_ids')) { + $sku = $this->getOptionSku($product,$sku); + } + return $sku; + } + + /** + * Default action to get sku of product with option + * + * @param Mage_Catalog_Model_Product $product Product with Custom Options + * @param string $sku Product SKU without option + * @return string + */ + public function getOptionSku($product = null, $sku='') + { + $skuDelimiter = '-'; + if(empty($sku)){ + $sku = $this->getProduct($product)->getData('sku'); + } if ($optionIds = $this->getProduct($product)->getCustomOption('option_ids')) { foreach (explode(',', $optionIds->getValue()) as $optionId) { if ($option = $this->getProduct($product)->getOptionById($optionId)) { @@ -510,7 +548,7 @@ public function getSku($product = null) $group = $option->groupFactory($option->getType()) ->setOption($option)->setListener(new Varien_Object()); - + if ($optionSku = $group->getOptionSku($quoteItemOption->getValue(), $skuDelimiter)) { $sku .= $skuDelimiter . $optionSku; } @@ -528,7 +566,6 @@ public function getSku($product = null) } return $sku; } - /** * Default action to get weight of product * 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 4717ab0f3c..b5afd23fb2 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Type/Configurable.php +++ b/app/code/core/Mage/Catalog/Model/Product/Type/Configurable.php @@ -696,4 +696,23 @@ public function getProductsToPurchaseByReqGroups($product = null) $product = $this->getProduct($product); return array($this->getUsedProducts(null, $product)); } + + /** + * Get sku of product + * + * @param Mage_Catalog_Model_Product $product + * @return string + */ + public function getSku($product = null) + { + $sku = $this->getProduct($product)->getData('sku'); + if ($simpleOption = $this->getProduct($product)->getCustomOption('simple_product')) { + $simple_sku = $simpleOption->getProduct($product)->getSku(); + $sku = parent::getOptionSku($product, $simple_sku); + }else{ + $sku = parent::getSku($product); + } + + return $sku; + } } diff --git a/app/code/core/Mage/Catalog/Model/Product/Type/Configurable/Price.php b/app/code/core/Mage/Catalog/Model/Product/Type/Configurable/Price.php index 6b523a1ecf..1b2c57e303 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Type/Configurable/Price.php +++ b/app/code/core/Mage/Catalog/Model/Product/Type/Configurable/Price.php @@ -66,7 +66,12 @@ public function getFinalPrice($qty=null, $product) ); if($value) { if($value['pricing_value'] != 0) { - $finalPrice += $this->_calcSelectionPrice($value, $basePrice); + $product->setConfigurablePrice($this->_calcSelectionPrice($value, $basePrice)); + Mage::dispatchEvent( + 'catalog_product_type_configurable_price', + array('product' => $product) + ); + $finalPrice += $product->getConfigurablePrice(); } } } diff --git a/app/code/core/Mage/Catalog/Model/Product/Url.php b/app/code/core/Mage/Catalog/Model/Product/Url.php index fe32a188a1..9673a5dfea 100644 --- a/app/code/core/Mage/Catalog/Model/Product/Url.php +++ b/app/code/core/Mage/Catalog/Model/Product/Url.php @@ -186,10 +186,9 @@ public function getUrl(Mage_Catalog_Model_Product $product, $params = array()) if ($product->hasUrlDataObject()) { $requestPath = $product->getUrlDataObject()->getUrlRewrite(); $routeParams['_store'] = $product->getUrlDataObject()->getStoreId(); - } - else { + } else { $requestPath = $product->getRequestPath(); - if (empty($requestPath)) { + if (empty($requestPath) && $requestPath !== false) { $idPath = sprintf('product/%d', $product->getEntityId()); if ($categoryId) { $idPath = sprintf('%s/%d', $idPath, $categoryId); @@ -200,6 +199,8 @@ public function getUrl(Mage_Catalog_Model_Product $product, $params = array()) if ($rewrite->getId()) { $requestPath = $rewrite->getRequestPath(); $product->setRequestPath($requestPath); + } else { + $product->setRequestPath(false); } } } @@ -214,8 +215,7 @@ public function getUrl(Mage_Catalog_Model_Product $product, $params = array()) if (!empty($requestPath)) { $routeParams['_direct'] = $requestPath; - } - else { + } else { $routePath = 'catalog/product/view'; $routeParams['id'] = $product->getId(); $routeParams['s'] = $product->getUrlKey(); diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Abstract.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Abstract.php index e7260c7097..e8ea18da79 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Abstract.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Abstract.php @@ -109,6 +109,19 @@ protected function _getLoadAttributesSelect($object, $table) return $select; } + /** + * Prepare select object for loading entity attributes values + * + * @param array $selects + * @return Zend_Db_Select + */ + protected function _prepareLoadSelect(array $selects) + { + $select = parent::_prepareLoadSelect($selects); + $select->order('store_id'); + return $select; + } + /** * Initialize attribute value for object * @@ -121,8 +134,9 @@ protected function _setAttribteValue($object, $valueRow) $attribute = $this->getAttribute($valueRow['attribute_id']); if ($attribute) { $attributeCode = $attribute->getAttributeCode(); + $isDefaultStore = $valueRow['store_id'] == $this->getDefaultStoreId(); if (isset($this->_attributes[$valueRow['attribute_id']])) { - if ($valueRow['store_id'] == $this->getDefaultStoreId()) { + if ($isDefaultStore) { $object->setAttributeDefaultValue($attributeCode, $valueRow['value']); } else { @@ -137,6 +151,9 @@ protected function _setAttribteValue($object, $valueRow) $valueId = $valueRow['value_id']; $object->setData($attributeCode, $value); + if (!$isDefaultStore) { + $object->setExistsStoreValueFlag($attributeCode); + } $attribute->getBackend()->setValueId($valueId); } return $this; diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category.php index e30f300ef5..0eea4783ca 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category.php @@ -356,13 +356,18 @@ protected function _saveCategoryProducts($category) } if (!empty($insert) || !empty($update) || !empty($delete)) { - $category->setIsChangedProductList(true); /** * Moved to index */ //$categoryIds = explode('/', $category->getPath()); //$this->refreshProductIndex($categoryIds); + + /** + * Setting affected products to category for third party engine index refresh + */ + $productIds = array_keys($insert + $delete + $update); + $category->setAffectedProductIds($productIds); } return $this; @@ -564,7 +569,32 @@ public function getParentCategories($category) } /** - * Enter description here... + * Return parent category of current category with own custom design settings + * + * @param Mage_Catalog_Model_Category $category + * @return Mage_Catalog_Model_Category + */ + public function getParentDesignCategory($category) + { + $pathIds = array_reverse($category->getPathIds()); + $collection = $category->getCollection() + ->setStore(Mage::app()->getStore()) + ->addAttributeToSelect('custom_design') + ->addAttributeToSelect('custom_design_from') + ->addAttributeToSelect('custom_design_to') + ->addAttributeToSelect('page_layout') + ->addAttributeToSelect('custom_layout_update') + ->addAttributeToSelect('custom_apply_to_products') + ->addFieldToFilter('entity_id', array('in' => $pathIds)) + ->addFieldToFilter('custom_use_parent_settings', 0) + ->addFieldToFilter('level', array('neq' => 0)) + ->setOrder('level', 'DESC') + ->load(); + return $collection->getFirstItem(); + } + + /** + * Return child categories * * @param Mage_Catalog_Model_Category $category * @return unknown @@ -732,6 +762,10 @@ public function changeParent(Mage_Catalog_Model_Category $category, Mage_Catalog $data = array('path' => $newPath, 'level' => $newLevel, 'position'=>$position, 'parent_id'=>$newParent->getId()); $adapter->update($table, $data, $adapter->quoteInto('entity_id=?', $category->getId())); + + // Update category object to new data + $category->addData($data); + return $this; } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Attribute/Source/Layout.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Attribute/Source/Layout.php index 791e776efd..97523185b0 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Attribute/Source/Layout.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Attribute/Source/Layout.php @@ -43,7 +43,7 @@ public function getAllOptions() 'label'=>(string)$layoutConfig->label ); } - array_unshift($this->_options, array('value'=>'', 'label'=>Mage::helper('catalog')->__('No layout updates.'))); + array_unshift($this->_options, array('value'=>'', 'label'=>Mage::helper('catalog')->__('No layout updates'))); } return $this->_options; } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Flat.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Flat.php index da32b7ff44..086017f44f 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Flat.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Flat.php @@ -203,6 +203,7 @@ protected function _loadNodes($parentNode = null, $recursionLevel = 0, $storeId 'url_rewrite.category_id=main_table.entity_id AND url_rewrite.is_system=1 AND url_rewrite.product_id IS NULL AND url_rewrite.store_id="'.$storeId.'" AND url_rewrite.id_path LIKE "category/%"', array('request_path' => 'url_rewrite.request_path')) ->where('main_table.is_active = ?', '1') + ->where('main_table.include_in_menu', '1') // ->order('main_table.path', 'ASC') ->order('main_table.position', 'ASC'); @@ -327,6 +328,8 @@ public function getCategories($parent, $recursionLevel = 0, $sorted=false, $asCo ->addUrlRewriteToResult() ->addParentPathFilter($parentPath) ->addStoreFilter() + ->addIsActiveFilter() + ->addAttributeToFilter('include_in_menu', 1) ->addSortedField($sorted); if ($toLoad) { return $collection->load(); @@ -1014,6 +1017,19 @@ protected function _prepareDataForAllFields($category, $replaceFields = array()) return $data; } + /** + * Retrieve attribute instance + * Special for non static flat table + * + * @param mixed $attribute + * @return Mage_Eav_Model_Entity_Attribute_Abstract + */ + public function getAttribute($attribute) + { + return Mage::getSingleton('catalog/config') + ->getAttribute('catalog_category', $attribute); + } + /** * Get count of active/not active children categories * @@ -1074,6 +1090,25 @@ public function getParentCategories($category, $isActive = true) return $categories; } + /** + * Return parent category of current category with own custom design settings + * + * @param Mage_Catalog_Model_Category $category + * @return Mage_Catalog_Model_Category + */ + public function getParentDesignCategory($category) + { + $pathIds = array_reverse($category->getPathIds()); + $select = $this->_getReadAdapter()->select() + ->from(array('main_table' => $this->getMainStoreTable($category->getStoreId())), '*') + ->where('entity_id IN (?)', $pathIds) + ->where('custom_use_parent_settings = ?', 0) + ->where('level != ?', 0) + ->order('level DESC'); + $result = $this->_getReadAdapter()->fetchRow($select); + return Mage::getModel('catalog/category')->setData($result); + } + /** * Return children categories of category * @@ -1186,7 +1221,6 @@ public function getDesignUpdateData($category) array( 'main_table.entity_id', 'main_table.custom_design', - 'main_table.custom_design_apply', 'main_table.custom_design_from', 'main_table.custom_design_to', ) diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Indexer/Product.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Indexer/Product.php index 8ce1318f08..a825137934 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Indexer/Product.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Category/Indexer/Product.php @@ -184,7 +184,7 @@ public function catalogCategorySave(Mage_Index_Model_Event $event) /** * retrieve anchor category id */ - $anchorInfo = $this->_getAnchorAttributeInfo(); + $anchorInfo = $this->_getAnchorAttributeInfo(); $select = $this->_getReadAdapter()->select() ->distinct(true) ->from(array('ce' => $this->_categoryTable), array('entity_id')) @@ -205,9 +205,12 @@ public function catalogCategorySave(Mage_Index_Model_Event $event) $this->_getWriteAdapter()->quoteInto('category_id IN(?)', $deleteCategoryIds) ); + $currCategoryAnchorIds = array_intersect($anchorIds, $categoryIds); $anchorIds = array_diff($anchorIds, $categoryIds); $this->_refreshAnchorRelations($anchorIds); - $this->_refreshDirectRelations($categoryIds); + $currCategoryAnchorIds + ? $this->_refreshAnchorRelations($currCategoryAnchorIds) + : $this->_refreshDirectRelations($categoryIds); } /** @@ -295,21 +298,18 @@ protected function _refreshAnchorRelations($categoryIds=null, $productIds=null) /** * Insert anchor categories relations */ - $isParent = new Zend_Db_Expr('0'); - $position = new Zend_Db_Expr('0'); + $isParent = new Zend_Db_Expr('IF (cp.category_id=ce.entity_id, 1, 0) AS is_parent'); + $position = new Zend_Db_Expr('IF (cp.category_id=ce.entity_id, + cp.position, + ROUND((cc.position + 1) * (cc.level + 1) * 10000) + cp.position) AS position'); $select = $this->_getReadAdapter()->select() - ->distinct(true) - ->from(array('ce' => $this->_categoryTable), array('entity_id')) - ->joinInner(array('cc' => $this->_categoryTable), 'cc.path LIKE CONCAT(ce.path, \'/%\')', array()) - ->joinInner(array('cp' => $this->_categoryProductTable), 'cp.category_id=cc.entity_id', array()) - ->joinInner( - array('pw' => $this->_productWebsiteTable), - 'pw.product_id=cp.product_id', - array('product_id', $position, $isParent) - ) - ->joinInner(array('g' => $this->_groupTable), 'g.website_id=pw.website_id', array()) - ->joinInner(array('s' => $this->_storeTable), 's.group_id=g.group_id', array('store_id')) - ->joinInner(array('rc' => $this->_categoryTable), 'rc.entity_id=g.root_category_id', array()) + ->from(array('ce' => $this->_categoryTable), array('entity_id', 'cp.product_id', $position, $isParent)) + ->joinLeft(array('cc' => $this->_categoryTable), 'cc.path LIKE CONCAT(ce.path, \'/%\')', array()) + ->joinInner(array('cp' => $this->_categoryProductTable), 'cp.category_id=cc.entity_id OR cp.category_id=ce.entity_id', array()) + ->joinInner(array('pw' => $this->_productWebsiteTable), 'pw.product_id=cp.product_id', array()) + ->joinInner(array('g' => $this->_groupTable), 'g.website_id=pw.website_id', array()) + ->joinInner(array('s' => $this->_storeTable), 's.group_id=g.group_id', array('store_id')) + ->joinInner(array('rc' => $this->_categoryTable), 'rc.entity_id=g.root_category_id', array()) ->joinLeft( array('dca'=>$anchorInfo['table']), "dca.entity_id=ce.entity_id AND dca.attribute_id={$anchorInfo['id']} AND dca.store_id=0", @@ -338,8 +338,8 @@ protected function _refreshAnchorRelations($categoryIds=null, $productIds=null) * Condition for anchor or root category (all products should be assigned to root) */ ->where('(ce.path LIKE CONCAT(rc.path, \'/%\') AND IF(sca.value_id, sca.value, dca.value)=1) OR ce.entity_id=rc.entity_id') - ->where('IF(ss.value_id, ss.value, ds.value)=?', Mage_Catalog_Model_Product_Status::STATUS_ENABLED); - + ->where('IF(ss.value_id, ss.value, ds.value)=?', Mage_Catalog_Model_Product_Status::STATUS_ENABLED) + ->group(array('ce.entity_id', 'cp.product_id', 's.store_id')); if ($categoryIds) { $select->where('ce.entity_id IN (?)', $categoryIds); } @@ -375,22 +375,24 @@ protected function _refreshRootRelations($productIds) ->joinInner(array('s' => $this->_storeTable), 's.group_id=g.group_id', array()) ->joinInner(array('rc' => $this->_categoryTable), 'rc.entity_id=g.root_category_id', array('entity_id')) - ->joinLeft(array('cp' => $this->_categoryProductTable), 'cp.product_id=pw.product_id', - array('pw.product_id', $position, $isParent, 's.store_id')) ->joinLeft( - array('dv'=>$visibilityInfo['table']), + array('cp' => $this->_categoryProductTable), 'cp.product_id=pw.product_id', + array('pw.product_id', $position, $isParent, 's.store_id') + ) + ->joinLeft( + array('dv' => $visibilityInfo['table']), "dv.entity_id=pw.product_id AND dv.attribute_id={$visibilityInfo['id']} AND dv.store_id=0", array()) ->joinLeft( - array('sv'=>$visibilityInfo['table']), + array('sv' => $visibilityInfo['table']), "sv.entity_id=pw.product_id AND sv.attribute_id={$visibilityInfo['id']} AND sv.store_id=s.store_id", array('visibility' => 'IF(sv.value_id, sv.value, dv.value)')) ->joinLeft( - array('ds'=>$statusInfo['table']), + array('ds' => $statusInfo['table']), "ds.entity_id=pw.product_id AND ds.attribute_id={$statusInfo['id']} AND ds.store_id=0", array()) ->joinLeft( - array('ss'=>$statusInfo['table']), + array('ss' => $statusInfo['table']), "ss.entity_id=pw.product_id AND ss.attribute_id={$statusInfo['id']} AND ss.store_id=s.store_id", array()) /** @@ -399,21 +401,50 @@ protected function _refreshRootRelations($productIds) ->where('cp.product_id IS NULL') ->where('IF(ss.value_id, ss.value, ds.value)=?', Mage_Catalog_Model_Product_Status::STATUS_ENABLED) ->where('pw.product_id IN(?)', $productIds); + $sql = $select->insertFromSelect($this->getMainTable()); $this->_getWriteAdapter()->query($sql); + + $select = $this->_getReadAdapter()->select() + ->from(array('pw' => $this->_productWebsiteTable), array()) + ->joinInner(array('g' => $this->_groupTable), 'g.website_id = pw.website_id', array()) + ->joinInner(array('s' => $this->_storeTable), 's.group_id = g.group_id', array()) + ->joinLeft(array('i' => $this->getMainTable()), 'i.product_id = pw.product_id AND i.category_id = g.root_category_id', array()) + ->joinLeft( + array('dv' => $visibilityInfo['table']), + "dv.entity_id = pw.product_id AND dv.attribute_id = {$visibilityInfo['id']} AND dv.store_id = 0", + array()) + ->joinLeft( + array('sv' => $visibilityInfo['table']), + "sv.entity_id = pw.product_id AND sv.attribute_id = {$visibilityInfo['id']} AND sv.store_id = s.store_id", + array()) + ->where('i.product_id IS NULL') + ->where('pw.product_id IN(?)', $productIds) + ->columns(array( + 'category_id' => 'g.root_category_id', + 'product_id' => 'pw.product_id', + 'position' => new Zend_Db_Expr('0'), + 'is_parent' => new Zend_Db_Expr('1'), + 'store_id' => 's.store_id', + 'visibility' => 'IF(sv.value_id, sv.value, dv.value)' + )); + + $sql = $select->insertFromSelect($this->getMainTable()); + $this->_getWriteAdapter()->query($sql); + return $this; } /** * Get is_anchor category attribute information * - * @return array array('id' => $id, 'table'=>$table) + * @return array array('id' => $id, 'table' => $table) */ protected function _getAnchorAttributeInfo() { $isAnchorAttribute = Mage::getSingleton('eav/config')->getAttribute('catalog_category', 'is_anchor'); $info = array( - 'id' => $isAnchorAttribute->getId() , + 'id' => $isAnchorAttribute->getId(), 'table' => $isAnchorAttribute->getBackend()->getTable() ); return $info; @@ -422,13 +453,13 @@ protected function _getAnchorAttributeInfo() /** * Get visibility product attribute information * - * @return array array('id' => $id, 'table'=>$table) + * @return array array('id' => $id, 'table' => $table) */ protected function _getVisibilityAttributeInfo() { $visibilityAttribute = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'visibility'); $info = array( - 'id' => $visibilityAttribute->getId() , + 'id' => $visibilityAttribute->getId(), 'table' => $visibilityAttribute->getBackend()->getTable() ); return $info; @@ -437,13 +468,13 @@ protected function _getVisibilityAttributeInfo() /** * Get status product attribute information * - * @return array array('id' => $id, 'table'=>$table) + * @return array array('id' => $id, 'table' => $table) */ protected function _getStatusAttributeInfo() { $statusAttribute = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'status'); $info = array( - 'id' => $statusAttribute->getId() , + 'id' => $statusAttribute->getId(), 'table' => $statusAttribute->getBackend()->getTable() ); return $info; @@ -509,23 +540,30 @@ public function reindexAll() $anchorProductsTable = $this->_getAnchorCategoriesProductsTemporaryTable(); $idxAdapter->delete($anchorProductsTable); + $position = new Zend_Db_Expr('IF (ca.category_id=ce.entity_id, + cp.position, + ROUND((ce.position + 1) * (ce.level + 1) * 10000) + cp.position) + AS position'); + $sql = "SELECT STRAIGHT_JOIN DISTINCT - ca.category_id, cp.product_id + ca.category_id, cp.product_id, $position FROM {$anchorTable} AS ca INNER JOIN {$this->_categoryTable} AS ce ON ce.path LIKE ca.path OR ce.entity_id = ca.category_id INNER JOIN {$this->_categoryProductTable} AS cp ON cp.category_id = ce.entity_id INNER JOIN {$enabledTable} as pv - ON pv.product_id = cp.product_id"; - $this->insertFromSelect($sql, $anchorProductsTable, array('category_id' , 'product_id')); + ON pv.product_id = cp.product_id + GROUP BY ca.category_id, cp.product_id"; + $this->insertFromSelect($sql, $anchorProductsTable, array('category_id', 'product_id', 'position')); + /** * Add anchor categories products to index */ $sql = "INSERT INTO {$idxTable} SELECT - ap.category_id, ap.product_id, cp.position, + ap.category_id, ap.product_id, ap.position, IF(cp.product_id, 1, 0), {$storeId}, pv.visibility FROM {$anchorProductsTable} AS ap @@ -534,6 +572,28 @@ public function reindexAll() INNER JOIN {$enabledTable} as pv ON pv.product_id = ap.product_id"; $idxAdapter->query($sql); + + $select = $idxAdapter->select() + ->from(array('e' => $this->getTable('catalog/product')), null) + ->join( + array('ei' => $enabledTable), + 'ei.product_id = e.entity_id', + array()) + ->joinLeft( + array('i' => $idxTable), + 'i.product_id = e.entity_id AND i.category_id = :category_id AND i.store_id = :store_id', + array()) + ->where('i.product_id IS NULL') + ->columns(array( + 'category_id' => new Zend_Db_Expr($rootId), + 'product_id' => 'e.entity_id', + 'position' => new Zend_Db_Expr('0'), + 'is_parent' => new Zend_Db_Expr('1'), + 'store_id' => new Zend_Db_Expr($storeId), + 'visibility' => 'ei.visibility' + )); + $query = $select->insertFromSelect($idxTable); + $idxAdapter->query($query, array('store_id' => $storeId, 'category_id' => $rootId)); } $this->syncData(); @@ -639,7 +699,7 @@ protected function _prepareAnchorCategories($storeId, $rootPath) $sql = "SELECT ce.entity_id AS category_id, - concat(ce.path, '/%') AS path + CONCAT(ce.path, '/%') AS path FROM {$this->_categoryTable} as ce LEFT JOIN {$anchorTable} AS cad @@ -649,7 +709,7 @@ protected function _prepareAnchorCategories($storeId, $rootPath) WHERE (IF(cas.value_id>0, cas.value, cad.value) = 1 AND ce.path LIKE '{$rootPath}/%') OR ce.path='{$rootPath}'"; - $this->insertFromSelect($sql, $tmpTable, array('category_id' , 'path')); + $this->insertFromSelect($sql, $tmpTable, array('category_id', 'path')); return $tmpTable; } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Layer/Filter/Price.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Layer/Filter/Price.php index c0178d6e2c..8c4ca287a3 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Layer/Filter/Price.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Layer/Filter/Price.php @@ -125,8 +125,8 @@ public function getMaxPrice($filter) $table = $this->_getIndexTableAlias(); - $additional = join('', $response->getAdditionalCalculations()); - $maxPriceExpr = new Zend_Db_Expr("MAX({$table}.min_price {$additional})"); + $additional = join('', $response->getAdditionalCalculations()); + $maxPriceExpr = new Zend_Db_Expr("MAX({$table}.min_price {$additional})"); $select->columns(array($maxPriceExpr)); @@ -145,12 +145,11 @@ public function getCount($filter, $range) $select = $this->_getSelect($filter); $connection = $this->_getReadAdapter(); $response = $this->_dispatchPreparePriceEvent($filter, $select); - - $table = $this->_getIndexTableAlias(); + $table = $this->_getIndexTableAlias(); $additional = join('', $response->getAdditionalCalculations()); $rate = $filter->getCurrencyRate(); - $countExpr = new Zend_Db_Expr("COUNT(*)"); + $countExpr = new Zend_Db_Expr('COUNT(*)'); $rangeExpr = new Zend_Db_Expr("FLOOR((({$table}.min_price {$additional}) * {$rate}) / {$range}) + 1"); $select->columns(array( @@ -175,6 +174,7 @@ public function applyFilterToCollection($filter, $range, $index) { $collection = $filter->getLayer()->getProductCollection(); $collection->addPriceData($filter->getCustomerGroupId(), $filter->getWebsiteId()); + $select = $collection->getSelect(); $response = $this->_dispatchPreparePriceEvent($filter, $select); diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product.php index 5c7f3aa496..d79c79851c 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product.php @@ -489,6 +489,7 @@ public function canBeShowInCategory($product, $categoryId) */ public function duplicate($oldId, $newId) { + $adapter = $this->_getWriteAdapter(); $eavTables = array('datetime', 'decimal', 'int', 'text', 'varchar'); // duplicate EAV store values @@ -497,33 +498,36 @@ public function duplicate($oldId, $newId) $sql = 'REPLACE INTO `' . $tableName . '` ' . 'SELECT NULL, `entity_type_id`, `attribute_id`, `store_id`, ' . $newId . ', `value`' . 'FROM `' . $tableName . '` WHERE `entity_id`=' . $oldId . ' AND `store_id`>0'; - $this->_getWriteAdapter()->query($sql); + $adapter->query($sql); } + // set status as disabled + $statusAttribute = $this->getAttribute('status'); + $statusAttributeId = $statusAttribute->getAttributeId(); + $statusAttributeTable = $statusAttribute->getBackend()->getTable(); + $updateCond[] = 'store_id > 0'; + $updateCond[] = $adapter->quoteInto('entity_id = ?', $newId); + $updateCond[] = $adapter->quoteInto('attribute_id = ?', $statusAttributeId); + $adapter->update( + $statusAttributeTable, + array('value' => Mage_Catalog_Model_Product_Status::STATUS_DISABLED), + $updateCond + ); + return $this; } - public function getParentProductIds($object) + /** + * Get SKU through product identifiers + * + * @param array $productIds + * @return array + */ + public function getProductsSku(array $productIds) { - $childId = $object->getId(); - - $groupedProductsTable = $this->getTable('catalog/product_link'); - $groupedLinkTypeId = Mage_Catalog_Model_Product_Link::LINK_TYPE_GROUPED; - - $configurableProductsTable = $this->getTable('catalog/product_super_link'); - - $groupedSelect = $this->_getReadAdapter()->select() - ->from(array('g'=>$groupedProductsTable), 'g.product_id') - ->where("g.linked_product_id = ?", $childId) - ->where("link_type_id = ?", $groupedLinkTypeId); - - $groupedIds = $this->_getReadAdapter()->fetchCol($groupedSelect); - - $configurableSelect = $this->_getReadAdapter()->select() - ->from(array('c'=>$configurableProductsTable), 'c.parent_id') - ->where("c.product_id = ?", $childId); - - $configurableIds = $this->_getReadAdapter()->fetchCol($configurableSelect); - return array_merge($groupedIds, $configurableIds); + $select = $this->_getReadAdapter()->select() + ->from($this->getTable('catalog/product'), array('entity_id', 'sku')) + ->where('entity_id IN (?)', $productIds); + return $this->_getReadAdapter()->fetchAll($select); } } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Attribute/Collection.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Attribute/Collection.php index 72bf54a60a..9dc57d713c 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Attribute/Collection.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Attribute/Collection.php @@ -70,11 +70,29 @@ public function setEntityTypeFilter($typeId) */ protected function _getLoadDataFields() { - $fields = parent::_getLoadDataFields(); - $fields = array_merge($fields, array('additional_table.is_global')); + $fields = array_merge( + parent::_getLoadDataFields(), + array( + 'additional_table.is_global', + 'additional_table.is_html_allowed_on_front', + 'additional_table.is_wysiwyg_enabled' + ) + ); + return $fields; } + /** + * Remove price from attribute list + * + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Collection + */ + public function removePriceFilter() + { + $this->getSelect()->where('main_table.attribute_code <> ?', 'price'); + return $this; + } + /** * Specify "is_visible_in_advanced_search" filter * @@ -115,7 +133,7 @@ public function addIsFilterableInSearchFilter() */ public function addVisibleFilter() { - $this->getSelect()->where('additional_table.is_visible=?', 1); + $this->getSelect()->where('additional_table.is_visible = ?', 1); return $this; } @@ -126,7 +144,45 @@ public function addVisibleFilter() */ public function addIsSearchableFilter() { - $this->getSelect()->where('additional_table.is_searchable=1'); + $this->getSelect()->where('additional_table.is_searchable = ?', 1); + return $this; + } + + /** + * Specify filter for attributes that have to be indexed using advanced index + * + * @param bool $addRequiredCodes + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Collection + */ + public function addToIndexFilter($addRequiredCodes = false) + { + $requiredCodesCondition = ($addRequiredCodes) + ? $this->getConnection()->quoteInto(' OR main_table.attribute_code IN (?)', array('status', 'visibility')) + : ''; + + $this->getSelect()->where('( + additional_table.is_searchable = 1 OR + additional_table.is_visible_in_advanced_search = 1 OR + additional_table.is_filterable > 0 OR + additional_table.is_filterable_in_search = 1'. + $requiredCodesCondition . + ')'); + + return $this; + } + + /** + * Specify filter for attributes used in quick search + * + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Collection + */ + public function addSearchableAttributeFilter() + { + $this->getSelect()->where( + 'additional_table.is_searchable = 1 OR '. + $this->getConnection()->quoteInto('main_table.attribute_code IN (?)', array('status', 'visibility')) + ); + return $this; } } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php index c0ea8b08b9..9966ba907a 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php @@ -127,6 +127,27 @@ class Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */ protected $_isWebsiteFilter = false; + /** + * Additional field filters, applied in _productLimitationJoinPrice() + * + * @var array + */ + protected $_priceDataFieldFilters = array(); + + /** + * Map of price fields + * + * @var array + */ + protected $_map = array('fields' => array( + 'price' => 'price_index.price', + 'final_price' => 'price_index.final_price', + 'min_price' => 'price_index.min_price', + 'max_price' => 'price_index.max_price', + 'tier_price' => 'price_index.tier_price', + 'special_price' => 'price_index.special_price', + )); + /** * Retrieve Catalog Product Flat Helper object * @@ -167,7 +188,14 @@ protected function _construct() else { $this->_init('catalog/product'); } + $this->_initTables(); + } + /** + * Define product website and category product tables + */ + protected function _initTables() + { $this->_productWebsiteTable = $this->getResource()->getTable('catalog/product_website'); $this->_productCategoryTable= $this->getResource()->getTable('catalog/category_product'); } @@ -857,6 +885,21 @@ public function getSetIds() return $this->getConnection()->fetchCol($select); } + /** + * Return array of unique product type ids in collection + * + * @return array + */ + public function getProductTypeIds() + { + $select = clone $this->getSelect(); + /* @var $select Zend_Db_Select */ + $select->reset(Zend_Db_Select::COLUMNS); + $select->distinct(true); + $select->columns('type_id'); + return $this->getConnection()->fetchCol($select); + } + /** * Joins url rewrite rules to collection * @@ -875,7 +918,13 @@ public function joinUrlRewrite() return $this; } - + /** + * Add URL rewrites data to product + * If collection loadded - run processing else set flag + * + * @param int $categoryId + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection + */ public function addUrlRewrite($categoryId = '') { $this->_addUrlRewrite = true; @@ -884,9 +933,18 @@ public function addUrlRewrite($categoryId = '') } else { $this->_urlRewriteCategory = 0; } + + if ($this->isLoaded()) { + $this->_addUrlRewrite(); + } + return $this; } + /** + * Add URL rewrites to collection + * + */ protected function _addUrlRewrite() { $urlRewrites = null; @@ -935,6 +993,8 @@ protected function _addUrlRewrite() foreach($this->getItems() as $item) { if (isset($urlRewrites[$item->getEntityId()])) { $item->setData('request_path', $urlRewrites[$item->getEntityId()]); + } else { + $item->setData('request_path', false); } } } @@ -985,7 +1045,7 @@ protected function _joinPriceRules() return $this; } - $wId = Mage::app()->getWebsite()->getId(); + $wId = Mage::app()->getStore($this->getStoreId())->getWebsite()->getId(); $gId = Mage::getSingleton('customer/session')->getCustomerGroupId(); $storeDate = Mage::app()->getLocale()->storeTimeStamp($this->getStoreId()); @@ -1106,7 +1166,7 @@ public function addAttributeToFilter($attribute, $condition=null, $joinType='inn $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType); } $conditionSql = '('.join(') OR (', $sqlArr).')'; - $this->getSelect()->where($conditionSql); + $this->getSelect()->where($conditionSql, null, Varien_Db_Select::TYPE_CONDITION); return $this; } @@ -1122,28 +1182,29 @@ public function addAttributeToFilter($attribute, $condition=null, $joinType='inn } $this->_allIdsCache = null; + if (is_string($attribute) && $attribute == 'is_saleable') { - $isStockManagedInConfig = (int) Mage::getStoreConfig(Mage_CatalogInventory_Model_Stock_Item::XML_PATH_MANAGE_STOCK); - $inventoryTable = $this->getTable('cataloginventory_stock_item'); - $this->getSelect()->where( - $this->_getConditionSql( - "( - IF( - IF( - $inventoryTable.use_config_manage_stock, - $isStockManagedInConfig, - $inventoryTable.manage_stock - ), - $inventoryTable.is_in_stock, - 1 - ) - )", - $condition - ) - ); + $columns = $this->getSelect()->getPart(Zend_Db_Select::COLUMNS); + foreach ($columns as $columnEntry) { + list($correlationName, $column, $alias) = $columnEntry; + if ($alias == 'is_saleable') { + if ($column instanceof Zend_Db_Expr) { + $field = $column; + } else { + $adapter = $this->getSelect()->getAdapter(); + if (empty($correlationName)) { + $field = $adapter->quoteColumnAs($column, $alias, true); + } else { + $field = $adapter->quoteColumnAs(array($correlationName, $column), $alias, true); + } + } + $this->getSelect()->where("{$field} = ?", $condition); + break; + } + } + return $this; - } - else { + } else { return parent::addAttributeToFilter($attribute, $condition, $joinType); } } @@ -1266,6 +1327,9 @@ public function addAttributeToSort($attribute, $dir='asc') $this->getSelect()->order('e.entity_id ' . $dir); } + return $this; + } else if($attribute == 'is_saleable'){ + $this->getSelect()->order("is_saleable " . $dir); return $this; } @@ -1277,11 +1341,6 @@ public function addAttributeToSort($attribute, $dir='asc') return $this; } - if($attribute == 'is_saleable'){ - $this->getSelect()->order("is_saleable " . $dir); - return $this; - } - if ($this->isEnabledFlat()) { $column = $this->getEntity()->getAttributeSortColumn($attribute); @@ -1484,6 +1543,11 @@ protected function _productLimitationJoinPrice() $joinCond, array('price', 'tax_class_id', 'final_price', 'minimal_price'=>$minimalExpr , 'min_price', 'max_price', 'tier_price') ); + + // Set additional field filters + foreach ($this->_priceDataFieldFilters as $filterData) { + $this->getSelect()->where(call_user_func_array('sprintf', $filterData)); + } } else { $fromPart['price_index']['joinCondition'] = $joinCond; $this->getSelect()->setPart(Zend_Db_Select::FROM, $fromPart); @@ -1603,4 +1667,158 @@ protected function _applyZeroStoreProductLimitations() return $this; } + + /** + * Stub method + * + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection + */ + public function setGeneralDefoultQuery() + { + return $this; + } + + /** + * Add category ids to loaded items + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection + */ + public function addCategoryIds() + { + if ($this->getFlag('category_ids_added')) { + return $this; + } + $ids = array_keys($this->_items); + if (empty($ids)) { + return $this; + } + + $select = $this->getConnection()->select(); + + $select->from($this->_productCategoryTable, array('product_id', 'category_id')); + $select->where('product_id IN (?)', $ids); + + $data = $this->getConnection()->fetchAll($select); + + $categoryIds = array(); + foreach ($data as $info) { + if (isset($categoryIds[$info['product_id']])) { + $categoryIds[$info['product_id']][] = $info['category_id']; + } else { + $categoryIds[$info['product_id']] = array($info['category_id']); + } + } + + + foreach ($this->getItems() as $item) { + $productId = $item->getId(); + if (isset($categoryIds[$productId])) { + $item->setCategoryIds($categoryIds[$productId]); + } else { + $item->setCategoryIds(array()); + } + } + + $this->setFlag('category_ids_added', true); + return $this; + } + + /** + * Add tier price data to loaded items + * + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection + */ + public function addTierPriceData() + { + if ($this->getFlag('tier_price_added')) { + return $this; + } + + $tierPrices = array(); + $productIds = array(); + foreach ($this->getItems() as $item) { + $productIds[] = $item->getId(); + $tierPrices[$item->getId()] = array(); + } + if (!$productIds) { + return $this; + } + + /* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ + $attribute = $this->getAttribute('tier_price'); + if ($attribute->isScopeGlobal()) { + $websiteId = 0; + } else if ($this->getStoreId()) { + $websiteId = Mage::app()->getStore($this->getStoreId())->getWebsiteId(); + } + + $adapter = $this->getConnection(); + $columns = array( + 'price_id' => 'value_id', + 'website_id' => 'website_id', + 'all_groups' => 'all_groups', + 'cust_group' => 'customer_group_id', + 'price_qty' => 'qty', + 'price' => 'value', + 'product_id' => 'entity_id' + ); + $select = $adapter->select() + ->from($this->getTable('catalog/product_attribute_tier_price'), $columns) + ->where('entity_id IN(?)', $productIds) + ->order(array('entity_id','qty')); + + if ($websiteId == '0') { + $select->where('website_id=?', $websiteId); + } else { + $select->where('website_id IN(?)', array('0', $websiteId)); + } + + foreach ($adapter->fetchAll($select) as $row) { + $tierPrices[$row['product_id']][] = array( + 'website_id' => $row['website_id'], + 'cust_group' => $row['all_groups'] ? Mage_Customer_Model_Group::CUST_GROUP_ALL : $row['cust_group'], + 'price_qty' => $row['price_qty'], + 'price' => $row['price'], + 'website_price' => $row['price'], + + ); + } + + /* @var $backend Mage_Catalog_Model_Product_Attribute_Backend_Tierprice */ + $backend = $attribute->getBackend(); + + foreach ($this->getItems() as $item) { + $data = $tierPrices[$item->getId()]; + if (!empty($data) && $websiteId) { + $data = $backend->preparePriceData($data, $item->getTypeId(), $websiteId); + } + $item->setData('tier_price', $data); + } + + $this->setFlag('tier_price_added', true); + return $this; + } + + /** + * Add field comparison expression + * + * @param string $comparisonFormat - expression for sprintf() + * @param array $fields - list of fields + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection + */ + public function addPriceDataFieldFilter($comparisonFormat, $fields) + { + if (!preg_match('/^%s( (<|>|=|<=|>=|<>) %s)*$/', $comparisonFormat)) { + throw new Exception('Invalid comparison format.'); + } + + if (!is_array($fields)) { + $fields = array($fields); + } + foreach ($fields as $key => $field) { + $fields[$key] = $this->_getMappedField($field); + } + + $this->_priceDataFieldFilters[] = array_merge(array($comparisonFormat), $fields); + return $this; + } } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Compare/Item.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Compare/Item.php index bfd2f55864..b8b59df3b8 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Compare/Item.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Compare/Item.php @@ -225,20 +225,20 @@ public function updateCustomerFromVisitor($object) /** * Clear compare items by visitor and/or customer * - * @param int $visitor_id - * @param int $customer_id + * @param int $visitorId + * @param int $customerId * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Compare_Item */ - public function clearItems($visitor_id = null, $customer_id = null) + public function clearItems($visitorId = null, $customerId = null) { $where = array(); - if ($customer_id) { - $customer_id = (int)$customer_id; - $where[] = $this->_getWriteAdapter()->quoteInto('customer_id=?', $customer_id); + if ($customerId) { + $customerId = (int)$customerId; + $where[] = $this->_getWriteAdapter()->quoteInto('customer_id=?', $customerId); } - if ($visitor_id) { - $visitor_id = (int)$visitor_id; - $where[] = $this->_getWriteAdapter()->quoteInto('visitor_id=?', $visitor_id); + if ($visitorId) { + $visitorId = (int)$visitorId; + $where[] = $this->_getWriteAdapter()->quoteInto('visitor_id=?', $visitorId); } if (!$where) { return $this; @@ -246,5 +246,4 @@ public function clearItems($visitor_id = null, $customer_id = null) $this->_getWriteAdapter()->delete($this->getMainTable(), $where); return $this; } - } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat.php index 5e97fa0cba..527d0a7d8a 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat.php @@ -70,7 +70,11 @@ public function getStoreId() */ public function setStoreId($store) { - $this->_storeId = Mage::app()->getStore($store)->getId(); + if (is_int($store)) { + $this->_storeId = $store; + } else { + $this->_storeId = Mage::app()->getStore($store)->getId(); + } return $this; } diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat/Indexer.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat/Indexer.php index 5b75e6fde1..c5382dd321 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat/Indexer.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Flat/Indexer.php @@ -454,12 +454,23 @@ protected function _compareColumnProperties($column, $describe) protected function _sqlColunmDefinition($fieldName, $fieldProp) { $fieldNameQuote = $this->_getWriteAdapter()->quoteIdentifier($fieldName); + + /** + * Process the case when 'is_null' prohibits null value, and 'default' proposed to be null + * It just means that default value not specified + */ + if (false === $fieldProp['is_null'] && null === $fieldProp['default']) { + $defaultValue = ''; + } else { + $defaultValue = $fieldProp['default'] === null ? ' DEFAULT NULL' : $this->_getReadAdapter() + ->quoteInto(' DEFAULT ?', $fieldProp['default']); + } + return "{$fieldNameQuote} {$fieldProp['type']}" . ($fieldProp['unsigned'] ? ' UNSIGNED' : '') . ($fieldProp['extra'] ? ' ' . $fieldProp['extra'] : '') . ($fieldProp['is_null'] === false ? ' NOT NULL' : '') - . ($fieldProp['default'] === null ? ' DEFAULT NULL' : $this->_getReadAdapter() - ->quoteInto(' DEFAULT ?', $fieldProp['default'])); + . $defaultValue; } /** diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Option/Collection.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Option/Collection.php index 8980317be7..941be572f7 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Option/Collection.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Option/Collection.php @@ -136,6 +136,18 @@ public function addProductToFilter($product) return $this; } + /** + * Add filtering by option ids + * + * @param mixed $optionIds + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Option_Collection + */ + public function addIdsToFilter($optionIds) + { + $this->addFieldToFilter('main_table.option_id', $optionIds); + return $this; + } + /** * Call of protected method reset * diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Setup.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Setup.php index 799138c570..95df3cb905 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Setup.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Setup.php @@ -57,13 +57,13 @@ protected function _prepareValues($attr) 'is_html_allowed_on_front' => $this->_getValue($attr, 'is_html_allowed_on_front', 0), 'is_visible_in_advanced_search' => $this->_getValue($attr, 'visible_in_advanced_search', 0), - 'is_used_for_price_rules' => $this->_getValue($attr, 'used_for_price_rules', 1), 'is_filterable_in_search' => $this->_getValue($attr, 'filterable_in_search', 0), 'used_in_product_listing' => $this->_getValue($attr, 'used_in_product_listing', 0), 'used_for_sort_by' => $this->_getValue($attr, 'used_for_sort_by', 0), 'apply_to' => $this->_getValue($attr, 'apply_to', ''), 'position' => $this->_getValue($attr, 'position', 0), - 'is_configurable' => $this->_getValue($attr, 'is_configurable', 1) + 'is_configurable' => $this->_getValue($attr, 'is_configurable', 1), + 'is_used_for_promo_rules' => $this->_getValue($attr, 'used_for_promo_rules', 0) )); return $data; } @@ -1347,26 +1347,6 @@ public function getDefaultEntities() 'unique' => false, 'group' => 'Design' ), - 'category_ids' => array( - 'type' => 'static', - 'backend' => '', - 'label' => '', - 'frontend' => '', - 'table' => '', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, - 'visible' => false, - 'required' => false, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'unique' => false, - ), 'options_container' => array( 'group' => 'Design', 'type' => 'varchar', diff --git a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Url.php b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Url.php index c2cc7f4ad6..3752dc3105 100644 --- a/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Url.php +++ b/app/code/core/Mage/Catalog/Model/Resource/Eav/Mysql4/Url.php @@ -61,6 +61,13 @@ class Mage_Catalog_Model_Resource_Eav_Mysql4_Url extends Mage_Core_Model_Mysql4_ */ protected $_productLimit = 250; + /** + * Cache of root category children ids + * + * @var array + */ + protected $_rootChildrenIds = array(); + /** * Load core Url rewrite model * @@ -194,8 +201,24 @@ public function prepareRewrites($storeId, $categoryIds = null, $productIds = nul $select->where('category_id IS NULL'); } elseif ($categoryIds) { - $select->where('category_id IN(?)', $categoryIds); + $catIds = is_array($categoryIds) ? $categoryIds : array($categoryIds); + + // Check maybe we request products and root category id is within categoryIds, + // it's a separate case because root category products are stored with NULL categoryId + if ($productIds) { + $addNullCategory = in_array($this->getStores($storeId)->getRootCategoryId(), $catIds); + } else { + $addNullCategory = false; + } + + // Compose optimal condition + if ($addNullCategory) { + $select->where('category_id IN(?) OR category_id IS NULL', $catIds); + } else { + $select->where('category_id IN(?)', $catIds); + } } + if (is_null($productIds)) { $select->where('product_id IS NULL'); } @@ -250,13 +273,14 @@ public function saveRewrite($rewriteData, $rewrite) $this->_getWriteAdapter()->insert($this->getMainTable(), $rewriteData); } catch (Exception $e) { + Mage::logException($e); Mage::throwException(Mage::helper('catalog')->__('An error occurred while saving the URL rewrite.')); } } unset($rewriteData); return $this; } - + public function saveRewriteHistory($rewriteData) { $rewriteData = new Varien_Object($rewriteData); @@ -594,6 +618,7 @@ protected function _prepareStoreRootCategories($stores) /** * Retrieve categories objects + * Either $categoryIds or $path (with ending slash) must be specified * * @param int|array $categoryIds * @param int $storeId @@ -602,7 +627,6 @@ protected function _prepareStoreRootCategories($stores) */ protected function _getCategories($categoryIds, $storeId = null, $path = null) { - //$isActiveAttribute = Mage::getModel('eav/entity_attribute')->loadByCode('catalog_category', 'is_active'); $isActiveAttribute = Mage::getSingleton('eav/config')->getAttribute('catalog_category', 'is_active'); $categories = array(); @@ -611,19 +635,31 @@ protected function _getCategories($categoryIds, $storeId = null, $path = null) } $select = $this->_getWriteAdapter()->select() - ->from(array('main_table'=>$this->getTable('catalog/category')), array('main_table.entity_id', 'main_table.parent_id', 'is_active'=>'IF(c.value_id>0, c.value, d.value)', 'main_table.path')); + ->from(array('main_table' => $this->getTable('catalog/category')), array( + 'main_table.entity_id', + 'main_table.parent_id', + 'main_table.level', + 'is_active' => 'IF(c.value_id>0, c.value, d.value)', + 'main_table.path')); if (is_null($path)) { $select->where('main_table.entity_id IN(?)', $categoryIds); - } - else { - $select->where('main_table.path LIKE ?', $path . '%') + } else { + // Ensure that path ends with '/', otherwise we can get wrong results - e.g. $path = '1/2' will get '1/20' + if (substr($path, -1) != '/') { + $path .= '/'; + } + + $select + ->where('main_table.path LIKE ?', $path . '%') ->order('main_table.path'); } + $table = $this->getTable('catalog/category') . '_int'; $select->joinLeft(array('d'=>$table), "d.attribute_id = '{$isActiveAttribute->getId()}' AND d.store_id = 0 AND d.entity_id = main_table.entity_id", array()) ->joinLeft(array('c'=>$table), "c.attribute_id = '{$isActiveAttribute->getId()}' AND c.store_id = '{$storeId}' AND c.entity_id = main_table.entity_id", array()); + // Prepare variables for checking whether categories belong to store if (!is_null($storeId)) { $rootCategoryPath = $this->getStores($storeId)->getRootCategoryPath(); $rootCategoryPathLength = strlen($rootCategoryPath); @@ -631,8 +667,16 @@ protected function _getCategories($categoryIds, $storeId = null, $path = null) $rowSet = $this->_getWriteAdapter()->fetchAll($select); foreach ($rowSet as $row) { - if (!is_null($storeId) && (strlen($row['path']) > $rootCategoryPathLength) && substr($row['path'], $rootCategoryPathLength, 1) != '/') { - continue; + if (!is_null($storeId)) { + // Check the category to be either store's root or its descendant + // First - check that category's start is the same as root category + if (substr($row['path'], 0, $rootCategoryPathLength) != $rootCategoryPath) { + continue; + } + // Second - check non-root category - that it's really a descendant, not a simple string match + if ((strlen($row['path']) > $rootCategoryPathLength) && ($row['path'][$rootCategoryPathLength] != '/')) { + continue; + } } $category = new Varien_Object($row); @@ -677,7 +721,7 @@ public function getCategory($categoryId, $storeId) } /** - * Retrieve categories data objects by ids + * Retrieve categories data objects by their ids. Return only categories that belong to specified store. * * @param int|array $categoryIds * @param int $storeId @@ -727,6 +771,38 @@ public function loadCategoryChilds(Varien_Object $category) return $category; } + /** + * Retrieves all children ids of root category tree + * Actually this routine can be used to get children ids of any category, not only root. + * But as far as result is cached in memory, it's not recommended to do so. + * + * @param Varien_Object $category + * @return Varien_Object + */ + public function getRootChildrenIds($categoryId, $categoryPath, $includeStart = true) + { + if (!isset($this->_rootChildrenIds[$categoryId])) { + // Select all descedant category ids + $adapter = $this->_getReadAdapter(); + $select = $adapter->select() + ->from(array($this->getTable('catalog/category')), array('entity_id')) + ->where('path LIKE ?', $categoryPath . '/%'); + + $categoryIds = array(); + $rowSet = $adapter->fetchAll($select); + foreach ($rowSet as $row) { + $categoryIds[$row['entity_id']] = $row['entity_id']; + } + $this->_rootChildrenIds[$categoryId] = $categoryIds; + } + + $categoryIds = $this->_rootChildrenIds[$categoryId]; + if ($includeStart) { + $categoryIds[$categoryId] = $categoryId; + } + return $categoryIds; + } + /** * Retrieve category parent path * @@ -891,7 +967,8 @@ public function getProductsByCategory(Varien_Object $category, &$lastEntityId) } /** - * Remove unused rewrite URLs + * Find and remove unused products rewrites - a case when products were moved away from the category + * (either to other category or deleted), so rewrite "category_id-product_id" is invalid * * @param int $storeId * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url @@ -920,9 +997,13 @@ public function clearCategoryProduct($storeId) return $this; } - + /** - * Remove unused rewrites for product + * Remove unused rewrites for product - called after we created all needed rewrites for product and know the categories + * where the product is contained ($excludeCategoryIds), so we can remove all invalid product rewrites that have other category ids + * + * Notice: this routine is not identical to clearCategoryProduct(), because after checking all categories this one removes rewrites + * for product still contained within categories. * * @param int $productId Product entity Id * @param int $storeId Store Id for rewrites @@ -932,14 +1013,104 @@ public function clearCategoryProduct($storeId) public function clearProductRewrites($productId, $storeId, $excludeCategoryIds = array()) { $adapter = $this->_getWriteAdapter(); + $where = $adapter->quoteInto('product_id=?', $productId); $where.= $adapter->quoteInto(' AND store_id=?', $storeId); - $where.= ' AND category_id IS NOT NULL'; + if (!empty($excludeCategoryIds)) { $where.= $adapter->quoteInto(' AND category_id NOT IN (?)', $excludeCategoryIds); + $where.= ' AND category_id IS NOT NULL'; // If there's at least one category to skip, also skip root category, because product belongs to website } + $adapter->delete($this->getMainTable(), $where); - + + return $this; + } + + /** + * Finds and deletes all old category and category/product rewrites for store + * left from the times when categories/products belonged to store + * + * @param int $storeId + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url + */ + public function clearStoreCategoriesInvalidRewrites($storeId) + { + // Form a list of all current store categories ids + $store = $this->getStores($storeId); + $rootCategoryId = $store->getRootCategoryId(); + if (!$rootCategoryId) { + return $this; + } + $categoryIds = $this->getRootChildrenIds($rootCategoryId, $store->getRootCategoryPath()); + + // Remove all store catalog rewrites that are for some category or cartegory/product not within store categories + $adapter = $this->_getWriteAdapter(); + $condition = $adapter->quoteInto('store_id = ?', $storeId); + $condition .= ' AND category_id IS NOT NULL'; // For sure check that it's a catalog rewrite + $condition .= $adapter->quoteInto(' AND category_id NOT IN (?)', $categoryIds); + $adapter->delete($this->getMainTable(), $condition); + + return $this; + } + + /** + * Finds and deletes product rewrites (that are not assigned to any category) for store + * left from the times when product was assigned to this store's website and now is not assigned + * + * Notice: this routine is different from clearProductRewrites() and clearCategoryProduct() because + * it handles direct rewrites to product without defined category (category_id IS NULL) whilst that routines + * handle only product rewrites within categories + * + * @param int $storeId + * @param int|array|null $productId + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url + */ + public function clearStoreProductsInvalidRewrites($storeId, $productId = null) + { + $store = $this->getStores($storeId); + $read = $this->_getReadAdapter(); + $select = $read->select() + ->from(array('rewrite' => $this->getMainTable()), $this->getIdFieldName()) + ->joinLeft( + array('website' => $this->getTable('catalog/product_website')), + 'rewrite.product_id=website.product_id AND ' . $read->quoteInto('website.website_id = ?', $store->getWebsiteId()), + array() + )->where('rewrite.store_id=?', $storeId) + ->where('rewrite.category_id IS NULL'); + if ($productId) { + $select->where('rewrite.product_id IN (?)', $productId); + } else { + $select->where('rewrite.product_id IS NOT NULL'); + } + $select->where('website.website_id IS NULL'); + + $rowSet = $read->fetchAll($select); + $rewriteIds = array(); + foreach ($rowSet as $row) { + $rewriteIds[] = $row[$this->getIdFieldName()]; + } + if ($rewriteIds) { + $write =$this->_getWriteAdapter(); + $where = $write->quoteInto($this->getIdFieldName() . ' IN(?)', $rewriteIds); + $this->_getWriteAdapter()->delete($this->getMainTable(), $where); + } + + return $this; + } + + /** + * Finds and deletes old rewrites for store + * a) category rewrites left from the times when store had some other root category + * b) product rewrites left from products that once belonged to this site, but then deleted or just removed from website + * + * @param int $storeId + * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url + */ + public function clearStoreInvalidRewrites($storeId) + { + $this->clearStoreCategoriesInvalidRewrites($storeId); + $this->clearStoreProductsInvalidRewrites($storeId); return $this; } @@ -957,7 +1128,7 @@ public function deleteCategoryProductRewrites($categoryId, $productIds) } /** - * Delete URL rewrites for category products of specific store \ + * Delete URL rewrites for category products of specific store * * @param int $categoryId * @param array|int|null $productIds @@ -967,18 +1138,23 @@ public function deleteCategoryProductRewrites($categoryId, $productIds) public function deleteCategoryProductStoreRewrites($categoryId, $productIds=null, $storeId=null) { $adapter = $this->_getWriteAdapter(); + + // Notice that we don't include category_id = NULL in case of root category, + // because product removed from all categories but assigned to store's website is still + // assumed to be in root cat. Unassigned products must be removed by other routine. $condition = $adapter->quoteInto('category_id=?', $categoryId); if (empty($productIds)) { $condition.= ' AND product_id IS NOT NULL'; } else { $condition.= $adapter->quoteInto(' AND product_id IN (?)', $productIds); } + if ($storeId !== null) { $condition.= $adapter->quoteInto(' AND store_id IN(?)', $storeId); } - $this->_getWriteAdapter()->delete($this->getMainTable(), $condition); - return $this; + $adapter->delete($this->getMainTable(), $condition); + return $this; } /** diff --git a/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Category/Flat.php b/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Category/Flat.php new file mode 100644 index 0000000000..9f4b91ecd7 --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Category/Flat.php @@ -0,0 +1,46 @@ +isValueChanged() && $this->getValue()) { + Mage::getSingleton('index/indexer')->getProcessByCode('catalog_category_flat') + ->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX); + } + + return $this; + } +} diff --git a/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Product/Flat.php b/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Product/Flat.php new file mode 100644 index 0000000000..7ce9843acb --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Product/Flat.php @@ -0,0 +1,46 @@ +isValueChanged() && $this->getValue()) { + Mage::getSingleton('index/indexer')->getProcessByCode('catalog_product_flat') + ->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX); + } + + return $this; + } +} diff --git a/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php b/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php new file mode 100644 index 0000000000..51b40dd77e --- /dev/null +++ b/app/code/core/Mage/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/Suffix.php @@ -0,0 +1,42 @@ +validateSuffix($this->getValue()); + return $this; + } +} diff --git a/app/code/core/Mage/Catalog/Model/Url.php b/app/code/core/Mage/Catalog/Model/Url.php index b4e05eafb0..aa5f4db6c3 100644 --- a/app/code/core/Mage/Catalog/Model/Url.php +++ b/app/code/core/Mage/Catalog/Model/Url.php @@ -62,6 +62,13 @@ class Mage_Catalog_Model_Url */ protected $_categories = array(); + /** + * Store root categories cache + * + * @var array + */ + protected $_rootCategories = array(); + /** * Rewrite cache * @@ -96,7 +103,46 @@ class Mage_Catalog_Model_Url * @var bool */ protected $_saveRewritesHistory = null; - + + /** + * Singleton of category model for building URL path + * + * @var Mage_Catalog_Model_Category + */ + static protected $_categoryForUrlPath; + + /** + * Adds url_path property for non-root category - to ensure that url path is not empty. + * + * Sometimes attribute 'url_path' can be empty, because url_path hasn't been generated yet, + * in this case category is loaded with empty url_path and we should generate it manually. + * + * @param Varien_Object $category + * @return void + */ + protected function _addCategoryUrlPath($category) + { + if (!($category instanceof Varien_Object) || $category->getUrlPath()) { + return; + } + + // This routine is not intended to be used with root categories, but handle 'em gracefully - ensure them to have empty path. + if ($category->getLevel() <= 1) { + $category->setUrlPath(''); + return; + } + + if (self::$_categoryForUrlPath === null) { + self::$_categoryForUrlPath = Mage::getModel('catalog/category'); + } + + // Generate url_path + $urlPath = self::$_categoryForUrlPath + ->setData($category->getData()) + ->getUrlPath(); + $category->setUrlPath($urlPath); + } + /** * Retrieve stores array or store model * @@ -140,7 +186,25 @@ public function getProductModel() { return $this->getResource()->getProductModel(); } - + + /** + * Returns store root category, uses caching for it + * + * @return Varien_Object + */ + public function getStoreRootCategory($storeId) { + if (!array_key_exists($storeId, $this->_rootCategories)) { + $category = null; + $store = $this->getStores($storeId); + if ($store) { + $rootCategoryId = $store->getRootCategoryId(); + $category = $this->getResource()->getCategory($rootCategoryId, $storeId); + } + $this->_rootCategories[$storeId] = $category; + } + return $this->_rootCategories[$storeId]; + } + /** * Setter for $_saveRewritesHistory * Force Rewrites History save bypass config settings @@ -152,7 +216,7 @@ public function setShouldSaveRewritesHistory($flag) $this->_saveRewritesHistory = (bool)$flag; return $this; } - + /** * Indicate whether to save URL Rewrite History or not (create redirects to old URLs) * @@ -166,9 +230,10 @@ public function getShouldSaveRewritesHistory($storeId = null) } return Mage::helper('catalog')->shouldSaveUrlRewritesHistory($storeId); } - + /** - * Refresh rewrite urls + * Refresh all rewrite urls for some store or for all stores + * Used to make full reindexing of url rewrites * * @param int $storeId * @return Mage_Catalog_Model_Url @@ -182,6 +247,7 @@ public function refreshRewrites($storeId = null) return $this; } + $this->clearStoreInvalidRewrites($storeId); $this->refreshCategoryRewrite($this->getStores($storeId)->getRootCategoryId(), $storeId, false); $this->refreshProductRewrites($storeId); $this->getResource()->clearCategoryProduct($storeId); @@ -221,7 +287,7 @@ protected function _refreshCategoryRewrites(Varien_Object $category, $parentPath ); $this->getResource()->saveRewrite($rewriteData, $this->_rewrite); - + if ($this->getShouldSaveRewritesHistory($category->getStoreId())) { $this->_saveRewriteHistory($rewriteData, $this->_rewrite); } @@ -274,12 +340,11 @@ protected function _refreshProductRewrite(Varien_Object $product, Varien_Object $idPath = $this->generatePath('id', $product, $category); $targetPath = $this->generatePath('target', $product, $category); - //$requestPath = $this->generatePath('request', $product, $category); $requestPath = $this->getProductRequestPath($product, $category); $categoryId = null; $updateKeys = true; - if ($category->getUrlPath()) { + if ($category->getLevel() > 1) { $categoryId = $category->getId(); $updateKeys = false; } @@ -299,7 +364,7 @@ protected function _refreshProductRewrite(Varien_Object $product, Varien_Object if ($this->getShouldSaveRewritesHistory($category->getStoreId())) { $this->_saveRewriteHistory($rewriteData, $this->_rewrite); } - + if ($updateKeys && $product->getUrlKey() != $urlKey) { $product->setUrlKey($urlKey); $this->getResource()->saveProductAttribute($product, 'url_key'); @@ -338,9 +403,13 @@ protected function _refreshCategoryProductRewrites(Varien_Object $category) break; } - $this->_rewrites = $this->getResource()->prepareRewrites($category->getStoreId(), $category->getId(), array_keys($products)); + // Prepare rewrites for generation + $rootCategory = $this->getStoreRootCategory($category->getStoreId()); + $categoryIds = array($category->getId(), $rootCategory->getId()); + $this->_rewrites = $this->getResource()->prepareRewrites($category->getStoreId(), $categoryIds, array_keys($products)); foreach ($products as $product) { + $this->_refreshProductRewrite($product, $rootCategory); // Product always must have rewrite in root category $this->_refreshProductRewrite($product, $category); } $firstIteration = false; @@ -352,9 +421,10 @@ protected function _refreshCategoryProductRewrites(Varien_Object $category) /** * Refresh category and childs rewrites + * Called when reindexing all rewrites and as a reaction on category change that affects rewrites * * @param int $categoryId - * @param int $storeId + * @param int|null $storeId * @param bool $refreshProducts * @return Mage_Catalog_Model_Url */ @@ -371,6 +441,8 @@ public function refreshCategoryRewrite($categoryId, $storeId = null, $refreshPro if (!$category) { return $this; } + + // Load all childs and refresh all categories $category = $this->getResource()->loadCategoryChilds($category); $categoryIds = array($category->getId()); if ($category->getAllChilds()) { @@ -386,10 +458,11 @@ public function refreshCategoryRewrite($categoryId, $storeId = null, $refreshPro } /** - * Refresh product and categories urls + * Refresh product rewrite urls for one store or all stores + * Called as a reaction on product change that affects rewrites * * @param int $productId - * @param int $storeId + * @param int|null $storeId * @return Mage_Catalog_Model_Url */ public function refreshProductRewrite($productId, $storeId = null) @@ -401,34 +474,54 @@ public function refreshProductRewrite($productId, $storeId = null) return $this; } - if ($product = $this->getResource()->getProduct($productId, $storeId)) { - $storeRootCategoryId = $this->getStores($storeId)->getRootCategoryId(); - $categories = $this->getResource()->getCategories($product->getCategoryIds(), $storeId); + $product = $this->getResource()->getProduct($productId, $storeId); + if ($product) { + $store = $this->getStores($storeId); + $storeRootCategoryId = $store->getRootCategoryId(); + $storeRootCategoryPath = $store->getRootCategoryPath(); + $categories = $this->getResource()->getCategories($product->getCategoryIds(), $storeId); // List of categories the product is assigned to, filtered by being within the store's categories root $this->_rewrites = $this->getResource()->prepareRewrites($storeId, '', $productId); - if (!isset($categories[$storeRootCategoryId])) { - $categories[$storeRootCategoryId] = $this->getResource()->getCategory($storeRootCategoryId, $storeId); - } + // Add rewrites for all needed categories + if ($categories) { + // If product is assigned to any of store's categories - we also should use store root category to create root product url rewrite + if (!isset($categories[$storeRootCategoryId])) { + $categories[$storeRootCategoryId] = $this->getResource()->getCategory($storeRootCategoryId, $storeId); + } - foreach ($categories as $category) { - $this->_refreshProductRewrite($product, $category); + // Create product url rewrites + foreach ($categories as $category) { + $this->_refreshProductRewrite($product, $category); + } } - $this->getResource()->clearProductRewrites($productId, $storeId, array_keys($categories)); - + // Remove all other product rewrites created earlier for this store - they're invalid now. + // Always leave root categroy, as far as product is found it means that it's assigned to store's website, + // so this product must have root url rewrite + $excludeCategoryIds = $categories ? array_keys($categories) : array($storeRootCategoryId); + $this->getResource()->clearProductRewrites($productId, $storeId, $excludeCategoryIds); + unset($categories); unset($product); - -// $this->getResource()->clearCategoryProduct($storeId); + } else { + // Product doesn't belong to this store - clear all its url rewrites including root one + $this->getResource()->clearProductRewrites($productId, $storeId, array()); } return $this; } + /** + * Refresh all product rewrites for designated store + * + * @param int $storeId + * @return Mage_Catalog_Model_Url + */ public function refreshProductRewrites($storeId) { - $this->_categories = array(); - $storeRootCategoryId = $this->getStores($storeId)->getRootCategoryId(); + $this->_categories = array(); + $storeRootCategoryId = $this->getStores($storeId)->getRootCategoryId(); + $storeRootCategoryPath = $this->getStores($storeId)->getRootCategoryPath(); $this->_categories[$storeRootCategoryId] = $this->getResource()->getCategory($storeRootCategoryId, $storeId); $lastEntityId = 0; @@ -441,7 +534,6 @@ public function refreshProductRewrites($storeId) break; } - $this->_rewrites = array(); $this->_rewrites = $this->getResource()->prepareRewrites($storeId, false, array_keys($products)); $loadCategories = array(); @@ -463,6 +555,9 @@ public function refreshProductRewrites($storeId) $this->_refreshProductRewrite($product, $this->_categories[$storeRootCategoryId]); foreach ($product->getCategoryIds() as $categoryId) { if ($categoryId != $storeRootCategoryId && isset($this->_categories[$categoryId])) { + if (strpos($this->_categories[$categoryId]['path'], $storeRootCategoryPath . '/') !== 0) { + continue; + } $this->_refreshProductRewrite($product, $this->_categories[$categoryId]); } } @@ -476,6 +571,25 @@ public function refreshProductRewrites($storeId) return $this; } + /** + * Deletes old rewrites for store, left from the times when store had some other root category + * + * @param int $storeId + * @return Mage_Catalog_Model_Url + */ + public function clearStoreInvalidRewrites($storeId = null) + { + if (is_null($storeId)) { + foreach ($this->getStores() as $store) { + $this->clearStoreInvalidRewrites($store->getId()); + } + return $this; + } + + $this->getResource()->clearStoreInvalidRewrites($storeId); + return $this; + } + /** * Get requestPath that was not used yet. * @@ -577,7 +691,8 @@ public function getProductRequestPath($product, $category) /** * Prepare product base request path */ - if ($category->getUrlPath()) { + if ($category->getLevel() > 1) { + $this->_addCategoryUrlPath($category); // To ensure, that category has path either from attribute or generated now $categoryUrl = Mage::helper('catalog/category')->getCategoryUrlPath($category->getUrlPath(), false, $storeId); $requestPath = $categoryUrl . '/' . $urlKey; } else { @@ -590,7 +705,7 @@ public function getProductRequestPath($product, $category) $this->_rewrite = null; /** - * Chack $requestPath should be unique + * Check $requestPath should be unique */ if (isset($this->_rewrites[$idPath])) { $this->_rewrite = $this->_rewrites[$idPath]; @@ -652,7 +767,7 @@ public function generatePath($type = 'target', $product = null, $category = null if (!$product) { return 'category/' . $category->getId(); } - if ($category && $category->getUrlPath()) { + if ($category && $category->getLevel() > 1) { return 'product/' . $product->getId() . '/' . $category->getId(); } return 'product/' . $product->getId(); @@ -695,7 +810,8 @@ public function generatePath($type = 'target', $product = null, $category = null $urlKey = $this->getProductModel()->formatUrlKey($product->getUrlKey()); } $productUrlSuffix = $this->getProductUrlSuffix($category->getStoreId()); - if ($category->getUrlPath()) { + if ($category->getLevel() > 1) { + $this->_addCategoryUrlPath($category); // To ensure, that category has url path either from attribute or generated now $categoryUrl = Mage::helper('catalog/category')->getCategoryUrlPath($category->getUrlPath(), false, $category->getStoreId()); return $this->getUnusedPath($category->getStoreId(), $categoryUrl . '/' . $urlKey . $productUrlSuffix, $this->generatePath('id', $product, $category) @@ -712,12 +828,12 @@ public function generatePath($type = 'target', $product = null, $category = null if (!$product) { return 'catalog/category/view/id/' . $category->getId(); } - if ($category && $category->getUrlPath()) { + if ($category && $category->getLevel() > 1) { return 'catalog/product/view/id/' . $product->getId() . '/category/' . $category->getId(); } return 'catalog/product/view/id/' . $product->getId(); } - + /** * Return unique string based on the time in microseconds. * @@ -727,7 +843,7 @@ public function generateUniqueIdPath() { return str_replace('0.', '', str_replace(' ', '_', microtime())); } - + /** * Create Custom URL Rewrite for old product/category URL after url_key changed * It will perform permanent redirect from old URL to new URL @@ -746,7 +862,7 @@ protected function _saveRewriteHistory($rewriteData, $rewrite) $rewriteData['options'] = 'RP'; // Redirect = Permanent $this->getResource()->saveRewriteHistory($rewriteData); } - + return $this; } } diff --git a/app/code/core/Mage/Catalog/controllers/CategoryController.php b/app/code/core/Mage/Catalog/controllers/CategoryController.php index 62ba122115..c3c7fe1c53 100644 --- a/app/code/core/Mage/Catalog/controllers/CategoryController.php +++ b/app/code/core/Mage/Catalog/controllers/CategoryController.php @@ -29,7 +29,7 @@ * * @category Mage * @package Mage_Catalog - * @author Magento Core Team + * @author Magento Core Team */ class Mage_Catalog_CategoryController extends Mage_Core_Controller_Front_Action { @@ -40,7 +40,7 @@ class Mage_Catalog_CategoryController extends Mage_Core_Controller_Front_Action */ protected function _initCatagory() { - Mage::dispatchEvent('catalog_controller_category_init_before', array('controller_action'=>$this)); + Mage::dispatchEvent('catalog_controller_category_init_before', array('controller_action' => $this)); $categoryId = (int) $this->getRequest()->getParam('id', false); if (!$categoryId) { return false; @@ -56,23 +56,63 @@ protected function _initCatagory() Mage::getSingleton('catalog/session')->setLastVisitedCategoryId($category->getId()); Mage::register('current_category', $category); try { - Mage::dispatchEvent('catalog_controller_category_init_after', array('category'=>$category, 'controller_action'=>$this)); + Mage::dispatchEvent('catalog_controller_category_init_after', array('category' => $category, 'controller_action' => $this)); } catch (Mage_Core_Exception $e) { Mage::logException($e); return false; } + return $category; } + /** + * Recursively apply custom design settings to category if it's option + * custom_use_parent_settings is setted to 1 while parent option is not + * + * @deprecated after 1.4.2.0-beta1, functionality moved to Mage_Catalog_Model_Design + * @param Mage_Catalog_Model_Category $category + * @param Mage_Core_Model_Layout_Update $update + * + * @return Mage_Catalog_CategoryController + */ + protected function _applyCustomDesignSettings($category, $update) + { + if ($category->getCustomUseParentSettings() && $category->getLevel() > 1) { + $parentCategory = $category->getParentCategory(); + if ($parentCategory && $parentCategory->getId()) { + return $this->_applyCustomDesignSettings($parentCategory, $update); + } + } + + $validityDate = $category->getCustomDesignDate(); + + if (array_key_exists('from', $validityDate) && + array_key_exists('to', $validityDate) && + Mage::app()->getLocale()->isStoreDateInInterval(null, $validityDate['from'], $validityDate['to'])) { + if ($category->getPageLayout()) { + $this->getLayout()->helper('page/layout') + ->applyHandle($category->getPageLayout()); + } + $update->addUpdate($category->getCustomLayoutUpdate()); + } + + return $this; + } + /** * Category view action */ public function viewAction() { - if ($category = $this->_initCatagory()) { + $design = Mage::getSingleton('catalog/design'); + $settings = $design->getDesignSettings($category); + + // apply custom design + if ($settings->getCustomDesign()) { + $design->applyCustomDesign($settings->getCustomDesign()); + } - Mage::getModel('catalog/design')->applyDesign($category, Mage_Catalog_Model_Design::APPLY_FOR_CATEGORY); Mage::getSingleton('catalog/session')->setLastViewedCategoryId($category->getId()); $update = $this->getLayout()->getUpdate(); @@ -83,31 +123,28 @@ public function viewAction() } $this->addActionLayoutHandles(); - $update->addHandle($category->getLayoutUpdateHandle()); - $update->addHandle('CATEGORY_'.$category->getId()); - - - - if ($category->getPageLayout()) { - $this->getLayout()->helper('page/layout') - ->applyHandle($category->getPageLayout()); - } - + $update->addHandle('CATEGORY_' . $category->getId()); $this->loadLayoutUpdates(); - $update->addUpdate($category->getCustomLayoutUpdate()); + // apply custom layout update once layout is loaded + if ($layoutUpdates = $settings->getLayoutUpdates()) { + if (is_array($layoutUpdates)) { + foreach($layoutUpdates as $layoutUpdate) { + $update->addUpdate($layoutUpdate); + } + } + } $this->generateLayoutXml()->generateLayoutBlocks(); - - if ($category->getPageLayout()) { - $this->getLayout()->helper('page/layout') - ->applyTemplate($category->getPageLayout()); + // apply custom layout (page) template once the blocks are generated + if ($settings->getPageLayout()) { + $this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout()); } if ($root = $this->getLayout()->getBlock('root')) { - $root->addBodyClass('categorypath-'.$category->getUrlPath()) - ->addBodyClass('category-'.$category->getUrlKey()); + $root->addBodyClass('categorypath-' . $category->getUrlPath()) + ->addBodyClass('category-' . $category->getUrlKey()); } $this->_initLayoutMessages('catalog/session'); diff --git a/app/code/core/Mage/Catalog/controllers/ProductController.php b/app/code/core/Mage/Catalog/controllers/ProductController.php index ef7a46cb10..6dabde51ec 100644 --- a/app/code/core/Mage/Catalog/controllers/ProductController.php +++ b/app/code/core/Mage/Catalog/controllers/ProductController.php @@ -32,6 +32,14 @@ */ class Mage_Catalog_ProductController extends Mage_Core_Controller_Front_Action { + /** + * Current applied design settings + * + * @deprecated after 1.4.2.0-beta1 + * @var array + */ + protected $_designProductSettingsApplied = array(); + /** * Initialize requested product object * @@ -95,28 +103,34 @@ protected function _initProduct() */ protected function _initProductLayout($product) { + $design = Mage::getSingleton('catalog/design'); + $settings = $design->getDesignSettings($product); + + if ($settings->getCustomDesign()) { + $design->applyCustomDesign($settings->getCustomDesign()); + } + $update = $this->getLayout()->getUpdate(); $update->addHandle('default'); $this->addActionLayoutHandles(); $update->addHandle('PRODUCT_TYPE_'.$product->getTypeId()); $update->addHandle('PRODUCT_'.$product->getId()); - - if ($product->getPageLayout()) { - $this->getLayout()->helper('page/layout') - ->applyHandle($product->getPageLayout()); - } - $this->loadLayoutUpdates(); - - $update->addUpdate($product->getCustomLayoutUpdate()); + // apply custom layout update once layout is loaded + if ($layoutUpdates = $settings->getLayoutUpdates()) { + if (is_array($layoutUpdates)) { + foreach($layoutUpdates as $layoutUpdate) { + $update->addUpdate($layoutUpdate); + } + } + } $this->generateLayoutXml()->generateLayoutBlocks(); - - if ($product->getPageLayout()) { - $this->getLayout()->helper('page/layout') - ->applyTemplate($product->getPageLayout()); + // apply custom layout (page) template once the blocks are generated + if ($settings->getPageLayout()) { + $this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout()); } $currentCategory = Mage::registry('current_category'); @@ -131,7 +145,49 @@ protected function _initProductLayout($product) } /** - * View product action + * Recursively apply custom design settings to product if it's container + * category custom_use_for_products option is setted to 1. + * If not or product shows not in category - applyes product's internal settings + * + * @deprecated after 1.4.2.0-beta1, functionality moved to Mage_Catalog_Model_Design + * @param Mage_Catalog_Model_Category|Mage_Catalog_Model_Product $object + * @param Mage_Core_Model_Layout_Update $update + */ + protected function _applyCustomDesignSettings($object, $update) + { + if ($object instanceof Mage_Catalog_Model_Category) { + // lookup the proper category recursively + if ($object->getCustomUseParentSettings()) { + $parentCategory = $object->getParentCategory(); + if ($parentCategory && $parentCategory->getId() && $parentCategory->getLevel() > 1) { + $this->_applyCustomDesignSettings($parentCategory, $update); + } + return; + } + + // don't apply to the product + if (!$object->getCustomApplyToProducts()) { + return; + } + } + + if ($this->_designProductSettingsApplied) { + return; + } + + $date = $object->getCustomDesignDate(); + if (array_key_exists('from', $date) && array_key_exists('to', $date) + && Mage::app()->getLocale()->isStoreDateInInterval(null, $date['from'], $date['to']) + ) { + if ($object->getPageLayout()) { + $this->_designProductSettingsApplied['layout'] = $object->getPageLayout(); + } + $this->_designProductSettingsApplied['update'] = $object->getCustomLayoutUpdate(); + } + } + + /** + * Product view action */ public function viewAction() { @@ -144,8 +200,6 @@ public function viewAction() } Mage::getSingleton('catalog/session')->setLastViewedProductId($product->getId()); - Mage::getModel('catalog/design')->applyDesign($product, Mage_Catalog_Model_Design::APPLY_FOR_PRODUCT); - $this->_initProductLayout($product); $this->_initLayoutMessages('catalog/session'); $this->_initLayoutMessages('tag/session'); diff --git a/app/code/core/Mage/Catalog/etc/config.xml b/app/code/core/Mage/Catalog/etc/config.xml index b4c38cc08e..61e1818a1a 100644 --- a/app/code/core/Mage/Catalog/etc/config.xml +++ b/app/code/core/Mage/Catalog/etc/config.xml @@ -28,7 +28,7 @@ - 1.4.0.0.28 + 1.4.0.0.38 @@ -726,10 +726,6 @@ 0 30 - - 0 - - 2 @@ -748,6 +744,10 @@ 12h php,exe + + auto + 100 + + + + + + checkout/cart_api + Cart Api + cart + + + Create shopping cart + create + cart/create + + + + + 100 + Can not create new quote for + + + + + + + shoppingCart + + + + diff --git a/app/code/core/Mage/Checkout/etc/config.xml b/app/code/core/Mage/Checkout/etc/config.xml index 2a7e8a4aa5..1eb87c0c2c 100644 --- a/app/code/core/Mage/Checkout/etc/config.xml +++ b/app/code/core/Mage/Checkout/etc/config.xml @@ -54,6 +54,17 @@ taxvat gender + + prefix + firstname + middlename + lastname + suffix + email + dob + taxvat + gender + Mage_Checkout_Block 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 0000000000..5307ba5e5c --- /dev/null +++ b/app/code/core/Mage/Checkout/etc/wsdl.xml @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + Create shopping cart + + + + + + + + + + + + + + + + + + + diff --git a/app/code/core/Mage/Cms/Model/Mysql4/Block.php b/app/code/core/Mage/Cms/Model/Mysql4/Block.php index 4a13955a68..7841782aeb 100644 --- a/app/code/core/Mage/Cms/Model/Mysql4/Block.php +++ b/app/code/core/Mage/Cms/Model/Mysql4/Block.php @@ -92,16 +92,18 @@ public function load(Mage_Core_Model_Abstract $object, $value, $field=null) */ protected function _afterLoad(Mage_Core_Model_Abstract $object) { - $select = $this->_getReadAdapter()->select() - ->from($this->getTable('cms/block_store')) - ->where('block_id = ?', $object->getId()); - - if ($data = $this->_getReadAdapter()->fetchAll($select)) { - $storesArray = array(); - foreach ($data as $row) { - $storesArray[] = $row['store_id']; + if ($object->getId()) { + $select = $this->_getReadAdapter()->select() + ->from($this->getTable('cms/block_store')) + ->where('block_id = ?', $object->getId()); + + if ($data = $this->_getReadAdapter()->fetchAll($select)) { + $storesArray = array(); + foreach ($data as $row) { + $storesArray[] = $row['store_id']; + } + $object->setData('store_id', $storesArray); } - $object->setData('store_id', $storesArray); } return parent::_afterLoad($object); diff --git a/app/code/core/Mage/Cms/Model/Mysql4/Block/Collection.php b/app/code/core/Mage/Cms/Model/Mysql4/Block/Collection.php index 41d89112f3..3f5f8e3411 100644 --- a/app/code/core/Mage/Cms/Model/Mysql4/Block/Collection.php +++ b/app/code/core/Mage/Cms/Model/Mysql4/Block/Collection.php @@ -34,10 +34,13 @@ class Mage_Cms_Model_Mysql4_Block_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract { - + /** + * Declare base table and mapping of some fields + */ protected function _construct() { $this->_init('cms/block'); + $this->_map['fields']['store'] = 'store_table.store_id'; } public function toOptionArray() @@ -46,25 +49,44 @@ public function toOptionArray() } /** - * Add Filter by store + * Add filter by store * * @param int|Mage_Core_Model_Store $store - * @return Mage_Cms_Model_Mysql4_Page_Collection + * @return Mage_Cms_Model_Mysql4_Block_Collection */ public function addStoreFilter($store, $withAdmin = true) { if ($store instanceof Mage_Core_Model_Store) { $store = array($store->getId()); } + $this->addFilter('store', array('in' => ($withAdmin ? array(0, $store) : $store)), 'public'); + return $this; + } - $this->getSelect()->join( - array('store_table' => $this->getTable('cms/block_store')), - 'main_table.block_id = store_table.block_id', - array() - ) - ->where('store_table.store_id in (?)', ($withAdmin ? array(0, $store) : $store)) - ->group('main_table.block_id'); + /** + * Get SQL for get record count + * + * @return Varien_Db_Select + */ + public function getSelectCountSql() + { + $countSelect = parent::getSelectCountSql(); + $countSelect->reset(Zend_Db_Select::GROUP); + return $countSelect; + } - return $this; + /** + * Join store relation table if there is store filter + */ + protected function _renderFiltersBefore() + { + if ($this->getFilter('store')) { + $this->getSelect()->join( + array('store_table' => $this->getTable('cms/block_store')), + 'main_table.block_id = store_table.block_id', + array() + )->group('main_table.block_id'); + } + return parent::_renderFiltersBefore(); } } diff --git a/app/code/core/Mage/Cms/Model/Mysql4/Page/Collection.php b/app/code/core/Mage/Cms/Model/Mysql4/Page/Collection.php index 7b951efa7d..dc9c6c6fcf 100644 --- a/app/code/core/Mage/Cms/Model/Mysql4/Page/Collection.php +++ b/app/code/core/Mage/Cms/Model/Mysql4/Page/Collection.php @@ -36,11 +36,14 @@ class Mage_Cms_Model_Mysql4_Page_Collection extends Mage_Core_Model_Mysql4_Colle { protected $_previewFlag; + /** + * Declare base table and mapping of some fields + */ protected function _construct() { $this->_init('cms/page'); - $this->_map['fields']['page_id'] = 'main_table.page_id'; + $this->_map['fields']['store'] = 'store_table.store_id'; } /** @@ -119,30 +122,33 @@ protected function _afterLoad() } /** - * Add Filter by store + * Add filter by store * * @param int|Mage_Core_Model_Store $store * @return Mage_Cms_Model_Mysql4_Page_Collection */ public function addStoreFilter($store, $withAdmin = true) { - if (!$this->getFlag('store_filter_added')) { - if ($store instanceof Mage_Core_Model_Store) { - $store = array($store->getId()); - } + if ($store instanceof Mage_Core_Model_Store) { + $store = array($store->getId()); + } + $this->addFilter('store', array('in' => ($withAdmin ? array(0, $store) : $store)), 'public'); + return $this; + } + /** + * Join store relation table if there is store filter + */ + protected function _renderFiltersBefore() + { + if ($this->getFilter('store')) { $this->getSelect()->join( array('store_table' => $this->getTable('cms/page_store')), 'main_table.page_id = store_table.page_id', array() - ) - ->where('store_table.store_id in (?)', ($withAdmin ? array(0, $store) : $store)) - ->group('main_table.page_id'); - - $this->setFlag('store_filter_added', true); + )->group('main_table.page_id'); } - - return $this; + return parent::_renderFiltersBefore(); } /** diff --git a/app/code/core/Mage/Cms/Model/Mysql4/Page/Service.php b/app/code/core/Mage/Cms/Model/Mysql4/Page/Service.php new file mode 100644 index 0000000000..0d69f21c72 --- /dev/null +++ b/app/code/core/Mage/Cms/Model/Mysql4/Page/Service.php @@ -0,0 +1,82 @@ + + */ +class Mage_Cms_Model_Mysql4_Page_Service extends Mage_Core_Model_Mysql4_Abstract +{ + /** + * Init cms page service model + * + */ + protected function _construct() + { + $this->_init('cms/page', 'page_id'); + } + + /** + * Unlinks from $fromStoreId store pages that have same identifiers as pages in $byStoreId + * + * Routine is intented to be used before linking pages of some store ($byStoreId) to other store ($fromStoreId) + * to prevent duplication of url keys + * + * Resolved $byLinkTable can be provided when restoring links from some backup table + * + * @param int $fromStoreId + * @param int $byStoreId + * @param string $byLinkTable + * + * @return Mage_Cms_Model_Mysql4_Page_Service + */ + public function unlinkConflicts($fromStoreId, $byStoreId, $byLinkTable = null) + { + $readAdapter = $this->_getReadAdapter(); + + $linkTable = $this->getTable('cms/page_store'); + $mainTable = $this->getMainTable(); + $byLinkTable = $byLinkTable ? $byLinkTable : $linkTable; + + // Select all page ids of $fromStoreId that have identifiers as some pages in $byStoreId + $select = $readAdapter->select() + ->from(array('from_link' => $linkTable), 'page_id') + ->join(array('from_entity' => $mainTable), $readAdapter->quoteInto('from_entity.page_id = from_link.page_id AND from_link.store_id = ?', $fromStoreId), array()) + ->join(array('by_entity' => $mainTable), 'from_entity.identifier = by_entity.identifier AND from_entity.page_id != by_entity.page_id', array()) + ->join(array('by_link' => $byLinkTable), $readAdapter->quoteInto('by_link.page_id = by_entity.page_id AND by_link.store_id = ?', $byStoreId), array()); + $pageIds = $readAdapter->fetchCol($select); + + // Unlink found pages + if ($pageIds) { + $writeAdapter = $this->_getWriteAdapter(); + $where = $writeAdapter->quoteInto('page_id IN (?)', $pageIds); + $where .= $writeAdapter->quoteInto('AND store_id = ?', $fromStoreId); + $writeAdapter->delete($linkTable, $where); + } + return $this; + } +} diff --git a/app/code/core/Mage/Compiler/etc/compilation.xml b/app/code/core/Mage/Compiler/etc/compilation.xml index e01ef7d3be..4d300081bb 100644 --- a/app/code/core/Mage/Compiler/etc/compilation.xml +++ b/app/code/core/Mage/Compiler/etc/compilation.xml @@ -208,6 +208,16 @@ + + + + + + + + + +
    @@ -233,17 +243,7 @@ - - - - - - - - - - diff --git a/app/code/core/Mage/Core/Block/Abstract.php b/app/code/core/Mage/Core/Block/Abstract.php index 6778d346f9..ad96d62352 100644 --- a/app/code/core/Mage/Core/Block/Abstract.php +++ b/app/code/core/Mage/Core/Block/Abstract.php @@ -143,6 +143,11 @@ abstract class Mage_Core_Block_Abstract extends Varien_Object protected static $_urlModel; + /** + * @var Varien_Object + */ + private static $_transportObject; + /** * Internal constructor, that is called from real constructor @@ -769,13 +774,12 @@ final public function toHtml() /** * Use single transport object instance for all blocks */ - static $transport; - if ($transport === null) { - $transport = new Varien_Object; + if (self::$_transportObject === null) { + self::$_transportObject = new Varien_Object; } - $transport->setHtml($html); - Mage::dispatchEvent('core_block_abstract_to_html_after', array('block' => $this, 'transport' => $transport)); - $html = $transport->getHtml(); + self::$_transportObject->setHtml($html); + Mage::dispatchEvent('core_block_abstract_to_html_after', array('block' => $this, 'transport' => self::$_transportObject)); + $html = self::$_transportObject->getHtml(); return $html; } diff --git a/app/code/core/Mage/Core/Block/Html/Calendar.php b/app/code/core/Mage/Core/Block/Html/Calendar.php index dee672f64e..6c4a8d037c 100644 --- a/app/code/core/Mage/Core/Block/Html/Calendar.php +++ b/app/code/core/Mage/Core/Block/Html/Calendar.php @@ -29,7 +29,7 @@ * Prepares localization data for calendar * * @category Mage - * @package Mage + * @package Mage_Core * @author Magento Core Team */ class Mage_Core_Block_Html_Calendar extends Mage_Core_Block_Template diff --git a/app/code/core/Mage/Core/Block/Html/Select.php b/app/code/core/Mage/Core/Block/Html/Select.php index 3e76e26119..8741e41ea9 100644 --- a/app/code/core/Mage/Core/Block/Html/Select.php +++ b/app/code/core/Mage/Core/Block/Html/Select.php @@ -145,15 +145,24 @@ protected function _toHtml() return $html; } - protected function _optionToHtml($option, $selected=false) + /** + * Return option HTML node + * + * @param array $option + * @param boolean $selected + * @return string + */ + protected function _optionToHtml($option, $selected = false) { $selectedHtml = $selected ? ' selected="selected"' : ''; if ($this->getIsRenderToJsTemplate() === true) { $selectedHtml .= ' #{option_extra_attr_' . self::calcOptionHash($option['value']) . '}'; } - $html = ''; - return $html; + return sprintf('', + $this->htmlEscape($option['value']), + $selectedHtml, + $this->htmlEscape($option['label'])); } public function getHtml() diff --git a/app/code/core/Mage/Core/Block/Template.php b/app/code/core/Mage/Core/Block/Template.php index ed465c3b5c..4287b45e06 100644 --- a/app/code/core/Mage/Core/Block/Template.php +++ b/app/code/core/Mage/Core/Block/Template.php @@ -194,7 +194,9 @@ public function fetchView($fileName) { Varien_Profiler::start($fileName); - extract ($this->_viewVars); + // EXTR_SKIP protects from overriding + // already defined variables + extract ($this->_viewVars, EXTR_SKIP); $do = $this->getDirectOutput(); if (!$do) { @@ -209,7 +211,13 @@ public function fetchView($fileName) } try { - include $this->_viewDir . DS . $fileName; + $includeFilePath = realpath($this->_viewDir . DS . $fileName); + if (strpos($includeFilePath, realpath($this->_viewDir)) === 0) { + include $includeFilePath; + } else { + Mage::log('Not valid template file:'.$fileName, Zend_Log::CRIT, null, null, true); + } + } catch (Exception $e) { ob_get_clean(); throw $e; diff --git a/app/code/core/Mage/Core/Controller/Request/Http.php b/app/code/core/Mage/Core/Controller/Request/Http.php index ffa7d59986..0420e08712 100644 --- a/app/code/core/Mage/Core/Controller/Request/Http.php +++ b/app/code/core/Mage/Core/Controller/Request/Http.php @@ -51,10 +51,11 @@ class Mage_Core_Controller_Request_Http extends Zend_Controller_Request_Http */ protected $_rewritedPathInfo= null; protected $_requestedRouteName = null; + protected $_routingInfo = array(); protected $_route; - protected $_directFrontNames = array(); + protected $_directFrontNames = null; protected $_controllerModule = null; /** @@ -72,15 +73,6 @@ class Mage_Core_Controller_Request_Http extends Zend_Controller_Request_Http */ protected $_beforeForwardInfo = array(); - public function __construct($uri = null) - { - parent::__construct($uri); - $names = Mage::getConfig()->getNode(self::XML_NODE_DIRECT_FRONT_NAMES); - if ($names) { - $this->_directFrontNames = $names->asArray(); - } - } - /** * Returns ORIGINAL_PATH_INFO. * This value is calculated instead of reading PATH_INFO @@ -224,6 +216,14 @@ public function isDirectAccessFrontendName($code) */ public function getDirectFrontNames() { + if (is_null($this->_directFrontNames)) { + $names = Mage::getConfig()->getNode(self::XML_NODE_DIRECT_FRONT_NAMES); + if ($names) { + $this->_directFrontNames = $names->asArray(); + } else { + return array(); + } + } return $this->_directFrontNames; } @@ -361,6 +361,36 @@ public function getActionName() return $this->_action; } + /** + * Retrieve an alias + * + * Retrieve the actual key represented by the alias $name. + * + * @param string $name + * @return string|null Returns null when no alias exists + */ + public function getAlias($name) + { + $aliases = $this->getAliases(); + if (isset($aliases[$name])) { + return $aliases[$name]; + } + return null; + } + + /** + * Retrieve the list of all aliases + * + * @return array + */ + public function getAliases() + { + if (isset($this->_routingInfo['aliases'])) { + return $this->_routingInfo['aliases']; + } + return parent::getAliases(); + } + /** * Get route name used in request (ignore rewrite) * @@ -368,6 +398,9 @@ public function getActionName() */ public function getRequestedRouteName() { + if (isset($this->_routingInfo['requested_route'])) { + return $this->_routingInfo['requested_route']; + } if ($this->_requestedRouteName === null) { if ($this->_rewritedPathInfo !== null && isset($this->_rewritedPathInfo[0])) { $fronName = $this->_rewritedPathInfo[0]; @@ -388,6 +421,9 @@ public function getRequestedRouteName() */ public function getRequestedControllerName() { + if (isset($this->_routingInfo['requested_controller'])) { + return $this->_routingInfo['requested_controller']; + } if (($this->_rewritedPathInfo !== null) && isset($this->_rewritedPathInfo[1])) { return $this->_rewritedPathInfo[1]; } @@ -401,12 +437,29 @@ public function getRequestedControllerName() */ public function getRequestedActionName() { + if (isset($this->_routingInfo['requested_action'])) { + return $this->_routingInfo['requested_action']; + } if (($this->_rewritedPathInfo !== null) && isset($this->_rewritedPathInfo[2])) { return $this->_rewritedPathInfo[2]; } return $this->getActionName(); } + /** + * Set routing info data + * + * @param array $data + * @return Mage_Core_Controller_Request_Http + */ + public function setRoutingInfo($data) + { + if (is_array($data)) { + $this->_routingInfo = $data; + } + return $this; + } + /** * Collect properties changed by _forward in protected storage * before _forward was called first time. @@ -459,4 +512,20 @@ public function isStraight($flag = null) } return $this->_isStraight; } + + /** + * Check is Request from AJAX + * + * @return boolean + */ + public function isAjax() + { + if ($this->isXmlHttpRequest()) { + return true; + } + if ($this->getParam('ajax') || $this->getParam('isAjax')) { + return true; + } + return false; + } } diff --git a/app/code/core/Mage/Core/Controller/Varien/Action.php b/app/code/core/Mage/Core/Controller/Varien/Action.php index 195df3dfa1..0db5053290 100644 --- a/app/code/core/Mage/Core/Controller/Varien/Action.php +++ b/app/code/core/Mage/Core/Controller/Varien/Action.php @@ -469,6 +469,11 @@ public function preDispatch() } } + // Prohibit disabled store actions + if (Mage::isInstalled() && !Mage::app()->getStore()->getIsActive()) { + Mage::app()->throwStoreException(); + } + if ($this->_rewrite()) { return; } diff --git a/app/code/core/Mage/Core/Controller/Varien/Front.php b/app/code/core/Mage/Core/Controller/Varien/Front.php index 80a3c09aee..628f1d966f 100644 --- a/app/code/core/Mage/Core/Controller/Varien/Front.php +++ b/app/code/core/Mage/Core/Controller/Varien/Front.php @@ -169,7 +169,6 @@ public function dispatch() Varien_Profiler::start('mage::dispatch::config_url_rewrite'); $this->rewrite(); Varien_Profiler::stop('mage::dispatch::config_url_rewrite'); - Varien_Profiler::start('mage::dispatch::routers_match'); $i = 0; while (!$request->isDispatched() && $i++<100) { @@ -183,7 +182,8 @@ public function dispatch() if ($i>100) { Mage::throwException('Front controller reached 100 router match iterations'); } - + //This event give possibility to launch smth before sending ouptut(Allow cookie setting) + Mage::dispatchEvent('controller_front_send_response_before', array('front'=>$this)); Varien_Profiler::start('mage::app::dispatch::send_response'); $this->getResponse()->sendResponse(); Varien_Profiler::stop('mage::app::dispatch::send_response'); @@ -296,7 +296,7 @@ protected function _checkBaseUrl($request) if (!Mage::isInstalled() || $request->getPost()) { return; } - if (!Mage::getStoreConfigFlag('web/url/redirect_to_base')) { + if (!Mage::getStoreConfig('web/url/redirect_to_base')) { return; } @@ -306,6 +306,11 @@ protected function _checkBaseUrl($request) return; } + $redirectCode = 302; + if (Mage::getStoreConfig('web/url/redirect_to_base')==301) { + $redirectCode = 301; + } + $uri = @parse_url($baseUrl); $host = isset($uri['host']) ? $uri['host'] : ''; $path = isset($uri['path']) ? $uri['path'] : ''; @@ -314,7 +319,7 @@ protected function _checkBaseUrl($request) if ($host && $host != $request->getHttpHost() || $path && strpos($requestUri, $path) === false) { Mage::app()->getFrontController()->getResponse() - ->setRedirect($baseUrl) + ->setRedirect($baseUrl, $redirectCode) ->sendResponse(); exit; } diff --git a/app/code/core/Mage/Core/Controller/Varien/Router/Admin.php b/app/code/core/Mage/Core/Controller/Varien/Router/Admin.php index c20dda0140..50754eca65 100644 --- a/app/code/core/Mage/Core/Controller/Varien/Router/Admin.php +++ b/app/code/core/Mage/Core/Controller/Varien/Router/Admin.php @@ -30,7 +30,7 @@ class Mage_Core_Controller_Varien_Router_Admin extends Mage_Core_Controller_Vari public function fetchDefault() { // set defaults - $d = explode('/', (string)Mage::getConfig()->getNode('default/web/default/admin')); + $d = explode('/', $this->_getDefaultPath()); $this->getFront()->setDefault(array( 'module' => !empty($d[0]) ? $d[0] : '', 'controller' => !empty($d[1]) ? $d[1] : 'index', @@ -38,6 +38,15 @@ public function fetchDefault() )); } + /** + * Get router default request path + * @return string + */ + protected function _getDefaultPath() + { + return (string)Mage::getConfig()->getNode('default/web/default/admin'); + } + /** * dummy call to pass through checking * diff --git a/app/code/core/Mage/Core/Controller/Varien/Router/Default.php b/app/code/core/Mage/Core/Controller/Varien/Router/Default.php index 0a976263be..26a2ee1051 100644 --- a/app/code/core/Mage/Core/Controller/Varien/Router/Default.php +++ b/app/code/core/Mage/Core/Controller/Varien/Router/Default.php @@ -26,20 +26,35 @@ class Mage_Core_Controller_Varien_Router_Default extends Mage_Core_Controller_Varien_Router_Abstract { + /** + * Modify request and set to no-route action + * If store is admin and specified different admin front name, + * change store to default (Possible when enabled Store Code in URL) + * + * @param Zend_Controller_Request_Http $request + * @return boolean + */ public function match(Zend_Controller_Request_Http $request) { - $d = explode('/', Mage::app()->getStore()->getConfig('web/default/no_route')); - $request->setModuleName(isset($d[0]) ? $d[0] : 'core') - ->setControllerName(isset($d[1]) ? $d[1] : 'index') - ->setActionName(isset($d[2]) ? $d[2] : 'index'); + $noRoute = explode('/', Mage::app()->getStore()->getConfig('web/default/no_route')); + $moduleName = isset($noRoute[0]) ? $noRoute[0] : 'core'; + $controllerName = isset($noRoute[1]) ? $noRoute[1] : 'index'; + $actionName = isset($noRoute[2]) ? $noRoute[2] : 'index'; + + if (Mage::app()->getStore()->isAdmin()) { + $adminFrontName = (string)Mage::getConfig()->getNode('admin/routers/adminhtml/args/frontName'); + if ($adminFrontName != $moduleName) { + $moduleName = 'core'; + $controllerName = 'index'; + $actionName = 'noRoute'; + Mage::app()->setCurrentStore(Mage::app()->getDefaultStoreView()); + } + } + + $request->setModuleName($moduleName) + ->setControllerName($controllerName) + ->setActionName($actionName); return true; } - /* - public function getUrl($routeName, $params) - { - return 'no-route'; - } - */ - } diff --git a/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php b/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php index 0c461efb45..b7a2dcb8d6 100644 --- a/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php +++ b/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php @@ -117,9 +117,8 @@ public function match(Zend_Controller_Request_Http $request) if ($path) { $p = explode('/', $path); - } - else { - $p = explode('/', Mage::getStoreConfig('web/default/front')); + } else { + $p = explode('/', $this->_getDefaultPath()); } // get module name @@ -246,7 +245,7 @@ public function match(Zend_Controller_Request_Http $request) // set parameters from pathinfo for ($i=3, $l=sizeof($p); $i<$l; $i+=2) { - $request->setParam($p[$i], isset($p[$i+1]) ? $p[$i+1] : ''); + $request->setParam($p[$i], isset($p[$i+1]) ? urldecode($p[$i+1]) : ''); } // dispatch action @@ -256,6 +255,15 @@ public function match(Zend_Controller_Request_Http $request) return true; } + /** + * Get router default request path + * @return string + */ + protected function _getDefaultPath() + { + return Mage::getStoreConfig('web/default/front'); + } + /** * Allow to control if we need to enable no route functionality in current router * diff --git a/app/code/core/Mage/Core/Helper/Data.php b/app/code/core/Mage/Core/Helper/Data.php index 9c9e8b2919..c9079b9fdc 100644 --- a/app/code/core/Mage/Core/Helper/Data.php +++ b/app/code/core/Mage/Core/Helper/Data.php @@ -381,6 +381,13 @@ public function copyFieldset($fieldset, $aspect, $source, $target, $root='global $result = true; } + $eventName = sprintf('core_copy_fieldset_%s_%s', $fieldset, $aspect); + Mage::dispatchEvent($eventName, array( + 'target' => $target, + 'source' => $source, + 'root' => $root + )); + return $result; } @@ -628,7 +635,7 @@ public function mergeFiles(array $srcFiles, $targetFile = false, $mustMerge = fa } else { $targetMtime = filemtime($targetFile); foreach ($srcFiles as $file) { - if (filemtime($file) > $targetMtime) { + if (!file_exists($file) || @filemtime($file) > $targetMtime) { $shouldMerge = true; break; } diff --git a/app/code/core/Mage/Core/Helper/Js.php b/app/code/core/Mage/Core/Helper/Js.php index b464a4ebec..2840f5312e 100644 --- a/app/code/core/Mage/Core/Helper/Js.php +++ b/app/code/core/Mage/Core/Helper/Js.php @@ -142,7 +142,8 @@ protected function _getTranslateData() $this->__('Please enter a valid email address. For example johndoe@domain.com.'), 'Please enter 6 or more characters.' => $this->__('Please enter 6 or more characters.'), 'Please make sure your passwords match.' => $this->__('Please make sure your passwords match.'), - 'Please enter a valid URL. http:// is required' => $this->__('Please enter a valid URL. http:// is required'), + 'Please enter a valid URL. Protocol is required (http://, https:// or ftp://)' => + $this->__('Please enter a valid URL. Protocol is required (http://, https:// or ftp://)'), 'Please enter a valid URL. For example http://www.example.com or www.example.com' => $this->__('Please enter a valid URL. For example http://www.example.com or www.example.com'), 'Please enter a valid social security number. For example 123-45-6789.' => @@ -174,21 +175,36 @@ protected function _getTranslateData() 'Your order cannot be completed at this time as there is no payment methods available for it.' => $this->__('Your order cannot be completed at this time as there is no payment methods available for it.'), 'Please specify payment method.' => $this->__('Please specify payment method.'), - 'Credit card number doesn\'t match credit card type' => $this->__('Credit card number does not match credit card type'), - 'Card type does not match credit card number' => $this->__('Card type does not match credit card number'), + 'Credit card number does not match credit card type.' => $this->__('Credit card number does not match credit card type.'), + 'Card type does not match credit card number.' => $this->__('Card type does not match credit card number.'), 'Please enter a valid credit card verification number.' => $this->__('Please enter a valid credit card verification number.'), 'Please use only letters (a-z or A-Z), numbers (0-9) or underscore(_) in this field, first character should be a letter.' => $this->__('Please use only letters (a-z or A-Z), numbers (0-9) or underscores (_) in this field, first character must be a letter.'), - 'Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%' => $this->__('Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%'), + 'Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%.' => + $this->__('Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%.'), 'Maximum length exceeded.' => $this->__('Maximum length exceeded.'), - - - //Mage_Rule - 'Your session has been expired, you will be relogged in now.' => $this->__('Your session has been expired, you will be relogged in now.'), - 'Incorrect credit card expiration date' => $this->__('Incorrect credit card expiration date'), - // Date + 'Incorrect credit card expiration date.' => $this->__('Incorrect credit card expiration date.'), 'This date is a required value.' => $this->__('This date is a required value.'), + 'The value is not within the specified range.' => $this->__('The value is not within the specified range.'), + 'Please use only letters (a-z or A-Z) or numbers (0-9) only in this field. No spaces or other characters are allowed.' + => $this->__('Please use only letters (a-z or A-Z) or numbers (0-9) only in this field. No spaces or other characters are allowed.'), + 'Please use only letters (a-z or A-Z) or numbers (0-9) or spaces and # only in this field.' => + $this->__('Please use only letters (a-z or A-Z) or numbers (0-9) or spaces and # only in this field.'), + 'Please enter a valid fax number. For example (123) 456-7890 or 123-456-7890.' => + $this->__('Please enter a valid fax number. For example (123) 456-7890 or 123-456-7890.'), + 'Please use only visible characters and spaces.' => $this->__('Please use only visible characters and spaces.'), + 'Please enter 7 or more characters. Password should contain both numeric and alphabetic characters.' => + $this->__('Please enter 7 or more characters. Password should contain both numeric and alphabetic characters.'), + 'Please enter a valid URL Key. For example "example-page", "example-page.html" or "anotherlevel/example-page".' => + $this->__('Please enter a valid URL Key. For example "example-page", "example-page.html" or "anotherlevel/example-page".'), + 'Please enter a valid XML-identifier. For example something_1, block5, id-4.' => + $this->__('Please enter a valid XML-identifier. For example something_1, block5, id-4.'), + 'Please enter a number 0 or greater in this field.' => $this->__('Please enter a number 0 or greater in this field.'), + 'Text length does not satisfy specified text range.' => $this->__('Text length does not satisfy specified text range.'), + 'Please enter a number lower than 100.' => $this->__('Please enter a number lower than 100.'), + 'Please enter issue number or start date for switch/solo card type.' => + $this->__('Please enter issue number or start date for switch/solo card type.'), ); foreach ($this->_translateData as $key=>$value) { if ($key == $value) { diff --git a/app/code/core/Mage/Core/Helper/Url.php b/app/code/core/Mage/Core/Helper/Url.php index f4f2f2bbef..eb502f17b5 100644 --- a/app/code/core/Mage/Core/Helper/Url.php +++ b/app/code/core/Mage/Core/Helper/Url.php @@ -41,7 +41,10 @@ class Mage_Core_Helper_Url extends Mage_Core_Helper_Abstract */ public function getCurrentUrl() { - return $this->_getUrl('*/*/*', array('_current' => true, '_use_rewrite' => true)); + $request = Mage::app()->getRequest(); + $url = $request->getScheme() . '://' . $request->getHttpHost() . $request->getServer('REQUEST_URI'); + return $url; +// return $this->_getUrl('*/*/*', array('_current' => true, '_use_rewrite' => true)); } /** diff --git a/app/code/core/Mage/Core/Helper/Url/Rewrite.php b/app/code/core/Mage/Core/Helper/Url/Rewrite.php new file mode 100644 index 0000000000..108c6e3b65 --- /dev/null +++ b/app/code/core/Mage/Core/Helper/Url/Rewrite.php @@ -0,0 +1,97 @@ + + */ +class Mage_Core_Helper_Url_Rewrite extends Mage_Core_Helper_Abstract +{ + /** + * Validation error constants + */ + const VERR_MANYSLASHES = 1; // Too many slashes in a row of request path, e.g. '///foo//' + const VERR_ANCHOR = 2; // Anchor is not supported in request path, e.g. 'foo#bar' + + /** + * Core func to validate request path + * If something is wrong with a path it throws localized error message and error code, + * that can be checked to by wrapper func to alternate error message + * + * @return bool + */ + protected function _validateRequestPath($requestPath) + { + if (strpos($requestPath, '//') !== false) { + throw new Exception($this->__('Two and more slashes together are not permitted in request path'), self::VERR_MANYSLASHES); + } + if (strpos($requestPath, '#') !== false) { + throw new Exception($this->__('Anchor symbol (#) is not supported in request path'), self::VERR_ANCHOR); + } + return true; + } + + /** + * Validates request path + * Either returns TRUE (success) or throws error (validation failed) + * + * @return bool + */ + public function validateRequestPath($requestPath) + { + try { + $this->_validateRequestPath($requestPath); + } catch (Exception $e) { + Mage::throwException($e->getMessage()); + } + return true; + } + + /** + * Validates suffix for url rewrites to inform user about errors in it + * Either returns TRUE (success) or throws error (validation failed) + * + * @return bool + */ + public function validateSuffix($suffix) + { + try { + $this->_validateRequestPath($suffix); // Suffix itself must be a valid request path + } catch (Exception $e) { + // Make message saying about suffix, not request path + switch ($e->getCode()) { + case self::VERR_MANYSLASHES: + Mage::throwException($this->__('Two and more slashes together are not permitted in url rewrite suffix')); + case self::VERR_ANCHOR: + Mage::throwException($this->__('Anchor symbol (#) is not supported in url rewrite suffix')); + } + } + return true; + } +} diff --git a/app/code/core/Mage/Core/Model/Abstract.php b/app/code/core/Mage/Core/Model/Abstract.php index 7b62e6d86c..0bcf7de0e4 100644 --- a/app/code/core/Mage/Core/Model/Abstract.php +++ b/app/code/core/Mage/Core/Model/Abstract.php @@ -282,6 +282,18 @@ public function afterLoad() return $this; } + /** + * Check whether model has changed data. + * Can be overloaded in child classes to perform advanced check whether model needs to be saved + * e.g. usign resouceModel->hasDataChanged() or any other technique + * + * @return boolean + */ + protected function _hasModelChanged() + { + return $this->hasDataChanges(); + } + /** * Save object data * @@ -295,7 +307,7 @@ public function save() if ($this->isDeleted()) { return $this->delete(); } - if (!$this->hasDataChanges()) { + if (!$this->_hasModelChanged()) { return $this; } $this->_getResource()->beginTransaction(); diff --git a/app/code/core/Mage/Core/Model/App.php b/app/code/core/Mage/Core/Model/App.php index 9907a4ce2d..661303dcb0 100644 --- a/app/code/core/Mage/Core/Model/App.php +++ b/app/code/core/Mage/Core/Model/App.php @@ -415,6 +415,7 @@ protected function _initCurrentStore($scopeCode, $scopeType) $this->_checkCookieStore($scopeType); $this->_checkGetStore($scopeType); } + $this->_useSessionInUrl = $this->getStore()->getConfig(Mage_Core_Model_Session_Abstract::XML_PATH_USE_FRONTEND_SID); return $this; } @@ -474,9 +475,9 @@ protected function _checkGetStore($type) if ($this->_currentStore == $store) { $store = $this->getStore($store); if ($store->getWebsite()->getDefaultStore()->getId() == $store->getId()) { - $this->getCookie()->delete('store'); + $this->getCookie()->delete(Mage_Core_Model_Store::COOKIE_NAME); } else { - $this->getCookie()->set('store', $this->_currentStore, true); + $this->getCookie()->set(Mage_Core_Model_Store::COOKIE_NAME, $this->_currentStore, true); } } return $this; @@ -494,7 +495,7 @@ protected function _checkCookieStore($type) return $this; } - $store = $this->getCookie()->get('store'); + $store = $this->getCookie()->get(Mage_Core_Model_Store::COOKIE_NAME); if ($store && isset($this->_stores[$store]) && $this->_stores[$store]->getId() && $this->_stores[$store]->getIsActive()) { diff --git a/app/code/core/Mage/Core/Model/Config.php b/app/code/core/Mage/Core/Model/Config.php index e1ad6d1250..82de1bea74 100644 --- a/app/code/core/Mage/Core/Model/Config.php +++ b/app/code/core/Mage/Core/Model/Config.php @@ -812,21 +812,23 @@ public function determineOmittedNamespace($name, $asFullModuleName = false) $name = explode('_', strtolower($name)); $partsNum = count($name); - $i = 0; + $defaultNamespaceFlag = false; foreach ($this->_moduleNamespaces as $namespaceName => $namespace) { // assume the namespace is omitted (default namespace only, which comes first) - if (0 === $i) { + if ($defaultNamespaceFlag === false) { + $defaultNamespaceFlag = true; $defaultNS = $namespaceName . '_' . $name[0]; if (isset($namespace[$defaultNS])) { return $asFullModuleName ? $namespace[$defaultNS] : $name[0]; // return omitted as well } } // assume namespace is qualified - $fullNS = $name[0] . '_' . $name[1]; - if (2 <= $partsNum && isset($namespace[$fullNS])) { - return $asFullModuleName ? $namespace[$fullNS] : $fullNS; + if(isset($name[1])) { + $fullNS = $name[0] . '_' . $name[1]; + if (2 <= $partsNum && isset($namespace[$fullNS])) { + return $asFullModuleName ? $namespace[$fullNS] : $fullNS; + } } - $i++; } return ''; } diff --git a/app/code/core/Mage/Core/Model/Design/Package.php b/app/code/core/Mage/Core/Model/Design/Package.php index 2f3cfda3e0..74b2d0391d 100644 --- a/app/code/core/Mage/Core/Model/Design/Package.php +++ b/app/code/core/Mage/Core/Model/Design/Package.php @@ -726,17 +726,26 @@ protected function _prepareUrl($uri) { // check absolute or relative url if (!preg_match('/^[http|https]/i', $uri) && !preg_match('/^\//i', $uri)) { - $fileDir = ''; $pathParts = explode(DS, $uri); $fileDirParts = explode(DS, $this->_callbackFileDir); - $baseUrl = Mage::getBaseUrl('web'); + $store = $this->getStore(); + $secure = $store->isAdmin() ? $store->isAdminUrlSecure() : $store->isFrontUrlSecure(); + + if ('skin' == $fileDirParts[0]) { + $baseUrl = Mage::getBaseUrl('skin', $secure); + $fileDirParts = array_slice($fileDirParts, 1); + } elseif ('media' == $fileDirParts[0]) { + $baseUrl = Mage::getBaseUrl('media', $secure); + $fileDirParts = array_slice($fileDirParts, 1); + } else { + $baseUrl = Mage::getBaseUrl('web', $secure); + } foreach ($pathParts as $key=>$part) { if ($part == '.' || $part == '..') { unset($pathParts[$key]); } - if ($part == '..' && count($fileDirParts)) { $fileDirParts = array_slice($fileDirParts, 0, count($fileDirParts) - 1); } diff --git a/app/code/core/Mage/Core/Model/Design/Source/Apply.php b/app/code/core/Mage/Core/Model/Design/Source/Apply.php index 87ba9e88cb..2a97495286 100644 --- a/app/code/core/Mage/Core/Model/Design/Source/Apply.php +++ b/app/code/core/Mage/Core/Model/Design/Source/Apply.php @@ -24,7 +24,9 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - +/** + * @deprecated after 1.4.1.0. + */ class Mage_Core_Model_Design_Source_Apply extends Mage_Eav_Model_Entity_Attribute_Source_Abstract { public function getAllOptions() diff --git a/app/code/core/Mage/Core/Model/Email/Template.php b/app/code/core/Mage/Core/Model/Email/Template.php index 087404a25b..c13a7aff9b 100644 --- a/app/code/core/Mage/Core/Model/Email/Template.php +++ b/app/code/core/Mage/Core/Model/Email/Template.php @@ -42,14 +42,8 @@ * @package Mage_Core * @author Magento Core Team */ -class Mage_Core_Model_Email_Template extends Mage_Core_Model_Abstract +class Mage_Core_Model_Email_Template extends Mage_Core_Model_Template { - /** - * Types of template - */ - const TYPE_TEXT = 1; - const TYPE_HTML = 2; - /** * Configuration path for default email templates * @@ -64,13 +58,6 @@ class Mage_Core_Model_Email_Template extends Mage_Core_Model_Abstract static protected $_defaultTemplates; - /** - * Configuration of desing package for template - * - * @var Varien_Object - */ - protected $_designConfig; - /** * Initialize email template model * @@ -252,13 +239,12 @@ public function isValidForSend() } /** - * Return true if template type eq text + * Getter for template type * - * @return boolean + * @return int|string */ - public function isPlain() - { - return $this->getTemplateType() == self::TYPE_TEXT; + public function getType(){ + return $this->getTemplateType(); } /** @@ -277,6 +263,10 @@ public function getProcessedTemplate(array $variables = array()) $variables['this'] = $this; } + if(isset($variables['subscriber']) && ($variables['subscriber'] instanceof Mage_Newsletter_Model_Subscriber)) { + $processor->setStoreId($variables['subscriber']->getStoreId()); + } + $processor->setIncludeProcessor(array($this, 'getInclude')) ->setVariables($variables); @@ -327,9 +317,9 @@ public function getInclude($template, array $variables) /** * Send mail to recipient * - * @param string $email E-mail - * @param string|null $name receiver name - * @param array $variables template variables + * @param array|string $email E-mail(s) + * @param array|string|null $name receiver name(s) + * @param array $variables template variables * @return boolean **/ public function send($email, $name = null, array $variables = array()) @@ -339,12 +329,17 @@ public function send($email, $name = null, array $variables = array()) return false; } - if (is_null($name)) { - $name = substr($email, 0, strpos($email, '@')); + $emails = array_values((array)$email); + $names = is_array($name) ? $name : (array)$name; + $names = array_values($names); + foreach ($emails as $key => $email) { + if (!isset($names[$key])) { + $names[$key] = substr($email, 0, strpos($email, '@')); + } } - $variables['email'] = $email; - $variables['name'] = $name; + $variables['email'] = reset($emails); + $variables['name'] = reset($names); ini_set('SMTP', Mage::getStoreConfig('system/smtp/host')); ini_set('smtp_port', Mage::getStoreConfig('system/smtp/port')); @@ -365,15 +360,12 @@ public function send($email, $name = null, array $variables = array()) } if ($returnPathEmail !== null) { - $mail->setReturnPath($returnPathEmail); + $mailTransport = new Zend_Mail_Transport_Sendmail($returnPathEmail); + Zend_Mail::setDefaultTransport($mailTransport); } - if (is_array($email)) { - foreach ($email as $emailOne) { - $mail->addTo($emailOne, $name); - } - } else { - $mail->addTo($email, '=?utf-8?B?'.base64_encode($name).'?='); + foreach ($emails as $key => $email) { + $mail->addTo($email, '=?utf-8?B?' . base64_encode($names[$key]) . '?='); } $this->setUseAbsoluteLinks(true); @@ -385,7 +377,7 @@ public function send($email, $name = null, array $variables = array()) $mail->setBodyHTML($text); } - $mail->setSubject('=?utf-8?B?'.base64_encode($this->getProcessedTemplateSubject($variables)).'?='); + $mail->setSubject('=?utf-8?B?' . base64_encode($this->getProcessedTemplateSubject($variables)) . '?='); $mail->setFrom($this->getSenderEmail(), $this->getSenderName()); try { @@ -474,81 +466,6 @@ public function getProcessedTemplateSubject(array $variables) return $processedResult; } - /** - * Initialize design information for email template and subject processing - * - * @param array $config - * @return Mage_Core_Model_Email_Template - */ - public function setDesignConfig(array $config) - { - $this->getDesignConfig()->setData($config); - return $this; - } - - /** - * Get design configuration data - * - * @return Varien_Object - */ - public function getDesignConfig() - { - if(is_null($this->_designConfig)) { - $this->_designConfig = new Varien_Object(); - } - return $this->_designConfig; - } - - /** - * Apply declared configuration for design - * - * @return Mage_Core_Model_Email_Template - */ - protected function _applyDesignConfig() - { - if ($this->getDesignConfig()) { - $design = Mage::getDesign(); - $this->getDesignConfig() - ->setOldArea($design->getArea()) - ->setOldStore($design->getStore()); - - if ($this->getDesignConfig()->getArea()) { - Mage::getDesign()->setArea($this->getDesignConfig()->getArea()); - } - - if ($this->getDesignConfig()->getStore()) { - Mage::app()->getLocale()->emulate($this->getDesignConfig()->getStore()); - $design->setStore($this->getDesignConfig()->getStore()); - $design->setTheme(''); - $design->setPackageName(''); - } - - } - return $this; - } - - /** - * Revert design settings to previous - * - * @return Mage_Core_Model_Email_Template - */ - protected function _cancelDesignConfig() - { - if ($this->getDesignConfig()) { - if ($this->getDesignConfig()->getOldArea()) { - Mage::getDesign()->setArea($this->getDesignConfig()->getOldArea()); - } - - if ($this->getDesignConfig()->getOldStore()) { - Mage::getDesign()->setStore($this->getDesignConfig()->getOldStore()); - Mage::getDesign()->setTheme(''); - Mage::getDesign()->setPackageName(''); - } - } - Mage::app()->getLocale()->revert(); - return $this; - } - public function addBcc($bcc) { if (is_array($bcc)) { @@ -582,7 +499,7 @@ public function setReturnPath($email) */ public function setReplyTo($email) { - $this->getMail()->addHeader('Reply-To', $email); + $this->getMail()->setReplyTo($email); return $this; } diff --git a/app/code/core/Mage/Core/Model/Layout.php b/app/code/core/Mage/Core/Model/Layout.php index c9eb72e955..b093209c62 100644 --- a/app/code/core/Mage/Core/Model/Layout.php +++ b/app/code/core/Mage/Core/Model/Layout.php @@ -37,7 +37,7 @@ class Mage_Core_Model_Layout extends Varien_Simplexml_Config /** * Layout Update module * - * @var Mage_Core_Layout_Update + * @var Mage_Core_Model_Layout_Update */ protected $_update; diff --git a/app/code/core/Mage/Core/Model/Mysql4/Abstract.php b/app/code/core/Mage/Core/Model/Mysql4/Abstract.php index 6f2aeaf9ae..2f3bc90bcb 100644 --- a/app/code/core/Mage/Core/Model/Mysql4/Abstract.php +++ b/app/code/core/Mage/Core/Model/Mysql4/Abstract.php @@ -571,6 +571,29 @@ protected function _prepareDataForTable(Varien_Object $object, $table) return $data; } + /** + * Check that model data fields that can be saved + * has really changed comparing with origData + * + * @param Mage_Core_Model_Abstract $object + * @return boolean + */ + public function hasDataChanged($object) + { + if (!$object->getOrigData()) { + return true; + } + + $fields = $this->_getWriteAdapter()->describeTable($this->getMainTable()); + foreach (array_keys($fields) as $field) { + if ($object->getOrigData($field) != $object->getData($field)) { + return true; + } + } + + return false; + } + /** * Prepare value for save * diff --git a/app/code/core/Mage/Core/Model/Mysql4/Collection/Abstract.php b/app/code/core/Mage/Core/Model/Mysql4/Collection/Abstract.php index 3520981eb2..39275c5ba5 100644 --- a/app/code/core/Mage/Core/Model/Mysql4/Collection/Abstract.php +++ b/app/code/core/Mage/Core/Model/Mysql4/Collection/Abstract.php @@ -84,6 +84,25 @@ abstract class Mage_Core_Model_Mysql4_Collection_Abstract extends Varien_Data_Co */ protected $_mainTable = null; + /** + * Reset items data changed flag + * + * @var boolean + */ + protected $_resetItemsDataChanged = false; + + /** + * Event prefix key + * @var string + */ + protected $_eventPrefix = ''; + + /** + * Event object key + * @var string + */ + protected $_eventObject = ''; + /** * Collection constructor * @@ -148,7 +167,7 @@ public function setMainTable($table) /** * Init collection select * - * @return unknown + * @return Mage_Core_Model_Mysql4_Collection_Abstract */ protected function _initSelect() { @@ -321,7 +340,7 @@ public function addExpressionFieldToSelect($alias, $expression, $fields) foreach($fields as $fieldKey=>$fieldItem) { $fullExpression = str_replace('{{' . $fieldKey . '}}', $fieldItem, $fullExpression); } - + $this->getSelect()->columns(array($alias=>$fullExpression)); return $this; @@ -450,7 +469,7 @@ public function getAllIds() $idsSelect->columns( 'main_table.' . $this->getResource()->getIdFieldName() ); - return $this->getConnection()->fetchCol($idsSelect); + return $this->getConnection()->fetchCol($idsSelect, $this->_bindParams); } public function join($table, $cond, $cols='*') @@ -471,6 +490,37 @@ protected function _beforeLoad() { parent::_beforeLoad(); Mage::dispatchEvent('core_collection_abstract_load_before', array('collection' => $this)); + if ($this->_eventPrefix && $this->_eventObject) { + Mage::dispatchEvent($this->_eventPrefix.'_load_before', array( + $this->_eventObject => $this + )); + } + return $this; + } + + /** + * Set reset items data changed flag + * + * @param boolean $flag + * @return Mage_Core_Model_Mysql4_Collection_Abstract + */ + public function setResetItemsDataChanged($flag) + { + $this->_resetItemsDataChanged = (bool)$flag; + return $this; + } + + /** + * Set flag data has changed to all collection items + * + * @return Mage_Core_Model_Mysql4_Collection_Abstract + */ + public function resetItemsDataChanged() + { + foreach ($this->_items as $item) { + $item->setDataChanges(false); + } + return $this; } @@ -484,6 +534,9 @@ protected function _afterLoad() parent::_afterLoad(); foreach ($this->_items as $item) { $item->setOrigData(); + if ($this->_resetItemsDataChanged) { + $item->setDataChanges(false); + } } Mage::dispatchEvent('core_collection_abstract_load_after', array('collection' => $this)); return $this; diff --git a/app/code/core/Mage/Core/Model/Mysql4/Config.php b/app/code/core/Mage/Core/Model/Mysql4/Config.php index 91fce817c5..89eaa617b7 100644 --- a/app/code/core/Mage/Core/Model/Mysql4/Config.php +++ b/app/code/core/Mage/Core/Model/Mysql4/Config.php @@ -86,6 +86,9 @@ public function loadToXml(Mage_Core_Model_Config $xmlConfig, $cond=null) $stores = array(); $rows = $read->fetchAssoc("select store_id, code, name, website_id from ".$this->getTable('store')." order by sort_order asc"); foreach ($rows as $s) { + if (!isset($websites[$s['website_id']])) { + continue; + } $xmlConfig->setNode('stores/'.$s['code'].'/system/store/id', $s['store_id']); $xmlConfig->setNode('stores/'.$s['code'].'/system/store/name', $s['name']); $xmlConfig->setNode('stores/'.$s['code'].'/system/website/id', $s['website_id']); diff --git a/app/code/core/Mage/Core/Model/Mysql4/Url/Rewrite.php b/app/code/core/Mage/Core/Model/Mysql4/Url/Rewrite.php index 89869ef5fb..fdad542007 100644 --- a/app/code/core/Mage/Core/Model/Mysql4/Url/Rewrite.php +++ b/app/code/core/Mage/Core/Model/Mysql4/Url/Rewrite.php @@ -108,4 +108,55 @@ public function getRequestPathByIdPath($idPath, $store) return $this->_getReadAdapter()->fetchOne($select); } + + /** + * Load rewrite information for request + * If $path is array - we must load all possible records and choose one matching earlier record in array + * + * @param Mage_Core_Model_Url_Rewrite $object + * @param array|string $path + * @return Mage_Core_Model_Mysql4_Url_Rewrite + */ + public function loadByRequestPath(Mage_Core_Model_Url_Rewrite $object, $path) + { + if (!is_array($path)) { + $path = array($path); + } + + // Form select + $read = $this->_getReadAdapter(); + $select = $read->select() + ->from($this->getMainTable()) + ->where($this->getMainTable() . '.request_path IN (?)', $path) + ->where('store_id IN(?)', array(0, $object->getStoreId())); + + $items = $read->fetchAll($select); + + // Go through all found records and choose one with lowest penalty - earlier path in array, concrete store + $mapPenalty = array_flip(array_values($path)); // we got mapping array(path => index), lower index - better + $currentPenalty = null; + $foundItem = null; + foreach ($items as $item) { + $penalty = $mapPenalty[$item['request_path']] << 1 + ($item['store_id'] ? 0 : 1); + if (!$foundItem || $currentPenalty > $penalty) { + $foundItem = $item; + $currentPenalty = $penalty; + if (!$currentPenalty) { + break; // Found best matching item with zero penalty, no reason to continue + } + } + } + + // Set data and finish loading + if ($foundItem) { + $object->setData($foundItem); + } + + // Finish + $this->unserializeFields($object); + $this->_afterLoad($object); + + return $this; + } + } diff --git a/app/code/core/Mage/Core/Model/Session/Abstract.php b/app/code/core/Mage/Core/Model/Session/Abstract.php index b15dd199dc..6693a7e865 100644 --- a/app/code/core/Mage/Core/Model/Session/Abstract.php +++ b/app/code/core/Mage/Core/Model/Session/Abstract.php @@ -213,6 +213,7 @@ public function getMessages($clear=false) if ($clear) { $messages = clone $this->getData('messages'); $this->getData('messages')->clear(); + Mage::dispatchEvent('core_session_abstract_clear_messages'); return $messages; } return $this->getData('messages'); @@ -248,6 +249,7 @@ public function addException(Exception $exception, $alternativeText) public function addMessage(Mage_Core_Model_Message_Abstract $message) { $this->getMessages()->add($message); + Mage::dispatchEvent('core_session_abstract_add_message'); return $this; } @@ -325,7 +327,7 @@ public function setSessionId($id=null) { if (is_null($id) && $this->useSid()) { $_queryParam = $this->getSessionIdQueryParam(); - if (isset($_GET[$_queryParam])) { + if (isset($_GET[$_queryParam]) && Mage::getSingleton('core/url')->isOwnOriginUrl()) { $id = $_GET[$_queryParam]; /** * No reason use crypt key for session diff --git a/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php b/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php index 5deff72e6e..9fa671bd6a 100644 --- a/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php +++ b/app/code/core/Mage/Core/Model/Session/Abstract/Varien.php @@ -60,8 +60,8 @@ public function start($sessionName=null) ini_set('session.save_handler', 'eaccelerator'); break; default: - session_module_name('files'); - if (is_writable(Mage::getBaseDir('session'))) { + session_module_name($this->getSessionSaveMethod()); + if (is_writable($this->getSessionSavePath())) { session_save_path($this->getSessionSavePath()); } break; @@ -113,10 +113,13 @@ public function start($sessionName=null) } session_start(); + /** - * Renew cookie expiration time - */ - $cookie->renew(session_name()); + * Renew cookie expiration time if session id did not change + */ + if ($cookie->get(session_name()) == $this->getSessionId()) { + $cookie->renew(session_name()); + } Varien_Profiler::stop(__METHOD__.'/start'); return $this; diff --git a/app/code/core/Mage/Core/Model/Session/Abstract/Zend.php b/app/code/core/Mage/Core/Model/Session/Abstract/Zend.php index 31e25ddd40..5ff15725b1 100644 --- a/app/code/core/Mage/Core/Model/Session/Abstract/Zend.php +++ b/app/code/core/Mage/Core/Model/Session/Abstract/Zend.php @@ -51,6 +51,7 @@ public function start() $options = array( 'save_path'=>Mage::getBaseDir('session'), 'use_only_cookies'=>'off', + 'throw_startup_exceptions' => E_ALL ^ E_NOTICE, ); if ($this->getCookieDomain()) { $options['cookie_domain'] = $this->getCookieDomain(); diff --git a/app/code/core/Mage/Core/Model/Store.php b/app/code/core/Mage/Core/Model/Store.php index ef0f99ffc3..e49f41a172 100644 --- a/app/code/core/Mage/Core/Model/Store.php +++ b/app/code/core/Mage/Core/Model/Store.php @@ -59,6 +59,8 @@ class Mage_Core_Model_Store extends Mage_Core_Model_Abstract const CACHE_TAG = 'store'; + const COOKIE_NAME = 'store'; + protected $_cacheTag = true; /** @@ -465,12 +467,22 @@ protected function _updatePathUseRewrites($url) */ protected function _updatePathUseStoreView($url) { - if (Mage::isInstalled() && $this->getConfig(self::XML_PATH_STORE_IN_URL)) { - $url .= $this->getCode().'/'; + if ($this->getStoreInUrl()) { + $url .= $this->getCode() . '/'; } return $url; } + /** + * Returns whether url forming scheme prepends url path with store view code + * + * @return bool + */ + public function getStoreInUrl() + { + return Mage::isInstalled() && $this->getConfig(self::XML_PATH_STORE_IN_URL); + } + /** * Get store identifier * @@ -848,33 +860,41 @@ public function isCanDelete() */ public function getCurrentUrl($fromStore = true) { - $query = Mage::getSingleton('core/url')->escape(ltrim(Mage::app()->getRequest()->getRequestString(), '/')); + $sidQueryParam = $this->_getSession()->getSessionIdQueryParam(); + $requestString = Mage::getSingleton('core/url')->escape(ltrim(Mage::app()->getRequest()->getRequestString(), '/')); - if (Mage::app()->getStore()->isCurrentlySecure()) { - $parsedUrl = parse_url($this->getUrl('', array('_secure' => true))); - } else { - $parsedUrl = parse_url($this->getUrl('')); + $storeUrl = Mage::app()->getStore()->isCurrentlySecure() + ? $this->getUrl('', array('_secure' => true)) + : $this->getUrl(''); + $storeParsedUrl = parse_url($storeUrl); + + $storeParsedQuery = array(); + if (isset($storeParsedUrl['query'])) { + parse_str($storeParsedUrl['query'], $storeParsedQuery); } - $parsedQuery = array(); - if (isset($parsedUrl['query'])) { - parse_str($parsedUrl['query'], $parsedQuery); + + $currQuery = Mage::app()->getRequest()->getQuery(); + if (isset($currQuery[$sidQueryParam]) && !empty($currQuery[$sidQueryParam]) + && $this->_getSession()->getSessionIdForHost($storeUrl) != $currQuery[$sidQueryParam] + ) { + unset($currQuery[$sidQueryParam]); } - foreach (Mage::app()->getRequest()->getQuery() as $k => $v) { - $parsedQuery[$k] = $v; + foreach ($currQuery as $k => $v) { + $storeParsedQuery[$k] = $v; } if (!Mage::getStoreConfigFlag(Mage_Core_Model_Store::XML_PATH_STORE_IN_URL, $this->getCode())) { - $parsedQuery['___store'] = $this->getCode(); + $storeParsedQuery['___store'] = $this->getCode(); } if ($fromStore !== false) { - $parsedQuery['___from_store'] = $fromStore === true ? Mage::app()->getStore()->getCode() : $fromStore; + $storeParsedQuery['___from_store'] = $fromStore === true ? Mage::app()->getStore()->getCode() : $fromStore; } - return $parsedUrl['scheme'] . '://' . $parsedUrl['host'] - . (isset($parsedUrl['port']) ? ':' . $parsedUrl['port'] : '') - . $parsedUrl['path'] . $query - . ($parsedQuery ? '?'.http_build_query($parsedQuery, '', '&') : ''); + return $storeParsedUrl['scheme'] . '://' . $storeParsedUrl['host'] + . (isset($storeParsedUrl['port']) ? ':' . $storeParsedUrl['port'] : '') + . $storeParsedUrl['path'] . $requestString + . ($storeParsedQuery ? '?'.http_build_query($storeParsedQuery, '', '&') : ''); } public function getIsActive() diff --git a/app/code/core/Mage/Core/Model/Template.php b/app/code/core/Mage/Core/Model/Template.php new file mode 100644 index 0000000000..27f55b25ae --- /dev/null +++ b/app/code/core/Mage/Core/Model/Template.php @@ -0,0 +1,196 @@ + + */ +abstract class Mage_Core_Model_Template extends Mage_Core_Model_Abstract +{ + /** + * Types of template + */ + const TYPE_TEXT = 1; + const TYPE_HTML = 2; + + /** + * Default design area for emulation + */ + const DEFAULT_DESIGN_AREA = 'frontend'; + + /** + * Configuration of desing package for template + * + * @var Varien_Object + */ + protected $_designConfig; + + + /** + * Configuration of emulated desing package. + * + * @var Varien_Object|boolean + */ + protected $_emulatedDesignConfig = false; + + /** + * Applying of design config + * + * @return Mage_Core_Model_Template + */ + protected function _applyDesignConfig() + { + $design = Mage::getDesign(); + $designConfig = $this->getDesignConfig() + ->setOldArea($design->getArea()) + ->setOldStore(is_object($design->getStore()) ? $design->getStore()->getId() : $design->getStore()); + + if ($designConfig->hasArea()) { + $design->setArea($designConfig->getArea()); + } + + if ($designConfig->hasStore()) { + $store = $designConfig->getStore(); + Mage::app()->setCurrentStore($store); + $locale = new Zend_Locale(Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $store)); + Mage::app()->getLocale()->setLocale($locale)->setLocaleCode($locale->toString()); + if ($designConfig->hasArea()) { + Mage::getSingleton('core/translate')->setLocale($locale)->init($designConfig->getArea(), true); + } + $design->setStore($store); + $design->setTheme(''); + $design->setPackageName(''); + } + + return $this; + } + + /** + * Revert design settings to previous + * + * @return Mage_Core_Model_Template + */ + protected function _cancelDesignConfig() + { + if ($this->getDesignConfig()) { + if ($this->getDesignConfig()->getOldArea()) { + Mage::getDesign()->setArea($this->getDesignConfig()->getOldArea()); + } + + if ($this->getDesignConfig()->getOldStore()) { + Mage::getDesign()->setStore($this->getDesignConfig()->getOldStore()); + Mage::getDesign()->setTheme(''); + Mage::getDesign()->setPackageName(''); + } + } + Mage::app()->getLocale()->revert(); + return $this; + } + + /** + * Get design configuration data + * + * @return Varien_Object + */ + protected function getDesignConfig() + { + if(is_null($this->_designConfig)) { + $store = Mage::getDesign()->getStore(); + $storeId = is_object($store) ? $store->getId() : $store; + $this->_designConfig = new Varien_Object(array( + 'area' => Mage::getDesign()->getArea(), + 'store' => $storeId + )); + } + return $this->_designConfig; + } + + /** + * Initialize design information for template processing + * + * @param array $config + * @return Mage_Core_Model_Template + */ + public function setDesignConfig(array $config) + { + $this->getDesignConfig()->setData($config); + return $this; + } + + /** + * Save current design config and replace with design config from specified store + * Event is not dispatched. + * + * @param int|string $storeId + */ + public function emulateDesign($storeId, $area=self::DEFAULT_DESIGN_AREA) + { + if ($storeId) { + // save current design settings + $this->_emulatedDesignConfig = clone $this->getDesignConfig(); + if ($this->getDesignConfig()->getStore() != $storeId) { + $this->setDesignConfig(array('area' => $area, 'store' => $storeId)); + $this->_applyDesignConfig(); + } + } else { + $this->_emulatedDesignConfig = false; + } + } + + /** + * Revert to last design config, used before emulation + * + */ + public function revertDesign() + { + if ($this->_emulatedDesignConfig) + { + $this->setDesignConfig($this->_emulatedDesignConfig->getData()); + $this->_applyDesignConfig(); + } + } + + /** + * Return true if template type eq text + * + * @return boolean + */ + public function isPlain() + { + return $this->getType() == self::TYPE_TEXT; + } + + /** + * Getter for template type + * + * @return int|string + */ + abstract public function getType(); +} diff --git a/app/code/core/Mage/Core/Model/Url.php b/app/code/core/Mage/Core/Model/Url.php index 5ae085f86f..032d44382a 100644 --- a/app/code/core/Mage/Core/Model/Url.php +++ b/app/code/core/Mage/Core/Model/Url.php @@ -876,7 +876,7 @@ protected function _prepareSessionUrl($url) } $session = Mage::getSingleton('core/session'); /* @var $session Mage_Core_Model_Session */ - if (Mage::app()->getUseSessionVar()) { + if (Mage::app()->getUseSessionVar() && !$session->getSessionIdForHost($url)) { // secure URL if ($this->getSecure()) { $this->setQueryParam('___SID', 'S'); @@ -986,4 +986,23 @@ public function sessionVarCallback($match) } return ''; } + + /** + * Check if users originated URL is one of the domain URLs assigned to stores + * + * @return boolean + */ + public function isOwnOriginUrl() + { + $storeDomains = array(); + $referer = parse_url(Mage::app()->getFrontController()->getRequest()->getServer('HTTP_REFERER'), PHP_URL_HOST); + foreach (Mage::app()->getStores() as $store) { + $storeDomains[] = parse_url($store->getBaseUrl(), PHP_URL_HOST); + } + $storeDomains = array_unique($storeDomains); + if (empty($referer) || in_array($referer, $storeDomains)) { + return true; + } + return false; + } } diff --git a/app/code/core/Mage/Core/Model/Url/Rewrite.php b/app/code/core/Mage/Core/Model/Url/Rewrite.php index 03622576cc..9a9a6dfb2d 100644 --- a/app/code/core/Mage/Core/Model/Url/Rewrite.php +++ b/app/code/core/Mage/Core/Model/Url/Rewrite.php @@ -70,8 +70,7 @@ protected function _afterSave() /** * Load rewrite information for request - * - * if $path is array - that mean what we need try load for each item + * If $path is array - we must load possible records and choose one matching earlier record in array * * @param mixed $path * @return Mage_Core_Model_Url_Rewrite @@ -79,18 +78,10 @@ protected function _afterSave() public function loadByRequestPath($path) { $this->setId(null); - - if (is_array($path)) { - foreach ($path as $pathInfo) { - $this->load($pathInfo, 'request_path'); - if ($this->getId()) { - return $this; - } - } - } - else { - $this->load($path, 'request_path'); - } + $this->_getResource()->loadByRequestPath($this, $path); + $this->_afterLoad(); + $this->setOrigData(); + $this->_hasDataChanges = false; return $this; } @@ -197,20 +188,24 @@ public function rewrite(Zend_Controller_Request_Http $request=null, Zend_Control $this->setStoreId(Mage::app()->getStore()->getId()); } - $requestCases = array(); - $requestPath = trim($request->getPathInfo(), '/'); - /** - * We need try to find rewrites information for both cases - * More priority has url with query params + * We have two cases of incoming paths - with and without slashes at the end ("/somepath/" and "/somepath"). + * Each of them matches two url rewrite request paths - with and without slashes at the end ("/somepath/" and "/somepath"). + * Choose any matched rewrite, but in priority order that depends on same presence of slash and query params. */ - if ($queryString = $this->_getQueryString()) { - $requestCases[] = $requestPath .'?'.$queryString; - $requestCases[] = $requestPath; - } - else { - $requestCases[] = $requestPath; + $requestCases = array(); + $pathInfo = $request->getPathInfo(); + $origSlash = (substr($pathInfo, -1) == '/') ? '/' : ''; + $requestPath = trim($pathInfo, '/'); + + $altSlash = $origSlash ? '' : '/'; // If there were final slash - add nothing to less priority paths. And vice versa. + $queryString = $this->_getQueryString(); // Query params in request, matching "path + query" has more priority + if ($queryString) { + $requestCases[] = $requestPath . $origSlash . '?' . $queryString; + $requestCases[] = $requestPath . $altSlash . '?' . $queryString; } + $requestCases[] = $requestPath . $origSlash; + $requestCases[] = $requestPath . $altSlash; $this->loadByRequestPath($requestCases); @@ -265,7 +260,8 @@ public function rewrite(Zend_Controller_Request_Http $request=null, Zend_Control $targetUrl = $request->getBaseUrl(). '/' . $storeCode . '/' .$this->getTargetPath(); } - if ($queryString = $this->_getQueryString()) { + $queryString = $this->_getQueryString(); + if ($queryString) { $targetUrl .= '?'.$queryString; } diff --git a/app/code/core/Mage/Core/etc/config.xml b/app/code/core/Mage/Core/etc/config.xml index 6c0b842828..9bd36c6277 100644 --- a/app/code/core/Mage/Core/etc/config.xml +++ b/app/code/core/Mage/Core/etc/config.xml @@ -28,7 +28,7 @@ - 0.8.26 + 0.8.27 diff --git a/app/code/core/Mage/Core/etc/system.xml b/app/code/core/Mage/Core/etc/system.xml index 4e28a1ba35..9bf0bf0ddc 100644 --- a/app/code/core/Mage/Core/etc/system.xml +++ b/app/code/core/Mage/Core/etc/system.xml @@ -956,6 +956,24 @@ + + + 40 + 1 + 0 + 0 + + + + select + adminhtml/system_config_source_yesno + 1 + 1 + 0 + 0 + + + @@ -986,13 +1004,14 @@ 0 - + select - adminhtml/system_config_source_yesno + adminhtml/system_config_source_web_redirect 20 1 0 0 + I.e. redirect from http://example.com/store/ to http://www.example.com/store/ @@ -1129,6 +1148,7 @@ select adminhtml/system_config_source_yesno + adminhtml/system_config_backend_secure 60 1 1 @@ -1138,6 +1158,7 @@ select adminhtml/system_config_source_yesno + adminhtml/system_config_backend_secure 65 1 0 diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Recurring/Profile/Info.php b/app/code/core/Mage/Core/sql/core_setup/mysql4-upgrade-0.8.26-0.8.27.php similarity index 82% rename from app/code/core/Mage/Sales/Model/Mysql4/Recurring/Profile/Info.php rename to app/code/core/Mage/Core/sql/core_setup/mysql4-upgrade-0.8.26-0.8.27.php index b0b0fdcc70..9e8d381c8e 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Recurring/Profile/Info.php +++ b/app/code/core/Mage/Core/sql/core_setup/mysql4-upgrade-0.8.26-0.8.27.php @@ -19,15 +19,11 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category Mage - * @package Mage_Sales + * @package Mage_Core * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ -/** - * Sales Recurring Profile Gataway Info Model - * - */ -class Mage_Sales_Model_Recurring_Profile_Info extends Mage_Payment_Model_Recurring_Profile -{ -} +/* @var $installer Mage_Core_Model_Resource_Setup */ +$installer = $this; +$installer->getConnection()->dropForeignKey($installer->getTable('core/cache_tag'), 'FK_CORE_CACHE_TAG'); diff --git a/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php b/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php index 8d0637f318..2e57743f87 100644 --- a/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php +++ b/app/code/core/Mage/Customer/Block/Address/Renderer/Default.php @@ -78,36 +78,56 @@ public function getFormat(Mage_Customer_Model_Address_Abstract $address=null) */ public function render(Mage_Customer_Model_Address_Abstract $address, $format=null) { - $address->getRegion(); - $address->getCountry(); - $address->explodeStreetAddress(); + switch ($this->getType()->getCode()) { + case 'html': + $dataFormat = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_HTML; + break; + case 'pdf': + $dataFormat = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_PDF; + break; + case 'oneline': + $dataFormat = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_ONELINE; + break; + default: + $dataFormat = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT; + break; + } - $formater = new Varien_Filter_Template(); - $data = $address->getData(); - if ($this->getType()->getHtmlEscape()) { - foreach ($data as $key => $value) { - if (is_object($value)) { - unset($data[$key]); - } else { - $data[$key] = $this->htmlEscape($value); + $formater = new Varien_Filter_Template(); + $attributes = Mage::helper('customer/address')->getAttributes(); + + $data = array(); + foreach ($attributes as $attribute) { + /* @var $attribute Mage_Customer_Model_Attribute */ + if (!$attribute->getIsVisible()) { + continue; + } + if ($attribute->getAttributeCode() == 'country_id') { + $data['country'] = $address->getCountryModel()->getName(); + } else if ($attribute->getAttributeCode() == 'region') { + $data['region'] = $address->getRegion(); + } else { + $dataModel = Mage_Customer_Model_Attribute_Data::factory($attribute, $address); + $value = $dataModel->outputValue($dataFormat); + if ($attribute->getFrontendInput() == 'multiline') { + $values = $dataModel->outputValue(Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_ARRAY); + // explode lines + foreach ($values as $k => $v) { + $key = sprintf('%s%d', $attribute->getAttributeCode(), $k + 1); + $data[$key] = $v; + } } + $data[$attribute->getAttributeCode()] = $value; } } - /** - * Remove data that mustn't show - */ - if (!$this->helper('customer/address')->canShowConfig('prefix_show')) { - unset($data['prefix']); - } - if (!$this->helper('customer/address')->canShowConfig('middlename_show')) { - unset($data['middlename']); - } - if (!$this->helper('customer/address')->canShowConfig('suffix_show')) { - unset($data['suffix']); + if ($this->getType()->getHtmlEscape()) { + foreach ($data as $key => $value) { + $data[$key] = $this->htmlEscape($value); + } } - $formater->setVariables(array_merge($data, array('country'=>$address->getCountryModel()->getName()))); + $formater->setVariables($data); $format = !is_null($format) ? $format : $this->getFormat($address); diff --git a/app/code/core/Mage/Customer/Block/Form/Register.php b/app/code/core/Mage/Customer/Block/Form/Register.php index b57bdb262a..f6948b08ed 100644 --- a/app/code/core/Mage/Customer/Block/Form/Register.php +++ b/app/code/core/Mage/Customer/Block/Form/Register.php @@ -31,6 +31,13 @@ */ class Mage_Customer_Block_Form_Register extends Mage_Directory_Block_Data { + /** + * Address instance with data + * + * @var Mage_Customer_Model_Address + */ + protected $_address; + protected function _prepareLayout() { $this->getLayout()->getBlock('head')->setTitle(Mage::helper('customer')->__('Create New Customer Account')); @@ -70,7 +77,13 @@ public function getFormData() { $data = $this->getData('form_data'); if (is_null($data)) { - $data = new Varien_Object(Mage::getSingleton('customer/session')->getCustomerFormData(true)); + $formData = Mage::getSingleton('customer/session')->getCustomerFormData(true); + $data = new Varien_Object(); + if ($formData) { + $data->addData($formData); + $data->setCustomerData(1); + } + $this->setData('form_data', $data); } return $data; @@ -83,7 +96,8 @@ public function getFormData() */ public function getCountryId() { - if ($countryId = $this->getFormData()->getCountryId()) { + $countryId = $this->getFormData()->getCountryId(); + if ($countryId) { return $countryId; } return parent::getCountryId(); @@ -96,10 +110,9 @@ public function getCountryId() */ public function getRegion() { - if ($region = $this->getFormData()->getRegion()) { + if (false !== ($region = $this->getFormData()->getRegion())) { return $region; - } - elseif ($region = $this->getFormData()->getRegionId()) { + } else if (false !== ($region = $this->getFormData()->getRegionId())) { return $region; } return null; @@ -108,10 +121,42 @@ public function getRegion() /** * Newsletter module availability * - * @return boolean + * @return boolean */ public function isNewsletterEnabled() { return !Mage::getStoreConfigFlag('advanced/modules_disable_output/Mage_Newsletter'); } + + /** + * Return customer address instance + * + * @return Mage_Customer_Model_Address + */ + public function getAddress() + { + if (is_null($this->_address)) { + $this->_address = Mage::getModel('customer/address'); + } + + return $this->_address; + } + + /** + * Restore entity data from session + * Entity and form code must be defined for the form + * + * @param Mage_Customer_Model_Form $form + * @return Mage_Customer_Block_Form_Register + */ + public function restoreSessionData(Mage_Customer_Model_Form $form, $scope = null) + { + if ($this->getFormData()->getCustomerData()) { + $request = $form->prepareRequest($this->getFormData()->getData()); + $data = $form->extractData($request, $scope, false); + $form->restoreData($data); + } + + return $this; + } } diff --git a/app/code/core/Mage/Customer/Block/Widget/Abstract.php b/app/code/core/Mage/Customer/Block/Widget/Abstract.php index 7274d62d3c..44f95cd2d3 100644 --- a/app/code/core/Mage/Customer/Block/Widget/Abstract.php +++ b/app/code/core/Mage/Customer/Block/Widget/Abstract.php @@ -56,4 +56,15 @@ public function getFieldName($field) { return sprintf($this->getFieldNameFormat(), $field); } + + /** + * Retrieve customer attribute instance + * + * @param string $attributeCode + * @return Mage_Customer_Model_Attribute + */ + protected function _getAttribute($attributeCode) + { + return Mage::getSingleton('eav/config')->getAttribute('customer', $attributeCode); + } } diff --git a/app/code/core/Mage/Customer/Block/Widget/Dob.php b/app/code/core/Mage/Customer/Block/Widget/Dob.php index 5523293849..0f2d90919c 100644 --- a/app/code/core/Mage/Customer/Block/Widget/Dob.php +++ b/app/code/core/Mage/Customer/Block/Widget/Dob.php @@ -43,12 +43,12 @@ public function _construct() public function isEnabled() { - return (bool)$this->getConfig('dob_show'); + return (bool)$this->_getAttribute('dob')->getIsVisible(); } public function isRequired() { - return $this->getConfig('dob_show')=='req'; + return (bool)$this->_getAttribute('dob')->getIsRequired(); } public function setDate($date) diff --git a/app/code/core/Mage/Customer/Block/Widget/Gender.php b/app/code/core/Mage/Customer/Block/Widget/Gender.php index f96d2f61cd..16c5967ba7 100644 --- a/app/code/core/Mage/Customer/Block/Widget/Gender.php +++ b/app/code/core/Mage/Customer/Block/Widget/Gender.php @@ -49,7 +49,7 @@ public function _construct() */ public function isEnabled() { - return (bool)$this->getConfig('gender_show'); + return (bool)$this->_getAttribute('gender')->getIsVisible(); } /** @@ -59,7 +59,7 @@ public function isEnabled() */ public function isRequired() { - return 'req' == $this->getConfig('gender_show'); + return (bool)$this->_getAttribute('gender')->getIsRequired(); } /** diff --git a/app/code/core/Mage/Customer/Block/Widget/Name.php b/app/code/core/Mage/Customer/Block/Widget/Name.php index b52edd490c..cb22b74a78 100644 --- a/app/code/core/Mage/Customer/Block/Widget/Name.php +++ b/app/code/core/Mage/Customer/Block/Widget/Name.php @@ -56,12 +56,12 @@ protected function _showConfig($key) */ public function showPrefix() { - return $this->_showConfig('prefix_show'); + return (bool)$this->_getAttribute('prefix')->getIsVisible(); } public function isPrefixRequired() { - return $this->getConfig('prefix_show')=='req'; + return (bool)$this->_getAttribute('prefix')->getIsRequired(); } public function getPrefixOptions() @@ -79,17 +79,17 @@ public function getPrefixOptions() public function showMiddlename() { - return $this->_showConfig('middlename_show'); + return (bool)$this->_getAttribute('middlename')->getIsVisible(); } public function showSuffix() { - return $this->_showConfig('suffix_show'); + return (bool)$this->_getAttribute('suffix')->getIsVisible(); } public function isSuffixRequired() { - return $this->getConfig('suffix_show') == 'req'; + return (bool)$this->_getAttribute('suffix')->getIsRequired(); } public function getSuffixOptions() @@ -121,4 +121,18 @@ public function getContainerClassName() $class .= $this->showSuffix() ? '-suffix' : ''; return $class; } + + /** + * Retrieve customer attribute instance + * + * @param string $attributeCode + * @return Mage_Customer_Model_Attribute + */ + protected function _getAttribute($attributeCode) + { + if (!($this->getObject() instanceof Mage_Customer_Model_Customer)) { + return Mage::getSingleton('eav/config')->getAttribute('customer_address', $attributeCode); + } + return parent::_getAttribute($attributeCode); + } } diff --git a/app/code/core/Mage/Customer/Block/Widget/Taxvat.php b/app/code/core/Mage/Customer/Block/Widget/Taxvat.php index 3599848003..caef4fdb96 100644 --- a/app/code/core/Mage/Customer/Block/Widget/Taxvat.php +++ b/app/code/core/Mage/Customer/Block/Widget/Taxvat.php @@ -34,12 +34,12 @@ public function _construct() public function isEnabled() { - return (bool)$this->getConfig('taxvat_show'); + return (bool)$this->_getAttribute('taxvat')->getIsVisible(); } public function isRequired() { - return 'req' == $this->getConfig('taxvat_show'); + return (bool)$this->_getAttribute('taxvat')->getIsRequired(); } public function getCustomer() diff --git a/app/code/core/Mage/Customer/Helper/Address.php b/app/code/core/Mage/Customer/Helper/Address.php index 2b8f52e31a..cb719b25ea 100644 --- a/app/code/core/Mage/Customer/Helper/Address.php +++ b/app/code/core/Mage/Customer/Helper/Address.php @@ -31,9 +31,27 @@ */ class Mage_Customer_Helper_Address extends Mage_Core_Helper_Abstract { - protected $_config; - protected $_streetLines; - protected $_formatTemplate = array(); + /** + * Array of Customer Address Attributes + * + * @var array + */ + protected $_attributes; + + /** + * Customer address config node per website + * + * @var array + */ + protected $_config = array(); + + /** + * Customer Number of Lines in a Street Address per website + * + * @var array + */ + protected $_streetLines = array(); + protected $_formatTemplate = array(); /** * Addresses url @@ -67,21 +85,39 @@ public function getRenderer($renderer) } } - public function getConfig($key, $store=null) + /** + * Return customer address config value by key and store + * + * @param string $key + * @param Mage_Core_Model_Store|int|string $store + * @return string|null + */ + public function getConfig($key, $store = null) { - if (is_null($this->_config)) { - $this->_config = Mage::getStoreConfig('customer/address'); + $websiteId = Mage::app()->getStore($store)->getWebsiteId(); + + if (!isset($this->_config[$websiteId])) { + $this->_config[$websiteId] = Mage::getStoreConfig('customer/address', $store); } - return isset($this->_config[$key]) ? $this->_config[$key] : null; + return isset($this->_config[$websiteId][$key]) ? (string)$this->_config[$websiteId][$key] : null; } - public function getStreetLines($store=null) + /** + * Return Number of Lines in a Street Address for store + * + * @param Mage_Core_Model_Store|int|string $store + * @return int + */ + public function getStreetLines($store = null) { - if (is_null($this->_streetLines)) { - $lines = $this->getConfig('street_lines', $store); - $this->_streetLines = min(4, max(1, (int)$lines)); + $websiteId = Mage::app()->getStore($store)->getWebsiteId(); + if (!isset($this->_streetLines[$websiteId])) { + $attribute = Mage::getSingleton('eav/config')->getAttribute('customer_address', 'street'); + $lines = $attribute->getMultilineCount(); + $this->_streetLines[$websiteId] = min(4, max(1, (int)$lines)); } - return $this->_streetLines; + + return $this->_streetLines[$websiteId]; } public function getFormat($code) @@ -103,4 +139,22 @@ public function canShowConfig($key) } return true; } + + /** + * Return array of Customer Address Attributes + * + * @return array + */ + public function getAttributes() + { + if (is_null($this->_attributes)) { + $this->_attributes = array(); + /* @var $config Mage_Eav_Model_Config */ + $config = Mage::getSingleton('eav/config'); + foreach ($config->getEntityAttributeCodes('customer_address') as $attributeCode) { + $this->_attributes[$attributeCode] = $config->getAttribute('customer_address', $attributeCode); + } + } + return $this->_attributes; + } } diff --git a/app/code/core/Mage/Customer/Model/Address.php b/app/code/core/Mage/Customer/Model/Address.php index de208366fe..b8ecb283b3 100644 --- a/app/code/core/Mage/Customer/Model/Address.php +++ b/app/code/core/Mage/Customer/Model/Address.php @@ -125,4 +125,29 @@ public function __clone() { $this->setId(null); } + + /** + * Return Entity Type instance + * + * @return Mage_Eav_Model_Entity_Type + */ + public function getEntityType() + { + return $this->_getResource()->getEntityType(); + } + + /** + * Return Entity Type ID + * + * @return int + */ + public function getEntityTypeId() + { + $entityTypeId = $this->getData('entity_type_id'); + if (!$entityTypeId) { + $entityTypeId = $this->getEntityType()->getId(); + $this->setData('entity_type_id', $entityTypeId); + } + return $entityTypeId; + } } diff --git a/app/code/core/Mage/Customer/Model/Address/Abstract.php b/app/code/core/Mage/Customer/Model/Address/Abstract.php index e6c822dfdc..2cb39a9f77 100644 --- a/app/code/core/Mage/Customer/Model/Address/Abstract.php +++ b/app/code/core/Mage/Customer/Model/Address/Abstract.php @@ -55,16 +55,16 @@ class Mage_Customer_Model_Address_Abstract extends Mage_Core_Model_Abstract public function getName() { $name = ''; - $helper = Mage::helper('customer/address'); - if ($helper->canShowConfig('prefix_show') && $this->getPrefix()) { + $config = Mage::getSingleton('eav/config'); + if ($config->getAttribute('customer_address', 'prefix')->getIsVisible() && $this->getPrefix()) { $name .= $this->getPrefix() . ' '; } $name .= $this->getFirstname(); - if ($helper->canShowConfig('middlename_show') && $this->getMiddlename()) { + if ($config->getAttribute('customer_address', 'middlename')->getIsVisible() && $this->getMiddlename()) { $name .= ' ' . $this->getMiddlename(); } $name .= ' ' . $this->getLastname(); - if ($helper->canShowConfig('suffix_show')&& $this->getSuffix()) { + if ($config->getAttribute('customer_address', 'suffix')->getIsVisible() && $this->getSuffix()) { $name .= ' ' . $this->getSuffix(); } return $name; @@ -302,6 +302,7 @@ public function format($type) || !$formatType->getRenderer()) { return null; } + Mage::dispatchEvent('customer_address_format', array('type' => $formatType, 'address' => $this)); return $formatType->getRenderer()->render($this); } diff --git a/app/code/core/Mage/Customer/Model/Address/Config.php b/app/code/core/Mage/Customer/Model/Address/Config.php index 38d62fabde..5d4db7c993 100644 --- a/app/code/core/Mage/Customer/Model/Address/Config.php +++ b/app/code/core/Mage/Customer/Model/Address/Config.php @@ -30,30 +30,81 @@ * * @category Mage * @package Mage_Customer - * @author Magento Core Team + * @author Magento Core Team */ class Mage_Customer_Model_Address_Config extends Mage_Core_Model_Config_Base { - const DEFAULT_ADDRESS_RENDERER = 'customer/address_renderer_default'; - const DEFAULT_ADDRESS_FORMAT = 'oneline'; + const DEFAULT_ADDRESS_RENDERER = 'customer/address_renderer_default'; + const XML_PATH_ADDRESS_TEMPLATE = 'customer/address_templates/'; + const DEFAULT_ADDRESS_FORMAT = 'oneline'; - protected $_types; - protected $_defaultType; + /** + * Customer Address Templates per store + * + * @var array + */ + protected $_types = array(); + /** + * Current store instance + * + * @var Mage_Core_Model_Store + */ + protected $_store = null; + + /** + * Default types per store + * Using for invalid code + * + * @var array + */ + protected $_defaultTypes = array(); + + public function setStore($store) + { + $this->_store = Mage::app()->getStore($store); + return $this; + } + + /** + * Retrieve store + * + * @return Mage_Core_Model_Store + */ + public function getStore() + { + if (is_null($this->_store)) { + $this->_store = Mage::app()->getStore(); + } + return $this->_store; + } + + /** + * Define node + * + */ public function __construct() { parent::__construct(Mage::getConfig()->getNode()->global->customer->address); } + /** + * Retrieve address formats + * + * @return array + */ public function getFormats() { - if(is_null($this->_types)) { - $this->_types = array(); - foreach($this->getNode('formats')->children() as $typeCode=>$typeConfig) { + $store = $this->getStore(); + $storeId = $store->getId(); + if (!isset($this->_types[$storeId])) { + $this->_types[$storeId] = array(); + foreach ($this->getNode('formats')->children() as $typeCode => $typeConfig) { + $path = sprintf('%s%s', self::XML_PATH_ADDRESS_TEMPLATE, $typeCode); $type = new Varien_Object(); $type->setCode($typeCode) ->setTitle((string)$typeConfig->title) - ->setDefaultFormat((string)$typeConfig->defaultFormat) + ->setDefaultFormat(Mage::getStoreConfig($path, $store)) ->setHtmlEscape((bool)$typeConfig->htmlEscape); $renderer = (string)$typeConfig->renderer; @@ -62,32 +113,44 @@ public function getFormats() } $type->setRenderer( - Mage::helper('customer/address') - ->getRenderer($renderer)->setType($type) + Mage::helper('customer/address')->getRenderer($renderer)->setType($type) ); - $this->_types[] = $type; + $this->_types[$storeId][] = $type; } } - return $this->_types; + return $this->_types[$storeId]; } + /** + * Retrieve default address format + * + * @return Varien_Object + */ protected function _getDefaultFormat() { - if(is_null($this->_defaultType)) { - $this->_defaultType = new Varien_Object(); - $this->_defaultType->setCode('default') + $store = $this->getStore(); + $storeId = $store->getId(); + if(!isset($this->_defaultType[$storeId])) { + $this->_defaultType[$storeId] = new Varien_Object(); + $this->_defaultType[$storeId]->setCode('default') ->setDefaultFormat('{{depend prefix}}{{var prefix}} {{/depend}}{{var firstname}} {{depend middlename}}{{var middlename}} {{/depend}}{{var lastname}}{{depend suffix}} {{var suffix}}{{/depend}}, {{var street}}, {{var city}}, {{var region}} {{var postcode}}, {{var country}}'); - $this->_defaultType->setRenderer( + $this->_defaultType[$storeId]->setRenderer( Mage::helper('customer/address') - ->getRenderer(self::DEFAULT_ADDRESS_RENDERER)->setType($this->_defaultType) + ->getRenderer(self::DEFAULT_ADDRESS_RENDERER)->setType($this->_defaultType[$storeId]) ); } - return $this->_defaultType; + return $this->_defaultType[$storeId]; } + /** + * Retrieve address format by code + * + * @param string $typeCode + * @return Varien_Object + */ public function getFormatByCode($typeCode) { foreach($this->getFormats() as $type) { diff --git a/app/code/core/Mage/Customer/Model/Attribute.php b/app/code/core/Mage/Customer/Model/Attribute.php index ef09171cae..e7f63a8880 100644 --- a/app/code/core/Mage/Customer/Model/Attribute.php +++ b/app/code/core/Mage/Customer/Model/Attribute.php @@ -33,11 +33,61 @@ */ class Mage_Customer_Model_Attribute extends Mage_Eav_Model_Entity_Attribute { + /** + * Name of the module + */ const MODULE_NAME = 'Mage_Customer'; + /** + * Prefix of model events names + * + * @var string + */ protected $_eventPrefix = 'customer_entity_attribute'; + + /** + * Prefix of model events object + * + * @var string + */ protected $_eventObject = 'attribute'; + /** + * Active Website instance + * + * @var Mage_Core_Model_Website + */ + protected $_website; + + /** + * Set active website instance + * + * @param Mage_Core_Model_Website|int $website + * @return Mage_Customer_Model_Attribute + */ + public function setWebsite($website) + { + $this->_website = Mage::app()->getWebsite($website); + return $this; + } + + /** + * Return active website instance + * + * @return Mage_Core_Model_Website + */ + public function getWebsite() + { + if (is_null($this->_website)) { + $this->_website = Mage::app()->getWebsite(); + } + + return $this->_website; + } + + /** + * Init resource model + */ protected function _construct() { $this->_init('customer/attribute'); @@ -46,11 +96,115 @@ protected function _construct() /** * Processing object after save data * - * @return Mage_Core_Model_Abstract + * @return Mage_Customer_Model_Attribute */ protected function _afterSave() { Mage::getSingleton('eav/config')->clear(); return parent::_afterSave(); } + + /** + * Return forms in which the attribute + * + * @return array + */ + public function getUsedInForms() + { + $forms = $this->getData('used_in_forms'); + if (is_null($forms)) { + $forms = $this->_getResource()->getUsedInForms($this); + $this->setData('used_in_forms', $forms); + } + return $forms; + } + + /** + * Return validate rules + * + * @return array + */ + public function getValidateRules() + { + $rules = $this->getData('validate_rules'); + if (is_array($rules)) { + return $rules; + } else if (!empty($rules)) { + return unserialize($rules); + } + return array(); + } + + /** + * Set validate rules + * + * @param array|string $rules + * @return Mage_Customer_Model_Attribute + */ + public function setValidateRules($rules) + { + if (empty($rules)) { + $rules = null; + } else if (is_array($rules)) { + $rules = serialize($rules); + } + $this->setData('validate_rules', $rules); + + return $this; + } + + /** + * Return scope value by key + * + * @param string $key + * @return mixed + */ + protected function _getScopeValue($key) + { + $scopeKey = sprintf('scope_%s', $key); + if ($this->getData($scopeKey) !== null) { + return $this->getData($scopeKey); + } + return $this->getData($key); + } + + /** + * Return is attribute value required + * + * @return int + */ + public function getIsRequired() + { + return $this->_getScopeValue('is_required'); + } + + /** + * Return is visible attribute flag + * + * @return int + */ + public function getIsVisible() + { + return $this->_getScopeValue('is_visible'); + } + + /** + * Return default value for attribute + * + * @return int + */ + public function getDefaultValue() + { + return $this->_getScopeValue('default_value'); + } + + /** + * Return count of lines for multiply line attribute + * + * @return int + */ + public function getMultilineCount() + { + return $this->_getScopeValue('multiline_count'); + } } diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data.php b/app/code/core/Mage/Customer/Model/Attribute/Data.php new file mode 100644 index 0000000000..b4909a9599 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data.php @@ -0,0 +1,85 @@ + + */ +class Mage_Customer_Model_Attribute_Data +{ + const OUTPUT_FORMAT_JSON = 'json'; + const OUTPUT_FORMAT_TEXT = 'text'; + const OUTPUT_FORMAT_HTML = 'html'; + const OUTPUT_FORMAT_PDF = 'pdf'; + const OUTPUT_FORMAT_ONELINE = 'oneline'; + const OUTPUT_FORMAT_ARRAY = 'array'; // available only for multiply attributes + + /** + * Array of attribute data models by input type + * + * @var array + */ + protected static $_dataModels = array(); + + /** + * Return attribute data model by attribute + * Set entity to data model (need for work) + * + * @param Mage_Customer_Model_Attribute $attribute + * @param Mage_Core_Model_Abstract $entity + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public static function factory(Mage_Customer_Model_Attribute $attribute, Mage_Core_Model_Abstract $entity) + { + /* @var $dataModel Mage_Customer_Model_Attribute_Data_Abstract */ + $dataModelClass = $attribute->getDataModel(); + if (!empty($dataModelClass)) { + if (empty(self::$_dataModels[$dataModelClass])) { + $dataModel = Mage::getModel($dataModelClass); + self::$_dataModels[$dataModelClass] = $dataModel; + } else { + $dataModel = self::$_dataModels[$dataModelClass]; + } + } else { + if (empty(self::$_dataModels[$attribute->getFrontendInput()])) { + $dataModelClass = sprintf('customer/attribute_data_%s', $attribute->getFrontendInput()); + $dataModel = Mage::getModel($dataModelClass); + self::$_dataModels[$attribute->getFrontendInput()] = $dataModel; + } else { + $dataModel = self::$_dataModels[$attribute->getFrontendInput()]; + } + } + + $dataModel->setAttribute($attribute); + $dataModel->setEntity($entity); + + return $dataModel; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Abstract.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Abstract.php new file mode 100644 index 0000000000..ea147e57c3 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Abstract.php @@ -0,0 +1,513 @@ + + */ +abstract class Mage_Customer_Model_Attribute_Data_Abstract +{ + /** + * Attribute instance + * + * @var Mage_Customer_Model_Attribute + */ + protected $_attribite; + + /** + * Entity instance + * + * @var Mage_Core_Model_Abstract + */ + protected $_entity; + + /** + * Request Scope name + * + * @var string + */ + protected $_requestScope; + + protected $_requestScopeOnly = true; + + /** + * Is AJAX request flag + * + * @var boolean + */ + protected $_isAjax = false; + + /** + * Array of full extracted data + * Needed for depends attributes + * + * @var array + */ + protected $_extractedData = array(); + + /** + * Mage_Core_Model_Locale FORMAT + * + * @var string + */ + protected $_dateFilterFormat; + + /** + * Set attribute instance + * + * @param Mage_Eav_Model_Entity_Attribute_Abstract $attribute + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function setAttribute(Mage_Eav_Model_Entity_Attribute_Abstract $attribute) + { + $this->_attribite = $attribute; + return $this; + } + + /** + * Return Attribute instance + * + * @throws Mage_Core_Exception + * @return Mage_Customer_Model_Attribute + */ + public function getAttribute() + { + if (!$this->_attribite) { + Mage::throwException(Mage::helper('customer')->__('Attribute object is undefined')); + } + return $this->_attribite; + } + + /** + * Set Request scope + * + * @param string $scope + * @return string + */ + public function setRequestScope($scope) + { + $this->_requestScope = $scope; + return $this; + } + + /** + * Set scope visibility + * Search value only in scope or search value in scope and global + * + * @param boolean $flag + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function setRequestScopeOnly($flag) + { + $this->_requestScopeOnly = (bool)$flag; + return $this; + } + + /** + * Set entity instance + * + * @param Mage_Core_Model_Abstract $entity + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function setEntity(Mage_Core_Model_Abstract $entity) + { + $this->_entity = $entity; + return $this; + } + + /** + * Returns entity instance + * + * @return Mage_Core_Model_Abstract + */ + public function getEntity() + { + if (!$this->_entity) { + Mage::throwException(Mage::helper('customer')->__('Entity object is undefined')); + } + return $this->_entity; + } + + /** + * Set array of full extracted data + * + * @param array $data + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function setExtractedData(array $data) + { + $this->_extractedData = $data; + return $this; + } + + /** + * Return extracted data + * + * @param string $index + * @return mixed + */ + public function getExtractedData($index = null) + { + if (!is_null($index)) { + if (isset($this->_extractedData[$index])) { + return $this->_extractedData[$index]; + } + return null; + } + return $this->_extractedData; + } + + /** + * Apply attribute input filter to value + * + * @param string $value + * @return string + */ + protected function _applyInputFilter($value) + { + if ($value === false) { + return false; + } + + $filter = $this->_getFormFilter(); + if ($filter) { + $value = $filter->inputFilter($value); + } + + return $value; + } + + /** + * Return Data Form Input/Output Filter + * + * @return Varien_Data_Form_Filter_Interface|false + */ + protected function _getFormFilter() + { + $filterCode = $this->getAttribute()->getInputFilter(); + if ($filterCode) { + $filterClass = 'Varien_Data_Form_Filter_' . ucfirst($filterCode); + if ($filterCode == 'date') { + $filter = new $filterClass($this->_dateFilterFormat(), Mage::app()->getLocale()->getLocale()); + } else { + $filter = new $filterClass(); + } + return $filter; + } + return false; + } + + /** + * Get/Set/Reset date filter format + * + * @param string|null|false $format + * @return Mage_Customer_Model_Attribute_Data_Abstract|string + */ + protected function _dateFilterFormat($format = null) + { + if (is_null($format)) { + // get format + if (is_null($this->_dateFilterFormat)) { + $this->_dateFilterFormat = Mage_Core_Model_Locale::FORMAT_TYPE_SHORT; + } + return Mage::app()->getLocale()->getDateFormat($this->_dateFilterFormat); + } else if ($format === false) { + // reset value + $this->_dateFilterFormat = null; + return $this; + } + + $this->_dateFilterFormat = $format; + return $this; + } + + /** + * Apply attribute output filter to value + * + * @param string $value + * @return string + */ + protected function _applyOutputFilter($value) + { + $filter = $this->_getFormFilter(); + if ($filter) { + $value = $filter->outputFilter($value); + } + + return $value; + } + + /** + * Validate value by attribute input validation rule + * + * @param string $value + * @return string + */ + protected function _validateInputRule($value) + { + // skip validate empty value + if (empty($value)) { + return true; + } + + $label = $this->getAttribute()->getStoreLabel(); + $validateRules = $this->getAttribute()->getValidateRules(); + + if (!empty($validateRules['input_validation'])) { + switch ($validateRules['input_validation']) { + case 'alphanumeric': + $validator = new Zend_Validate_Alnum(true); + $validator->setMessage( + Mage::helper('customer')->__('"%s" invalid type entered.', $label), + Zend_Validate_Alnum::INVALID + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" has not only alphabetic and digit characters.', $label), + Zend_Validate_Alnum::NOT_ALNUM + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is an empty string.', $label), + Zend_Validate_Alnum::STRING_EMPTY + ); + if (!$validator->isValid($value)) { + return $validator->getMessages(); + } + break; + case 'numeric': + $validator = new Zend_Validate_Digits(); + $validator->setMessage( + Mage::helper('customer')->__('"%s" invalid type entered.', $label), + Zend_Validate_Digits::INVALID + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" contains not only digit characters.', $label), + Zend_Validate_Digits::NOT_DIGITS + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is an empty string.', $label), + Zend_Validate_Digits::STRING_EMPTY + ); + if (!$validator->isValid($value)) { + return $validator->getMessages(); + } + break; + case 'alpha': + $validator = new Zend_Validate_Alpha(true); + $validator->setMessage( + Mage::helper('customer')->__('"%s" invalid type entered.', $label), + Zend_Validate_Alpha::INVALID + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" has not only alphabetic characters.', $label), + Zend_Validate_Alpha::NOT_ALPHA + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is an empty string.', $label), + Zend_Validate_Alpha::STRING_EMPTY + ); + if (!$validator->isValid($value)) { + return $validator->getMessages(); + } + break; + case 'email': + $validator = new Zend_Validate_EmailAddress(); + $validator->setMessage( + Mage::helper('customer')->__('"%s" invalid type entered.', $label), + Zend_Validate_EmailAddress::INVALID + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid email address.', $label), + Zend_Validate_EmailAddress::INVALID_FORMAT + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid hostname.', $label), + Zend_Validate_EmailAddress::INVALID_HOSTNAME + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid hostname.', $label), + Zend_Validate_EmailAddress::INVALID_MX_RECORD + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid hostname.', $label), + Zend_Validate_EmailAddress::INVALID_MX_RECORD + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid email address.', $label), + Zend_Validate_EmailAddress::DOT_ATOM + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid email address.', $label), + Zend_Validate_EmailAddress::QUOTED_STRING + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid email address.', $label), + Zend_Validate_EmailAddress::INVALID_LOCAL_PART + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" exceeds the allowed length.', $label), + Zend_Validate_EmailAddress::LENGTH_EXCEEDED + ); + if (!$validator->isValid($value)) { + return array_unique($validator->getMessages()); + } + break; + case 'url': + $parsedUrl = parse_url($value); + if ($parsedUrl === false || empty($parsedUrl['scheme']) || empty($parsedUrl['host'])) { + return array(Mage::helper('customer')->__('"%s" is not a valid URL.', $label)); + } + $validator = new Zend_Validate_Hostname(); + if (!$validator->isValid($parsedUrl['host'])) { + return array(Mage::helper('customer')->__('"%s" is not a valid URL.', $label)); + } + break; + case 'date': + $format = Mage::app()->getLocale()->getDateFormat(Varien_Date::DATE_INTERNAL_FORMAT); + $validator = new Zend_Validate_Date($format); + $validator->setMessage( + Mage::helper('customer')->__('"%s" invalid type entered.', $label), + Zend_Validate_Date::INVALID + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" is not a valid date.', $label), + Zend_Validate_Date::INVALID_DATE + ); + $validator->setMessage( + Mage::helper('customer')->__('"%s" does not fit the entered date format.', $label), + Zend_Validate_Date::FALSEFORMAT + ); + break; + } + } + return true; + } + + /** + * Set is AJAX Request flag + * + * @param boolean $flag + * @return Mage_Customer_Model_Form + */ + public function setIsAjaxRequest($flag = true) + { + $this->_isAjax = (bool)$flag; + return $this; + } + + /** + * Return is AJAX Request + * + * @return boolean + */ + public function getIsAjaxRequest() + { + return $this->_isAjax; + } + + /** + * Return Original Attribute value from Request + * + * @param Zend_Controller_Request_Http $request + * @return mixed + */ + protected function _getRequestValue(Zend_Controller_Request_Http $request) + { + $attrCode = $this->getAttribute()->getAttributeCode(); + if ($this->_requestScope) { + if (strpos($this->_requestScope, '/') !== false) { + $params = $request->getParams(); + $parts = explode('/', $this->_requestScope); + foreach ($parts as $part) { + if (isset($params[$part])) { + $params = $params[$part]; + } else { + $params = array(); + } + } + } else { + $params = $request->getParam($this->_requestScope); + } + + if (isset($params[$attrCode])) { + $value = $params[$attrCode]; + } else { + $value = false; + } + + if (!$this->_requestScopeOnly && $value === false) { + $value = $request->getParam($attrCode, false); + } + } else { + $value = $request->getParam($attrCode, false); + } + return $value; + } + + /** + * Extract data from request and return value + * + * @param Zend_Controller_Request_Http $request + * @return array|string + */ + abstract public function extractValue(Zend_Controller_Request_Http $request); + + /** + * Validate data + * + * @param array|string $value + * @throws Mage_Core_Exception + * @return boolean + */ + abstract public function validateValue($value); + + /** + * Export attribute value to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + abstract public function compactValue($value); + + /** + * Restore attribute value from SESSION to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + abstract public function restoreValue($value); + + /** + * Return formated attribute value from entity model + * + * @param string $format + * @return string|array + */ + abstract public function outputValue($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT); +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Boolean.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Boolean.php new file mode 100644 index 0000000000..9a7c5a4307 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Boolean.php @@ -0,0 +1,58 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Boolean extends Mage_Customer_Model_Attribute_Data_Select +{ + /** + * Return a text for option value + * + * @param int $value + * @return string + */ + protected function _getOptionText($value) + { + switch ($value) { + case '0': + $text = Mage::helper('customer')->__('No'); + break; + case '1': + $text = Mage::helper('customer')->__('Yes'); + break; + default: + $text = ''; + break; + } + return $text; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Date.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Date.php new file mode 100644 index 0000000000..fd40290a7f --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Date.php @@ -0,0 +1,137 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Date extends Mage_Customer_Model_Attribute_Data_Abstract +{ + /** + * Extract data from request and return value + * + * @param Zend_Controller_Request_Http $request + * @return array|string + */ + public function extractValue(Zend_Controller_Request_Http $request) + { + $value = $this->_getRequestValue($request); + return $this->_applyInputFilter($value); + } + + /** + * Validate data + * Return true or array of errors + * + * @param array|string $value + * @return boolean|array + */ + public function validateValue($value) + { + $errors = array(); + $attribute = $this->getAttribute(); + $label = $attribute->getStoreLabel(); + + if ($value === false) { + // try to load original value and validate it + $value = $this->getEntity()->getDataUsingMethod($attribute->getAttributeCode()); + } + + if ($attribute->getIsRequired() && empty($value)) { + $errors[] = Mage::helper('customer')->__('"%s" is a required value.', $label); + } + + if (!$errors && !$attribute->getIsRequired() && empty($value)) { + return true; + } + + $result = $this->_validateInputRule($value); + if ($result !== true) { + $errors = array_merge($errors, $result); + } + if (count($errors) == 0) { + return true; + } + + return $errors; + } + + /** + * Export attribute value to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Text + */ + public function compactValue($value) + { + if ($value !== false) { + if (empty($value)) { + $value = null; + } + $this->getEntity()->setDataUsingMethod($this->getAttribute()->getAttributeCode(), $value); + } + return $this; + } + + /** + * Restore attribute value from SESSION to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function restoreValue($value) + { + return $this->compactValue($value); + } + + /** + * Return formated attribute value from entity model + * + * @return string|array + */ + public function outputValue($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT) + { + $value = $this->getEntity()->getData($this->getAttribute()->getAttributeCode()); + if ($value) { + switch ($format) { + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT: + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_HTML: + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_PDF: + $this->_dateFilterFormat(Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM); + break; + } + $value = $this->_applyOutputFilter($value); + } + + $this->_dateFilterFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT); + + return $value; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/File.php b/app/code/core/Mage/Customer/Model/Attribute/Data/File.php new file mode 100644 index 0000000000..e94a89f11a --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/File.php @@ -0,0 +1,265 @@ + + */ +class Mage_Customer_Model_Attribute_Data_File extends Mage_Customer_Model_Attribute_Data_Abstract +{ + /** + * Extract data from request and return value + * + * @param Zend_Controller_Request_Http $request + * @return array|string + */ + public function extractValue(Zend_Controller_Request_Http $request) + { + if ($this->getIsAjaxRequest()) { + return false; + } + + $extend = $this->_getRequestValue($request); + + $attrCode = $this->getAttribute()->getAttributeCode(); + if ($this->_requestScope) { + $value = array(); + if (strpos($this->_requestScope, '/') !== false) { + $scopes = explode('/', $this->_requestScope); + $mainScope = array_shift($scopes); + } else { + $mainScope = $this->_requestScope; + $scopes = array(); + } + + if (!empty($_FILES[$mainScope])) { + foreach ($_FILES[$mainScope] as $fileKey => $scopeData) { + foreach ($scopes as $scopeName) { + if (isset($scopeData[$scopeName])) { + $scopeData = $scopeData[$scopeName]; + } else { + $scopeData[$scopeName] = array(); + } + } + + if (isset($scopeData[$attrCode])) { + $value[$fileKey] = $scopeData[$attrCode]; + } + } + } else { + $value = array(); + } + } else { + if (isset($_FILES[$attrCode])) { + $value = $_FILES[$attrCode]; + } else { + $value = array(); + } + } + + if (!empty($extend['delete'])) { + $value['delete'] = true; + } + + return $value; + } + + /** + * Validate file by attribute validate rules + * Return array of errors + * + * @param array $value + * @return array + */ + protected function _validateByRules($value) + { + $label = $this->getAttribute()->getStoreLabel(); + $rules = $this->getAttribute()->getValidateRules(); + if (!empty($rules['file_extensions'])) { + $extension = pathinfo($value['name'], PATHINFO_EXTENSION); + $extensions = explode(',', $rules['file_extensions']); + $extensions = array_map('trim', $extensions); + if (!in_array($extension, $extensions)) { + return array( + Mage::helper('customer')->__('"%s" is not a valid file extension.', $label) + ); + } + } + + if (!is_uploaded_file($value['tmp_name'])) { + return array( + Mage::helper('customer')->__('"%s" is not a valid file.', $label) + ); + } + + if (!empty($rules['max_file_size'])) { + $size = $value['size']; + if ($rules['max_file_size'] < $size) { + return array( + Mage::helper('customer')->__('"%s" exceeds the allowed file size.', $label) + ); + }; + } + + return array(); + } + + /** + * Validate data + * + * @param array|string $value + * @throws Mage_Core_Exception + * @return boolean + */ + public function validateValue($value) + { + if ($this->getIsAjaxRequest()) { + return true; + } + + $errors = array(); + $attribute = $this->getAttribute(); + $label = $attribute->getStoreLabel(); + + $toDelete = !empty($value['delete']) ? true : false; + $toUpload = !empty($value['tmp_name']) ? true : false; + + if (!$toUpload && !$toDelete && $this->getEntity()->getData($attribute->getAttributeCode())) { + return true; + } + + if (!$attribute->getIsRequired() && !$toUpload) { + return true; + } + + if ($attribute->getIsRequired() && !$toUpload) { + $errors[] = Mage::helper('customer')->__('"%s" is a required value.', $label); + } + + if ($toUpload) { + $errors = array_merge($errors, $this->_validateByRules($value)); + } + + if (count($errors) == 0) { + return true; + } + + return $errors; + } + + /** + * Export attribute value to entity model + * + * @param Mage_Core_Model_Abstract $entity + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_File + */ + public function compactValue($value) + { + if ($this->getIsAjaxRequest()) { + return $this; + } + + $attribute = $this->getAttribute(); + $original = $this->getEntity()->getData($attribute->getAttributeCode()); + $toDelete = false; + if ($original) { + if (!$attribute->getIsRequired() && !empty($value['delete'])) { + $toDelete = true; + } + if (!empty($value['tmp_name'])) { + $toDelete = true; + } + } + + $ioFile = new Varien_Io_File(); + $path = Mage::getBaseDir('media') . DS . 'customer'; + $ioFile->open(array('path' => $path)); + + // unlink entity file + if ($toDelete) { + $this->getEntity()->setData($attribute->getAttributeCode(), ''); + $file = $path . $original; + if ($ioFile->fileExists($file)) { + $ioFile->rm($file); + } + } + + if (!empty($value['tmp_name'])) { + try { + $uploader = new Varien_File_Uploader($value); + $uploader->setFilesDispersion(true); + $uploader->setFilenamesCaseSensitivity(false); + $uploader->setAllowRenameFiles(true); + $uploader->save($path, $value['name']); + $fileName = $uploader->getUploadedFileName(); + $this->getEntity()->setData($attribute->getAttributeCode(), $fileName); + } catch (Exception $e) { + Mage::logException($e); + } + } + + return $this; + } + + /** + * Restore attribute value from SESSION to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function restoreValue($value) + { + return $this; + } + + /** + * Return formated attribute value from entity model + * + * @return string|array + */ + public function outputValue($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT) + { + $output = ''; + $value = $this->getEntity()->getData($this->getAttribute()->getAttributeCode()); + if ($value) { + switch ($format) { + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_JSON: + $output = array( + 'value' => $value, + 'url_key' => Mage::helper('core')->urlEncode($value) + ); + break; + } + } + + return $output; + } +} diff --git a/app/code/core/Mage/GiftRegistry/Model/Mysql4/Gift.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Hidden.php similarity index 78% rename from app/code/core/Mage/GiftRegistry/Model/Mysql4/Gift.php rename to app/code/core/Mage/Customer/Model/Attribute/Data/Hidden.php index 193b9c1e12..cded7d222b 100644 --- a/app/code/core/Mage/GiftRegistry/Model/Mysql4/Gift.php +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Hidden.php @@ -19,23 +19,19 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category Mage - * @package Mage_GiftRegistry + * @package Mage_Customer * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ /** - * Giftregistry gift resource model + * Customer Attribute Hidden text Data Model * * @category Mage - * @package Mage_GiftRegistry + * @package Mage_Customer * @author Magento Core Team */ -class Mage_GiftRegistry_Model_Mysql4_Gift extends Mage_Core_Model_Mysql4_Abstract +class Mage_Customer_Model_Attribute_Data_Hidden extends Mage_Customer_Model_Attribute_Data_Text { - protected function _construct() - { - $this->_init('giftregistry/gift', 'gift_id'); - } } diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Image.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Image.php new file mode 100644 index 0000000000..81db30f491 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Image.php @@ -0,0 +1,96 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Image extends Mage_Customer_Model_Attribute_Data_File +{ + /** + * Validate file by attribute validate rules + * Return array of errors + * + * @param array $value + * @return array + */ + protected function _validateByRules($value) + { + $label = $this->getAttribute()->getStoreLabel(); + $rules = $this->getAttribute()->getValidateRules(); + + $imageProp = @getimagesize($value['tmp_name']); + + if (!is_uploaded_file($value['tmp_name']) || !$imageProp) { + return array( + Mage::helper('customer')->__('"%s" is not a valid file', $label) + ); + } + + $allowImageTypes = array( + 1 => 'gif', + 2 => 'jpg', + 3 => 'png', + ); + + if (!isset($allowImageTypes[$imageProp[2]])) { + return array( + Mage::helper('customer')->__('"%s" is not a valid image format', $label) + ); + } + + // modify image name + $extension = pathinfo($value['name'], PATHINFO_EXTENSION); + if ($extension != $allowImageTypes[$imageProp[2]]) { + $value['name'] = pathinfo($value['name'], PATHINFO_FILENAME) . '.' . $allowImageTypes[$imageProp[2]]; + } + + $errors = array(); + if (!empty($rules['max_file_size'])) { + $size = $value['size']; + if ($rules['max_file_size'] < $size) { + $errors[] = Mage::helper('customer')->__('"%s" exceeds the allowed file size.', $label); + }; + } + + if (!empty($rules['max_image_width'])) { + if ($rules['max_image_width'] < $imageProp[0]) { + $errors[] = Mage::helper('customer')->__('"%s" width exceeds allowed value of %s px.', $label, $rules['max_image_width']); + }; + } + if (!empty($rules['max_image_heght'])) { + if ($rules['max_image_heght'] < $imageProp[1]) { + $errors[] = Mage::helper('customer')->__('"%s" height exceeds allowed value of %s px.', $label, $rules['max_image_heght']); + }; + } + + return $errors; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Multiline.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Multiline.php new file mode 100644 index 0000000000..356440ca61 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Multiline.php @@ -0,0 +1,154 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Multiline extends Mage_Customer_Model_Attribute_Data_Text +{ + /** + * Extract data from request and return value + * + * @param Zend_Controller_Request_Http $request + * @return array|string + */ + public function extractValue(Zend_Controller_Request_Http $request) + { + $value = $this->_getRequestValue($request); + if (!is_array($value)) { + $value = false; + } else { + $value = array_map(array($this, '_applyInputFilter'), $value); + } + return $value; + } + + /** + * Validate data + * Return true or array of errors + * + * @param array|string $value + * @return boolean|array + */ + public function validateValue($value) + { + $errors = array(); + $attribute = $this->getAttribute(); + + if ($value === false) { + // try to load original value and validate it + $value = $this->getEntity()->getDataUsingMethod($attribute->getAttributeCode()); + if (!is_array($value)) { + $value = explode("\n", $value); + } + } + + for ($i = 0; $i < $attribute->getMultilineCount(); $i ++) { + if (!isset($value[$i])) { + $value[$i] = null; + } + // validate first line + if ($i == 0) { + $result = parent::validateValue($value[$i]); + if ($result !== true) { + $errors = $result; + } + } else { + if (!empty($value[$i])) { + $result = parent::validateValue($value[$i]); + if ($result !== true) { + $errors = array_merge($errors, $result); + } + } + } + } + + if (count($errors) == 0) { + return true; + } + return $errors; + } + + /** + * Export attribute value to entity model + * + * @param Mage_Core_Model_Abstract $entity + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Multiline + */ + public function compactValue($value) + { + if (is_array($value)) { + $value = trim(implode("\n", $value)); + } + return parent::compactValue($value); + } + + /** + * Restore attribute value from SESSION to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function restoreValue($value) + { + return $this->compactValue($value); + } + + /** + * Return formated attribute value from entity model + * + * @return string|array + */ + public function outputValue($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT) + { + $values = $this->getEntity()->getData($this->getAttribute()->getAttributeCode()); + if (!is_array($values)) { + $values = explode("\n", $values); + } + $values = array_map(array($this, '_applyOutputFilter'), $values); + switch ($format) { + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_ARRAY: + $output = $values; + break; + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_HTML: + $output = implode("
    ", $values); + break; + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_ONELINE: + $output = implode(" ", $values); + break; + default: + $output = implode("\n", $values); + break; + } + return $output; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Multiselect.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Multiselect.php new file mode 100644 index 0000000000..d1d784aaab --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Multiselect.php @@ -0,0 +1,96 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Multiselect extends Mage_Customer_Model_Attribute_Data_Select +{ + /** + * Extract data from request and return value + * + * @param Zend_Controller_Request_Http $request + * @return array|string + */ + public function extractValue(Zend_Controller_Request_Http $request) + { + $values = $this->_getRequestValue($request); + if ($values !== false && !is_array($values)) { + $values = array($values); + } + return $values; + } + + /** + * Export attribute value to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Multiselect + */ + public function compactValue($value) + { + if (is_array($value)) { + $value = implode(',', $value); + } + return parent::compactValue($value); + } + + /** + * Return formated attribute value from entity model + * + * @return string|array + */ + public function outputValue($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT) + { + $values = $this->getEntity()->getData($this->getAttribute()->getAttributeCode()); + if (!is_array($values)) { + $values = explode(',', $values); + } + + switch ($format) { + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_JSON: + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_ARRAY: + $output = $values; + default: + $output = array(); + foreach ($values as $value) { + if (!$value) { + continue; + } + $output[] = $this->getAttribute()->getSource()->getOptionText($value); + } + $output = implode(', ', $output); + break; + } + + return $output; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Postcode.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Postcode.php new file mode 100644 index 0000000000..f51667133e --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Postcode.php @@ -0,0 +1,53 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Postcode extends Mage_Customer_Model_Attribute_Data_Text +{ + /** + * Validate postal/zip code + * Return true and skip validation if country zip code is optional + * + * @param array|string $value + * @return boolean|array + */ + public function validateValue($value) + { + $countryId = $this->getExtractedData('country_id'); + $optionalZip = Mage::helper('directory')->getCountriesWithOptionalZip(); + if (!in_array($countryId, $optionalZip)) { + return parent::validateValue($value); + } + return true; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Select.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Select.php new file mode 100644 index 0000000000..9a9bee19c5 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Select.php @@ -0,0 +1,139 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Select extends Mage_Customer_Model_Attribute_Data_Abstract +{ + /** + * Extract data from request and return value + * + * @param Zend_Controller_Request_Http $request + * @return array|string + */ + public function extractValue(Zend_Controller_Request_Http $request) + { + return $this->_getRequestValue($request); + } + + /** + * Validate data + * Return true or array of errors + * + * @param array|string $value + * @return boolean|array + */ + public function validateValue($value) + { + $errors = array(); + $attribute = $this->getAttribute(); + $label = $attribute->getStoreLabel(); + + if ($value === false) { + // try to load original value and validate it + $value = $this->getEntity()->getData($attribute->getAttributeCode()); + } + + if ($attribute->getIsRequired() && empty($value) && $value != '0') { + $errors[] = Mage::helper('customer')->__('"%s" is a required value.', $label); + } + + if (!$errors && !$attribute->getIsRequired() && empty($value)) { + return true; + } + + if (count($errors) == 0) { + return true; + } + + return $errors; + } + + /** + * Export attribute value to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Text + */ + public function compactValue($value) + { + if ($value !== false) { + $this->getEntity()->setData($this->getAttribute()->getAttributeCode(), $value); + } + return $this; + } + + /** + * Restore attribute value from SESSION to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function restoreValue($value) + { + return $this->compactValue($value); + } + + /** + * Return a text for option value + * + * @param int $value + * @return string + */ + protected function _getOptionText($value) + { + return $this->getAttribute()->getSource()->getOptionText($value); + } + + /** + * Return formated attribute value from entity model + * + * @return string|array + */ + public function outputValue($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT) + { + $value = $this->getEntity()->getData($this->getAttribute()->getAttributeCode()); + switch ($format) { + case Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_JSON: + $output = $value; + default: + if ($value != '') { + $output = $this->_getOptionText($value); + } else { + $output = ''; + } + break; + } + + return $output; + } +} diff --git a/app/code/core/Mage/Customer/Model/Attribute/Data/Text.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Text.php new file mode 100644 index 0000000000..1792fed0a0 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Text.php @@ -0,0 +1,135 @@ + + */ +class Mage_Customer_Model_Attribute_Data_Text extends Mage_Customer_Model_Attribute_Data_Abstract +{ + /** + * Extract data from request and return value + * + * @param Zend_Controller_Request_Http $request + * @return array|string + */ + public function extractValue(Zend_Controller_Request_Http $request) + { + $value = $this->_getRequestValue($request); + return $this->_applyInputFilter($value); + } + + /** + * Validate data + * Return true or array of errors + * + * @param array|string $value + * @return boolean|array + */ + public function validateValue($value) + { + $errors = array(); + $attribute = $this->getAttribute(); + $label = $attribute->getStoreLabel(); + + if ($value === false) { + // try to load original value and validate it + $value = $this->getEntity()->getDataUsingMethod($attribute->getAttributeCode()); + } + + if ($attribute->getIsRequired() && empty($value)) { + $errors[] = Mage::helper('customer')->__('"%s" is a required value.', $label); + } + + if (!$errors && !$attribute->getIsRequired() && empty($value)) { + return true; + } + + // validate length + $length = Mage::helper('core/string')->strlen(trim($value)); + + $validateRules = $attribute->getValidateRules(); + if (!empty($validateRules['min_text_length']) && $length < $validateRules['min_text_length']) { + $errors[] = Mage::helper('customer')->__('"%s" length must be equal or greater than %s characters.', $label, $validateRules['min_text_length']); + } + if (!empty($validateRules['max_text_length']) && $length > $validateRules['max_text_length']) { + $errors[] = Mage::helper('customer')->__('"%s" length must be equal or greater than %s characters.', $label, $validateRules['max_text_length']); + } + + $result = $this->_validateInputRule($value); + if ($result !== true) { + $errors = array_merge($errors, $result); + } + if (count($errors) == 0) { + return true; + } + + return $errors; + } + + /** + * Export attribute value to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Text + */ + public function compactValue($value) + { + if ($value !== false) { + $this->getEntity()->setDataUsingMethod($this->getAttribute()->getAttributeCode(), $value); + } + return $this; + } + + /** + * Restore attribute value from SESSION to entity model + * + * @param array|string $value + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + public function restoreValue($value) + { + return $this->compactValue($value); + } + + /** + * Return formated attribute value from entity model + * + * @param string $format + * @return string|array + */ + public function outputValue($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT) + { + $value = $this->getEntity()->getData($this->getAttribute()->getAttributeCode()); + $value = $this->_applyOutputFilter($value); + + return $value; + } +} diff --git a/app/code/core/Mage/GiftRegistry/Model/Gift.php b/app/code/core/Mage/Customer/Model/Attribute/Data/Textarea.php similarity index 75% rename from app/code/core/Mage/GiftRegistry/Model/Gift.php rename to app/code/core/Mage/Customer/Model/Attribute/Data/Textarea.php index 571f4fdf50..c8df4f38e6 100644 --- a/app/code/core/Mage/GiftRegistry/Model/Gift.php +++ b/app/code/core/Mage/Customer/Model/Attribute/Data/Textarea.php @@ -19,26 +19,19 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category Mage - * @package Mage_GiftRegistry + * @package Mage_Customer * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ /** - * Giftregistry gift model + * Customer Attribute Text Area Data Model * * @category Mage - * @package Mage_GiftRegistry + * @package Mage_Customer * @author Magento Core Team */ -class Mage_GiftRegistry_Model_Gift extends Mage_Core_Model_Abstract +class Mage_Customer_Model_Attribute_Data_Textarea extends Mage_Customer_Model_Attribute_Data_Text { - protected $_eventPrefix = 'giftregisty_gift'; - protected $_eventObject = 'gift'; - - protected function _construct() - { - $this->_init('giftregistry/gift'); - } } diff --git a/app/code/core/Mage/Customer/Model/Convert/Adapter/Customer.php b/app/code/core/Mage/Customer/Model/Convert/Adapter/Customer.php index 99ba2eb99b..0d5698a4e9 100644 --- a/app/code/core/Mage/Customer/Model/Convert/Adapter/Customer.php +++ b/app/code/core/Mage/Customer/Model/Convert/Adapter/Customer.php @@ -443,12 +443,12 @@ public function saveRow($importData) /** * Check customer group */ - if (empty($importData['group_id']) || !isset($customerGroups[$importData['group_id']])) { - $value = isset($importData['group_id']) ? $importData['group_id'] : ''; - $message = Mage::helper('catalog')->__('Skipping import row, the value "%s" is not valid for the "%s" field.', $value, 'group_id'); + if (empty($importData['group']) || !isset($customerGroups[$importData['group']])) { + $value = isset($importData['group']) ? $importData['group'] : ''; + $message = Mage::helper('catalog')->__('Skipping import row, the value "%s" is not valid for the "%s" field.', $value, 'group'); Mage::throwException($message); } - $customer->setGroupId($customerGroups[$importData['group_id']]); + $customer->setGroupId($customerGroups[$importData['group']]); foreach ($this->_requiredFields as $field) { if (!isset($importData[$field])) { @@ -470,13 +470,13 @@ public function saveRow($importData) $customer->setPasswordHash($customer->hashPassword($customer->generatePassword(8))); } } - elseif (!empty($importData['group_id'])) { + elseif (!empty($importData['group'])) { $customerGroups = $this->getCustomerGroups(); /** * Check customer group */ - if (isset($customerGroups[$importData['group_id']])) { - $customer->setGroupId($customerGroups[$importData['group_id']]); + if (isset($customerGroups[$importData['group']])) { + $customer->setGroupId($customerGroups[$importData['group']]); } } diff --git a/app/code/core/Mage/Customer/Model/Customer.php b/app/code/core/Mage/Customer/Model/Customer.php index f1d40de0bb..6467cc122e 100644 --- a/app/code/core/Mage/Customer/Model/Customer.php +++ b/app/code/core/Mage/Customer/Model/Customer.php @@ -178,16 +178,16 @@ public function changePassword($newPassword) public function getName() { $name = ''; - $helper = Mage::helper('customer/address'); - if ($helper->canShowConfig('prefix_show') && $this->getPrefix()) { + $config = Mage::getSingleton('eav/config'); + if ($config->getAttribute('customer', 'prefix')->getIsVisible() && $this->getPrefix()) { $name .= $this->getPrefix() . ' '; } $name .= $this->getFirstname(); - if ($helper->canShowConfig('middlename_show') && $this->getMiddlename()) { + if ($config->getAttribute('customer', 'middlename')->getIsVisible() && $this->getMiddlename()) { $name .= ' ' . $this->getMiddlename(); } $name .= ' ' . $this->getLastname(); - if ($helper->canShowConfig('suffix_show')&& $this->getSuffix()) { + if ($config->getAttribute('customer', 'suffix')->getIsVisible() && $this->getSuffix()) { $name .= ' ' . $this->getSuffix(); } return $name; @@ -577,8 +577,8 @@ public function sendPasswordReminderEmail() Mage::getModel('core/email_template') ->setDesignConfig(array('area'=>'frontend', 'store'=>$storeId)) ->sendTransactional( - Mage::getStoreConfig(self::XML_PATH_FORGOT_EMAIL_TEMPLATE), - Mage::getStoreConfig(self::XML_PATH_FORGOT_EMAIL_IDENTITY), + Mage::getStoreConfig(self::XML_PATH_FORGOT_EMAIL_TEMPLATE, $storeId), + Mage::getStoreConfig(self::XML_PATH_FORGOT_EMAIL_IDENTITY, $storeId), $this->getEmail(), $this->getName(), array('customer'=>$this) @@ -596,7 +596,7 @@ public function sendPasswordReminderEmail() */ public function getGroupId() { - if (!$this->getData('group_id')) { + if (!$this->hasData('group_id')) { $storeId = $this->getStoreId() ? $this->getStoreId() : Mage::app()->getStore()->getId(); $this->setData('group_id', Mage::getStoreConfig(Mage_Customer_Model_Group::XML_PATH_DEFAULT_ID, $storeId)); } @@ -656,7 +656,7 @@ public function getSharedStoreIds() if (is_null($ids)) { $ids = array(); if ((bool)$this->getSharingConfig()->isWebsiteScope()) { - $ids = $this->getStore()->getWebsite()->getStoreIds(); + $ids = Mage::app()->getWebsite($this->getWebsiteId())->getStoreIds(); } else { foreach (Mage::app()->getStores() as $store) { @@ -705,7 +705,8 @@ public function setStore(Mage_Core_Model_Store $store) } /** - * Validate customer attribute values + * Validate customer attribute values. + * For existing customer password + confirmation will be validated only when password is set (i.e. its change is requested) * * @return bool */ @@ -713,7 +714,6 @@ public function validate() { $errors = array(); $customerHelper = Mage::helper('customer'); - $addressHelper = Mage::helper('customer/address'); if (!Zend_Validate::is( trim($this->getFirstname()) , 'NotEmpty')) { $errors[] = $customerHelper->__('The first name cannot be empty.'); } @@ -730,7 +730,7 @@ public function validate() if (!$this->getId() && !Zend_Validate::is($password , 'NotEmpty')) { $errors[] = $customerHelper->__('The password cannot be empty.'); } - if ($password && !Zend_Validate::is($password, 'StringLength', array(6))) { + if (strlen($password) && !Zend_Validate::is($password, 'StringLength', array(6))) { $errors[] = $customerHelper->__('The minimum password length is %s', 6); } $confirmation = $this->getConfirmation(); @@ -738,16 +738,17 @@ public function validate() $errors[] = $customerHelper->__('Please make sure your passwords match.'); } - if (('req' === $addressHelper->getConfig('dob_show')) - && '' == trim($this->getDob())) { + $entityType = Mage::getSingleton('eav/config')->getEntityType('customer'); + $attribute = Mage::getModel('customer/attribute')->loadByCode($entityType, 'dob'); + if ($attribute->getIsRequired() && '' == trim($this->getDob())) { $errors[] = $customerHelper->__('The Date of Birth is required.'); } - if (('req' === $addressHelper->getConfig('taxvat_show')) - && '' == trim($this->getTaxvat())) { + $attribute = Mage::getModel('customer/attribute')->loadByCode($entityType, 'taxvat'); + if ($attribute->getIsRequired() && '' == trim($this->getTaxvat())) { $errors[] = $customerHelper->__('The TAX/VAT number is required.'); } - if (('req' === $addressHelper->getConfig('gender_show')) - && '' == trim($this->getGender())) { + $attribute = Mage::getModel('customer/attribute')->loadByCode($entityType, 'gender'); + if ($attribute->getIsRequired() && '' == trim($this->getGender())) { $errors[] = $customerHelper->__('Gender is required.'); } @@ -1109,4 +1110,29 @@ public function __clone() $this->addAddress(clone $address); } } + + /** + * Return Entity Type instance + * + * @return Mage_Eav_Model_Entity_Type + */ + public function getEntityType() + { + return $this->_getResource()->getEntityType(); + } + + /** + * Return Entity Type ID + * + * @return int + */ + public function getEntityTypeId() + { + $entityTypeId = $this->getData('entity_type_id'); + if (!$entityTypeId) { + $entityTypeId = $this->getEntityType()->getId(); + $this->setData('entity_type_id', $entityTypeId); + } + return $entityTypeId; + } } diff --git a/app/code/core/Mage/Customer/Model/Customer/Api.php b/app/code/core/Mage/Customer/Model/Customer/Api.php index e290c17661..849fca6be6 100644 --- a/app/code/core/Mage/Customer/Model/Customer/Api.php +++ b/app/code/core/Mage/Customer/Model/Customer/Api.php @@ -36,6 +36,24 @@ 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 @@ -45,6 +63,7 @@ class Mage_Customer_Model_Customer_Api extends Mage_Customer_Model_Api_Resource */ public function create($customerData) { + $customerData = $this->_prepareData($customerData); try { $customer = Mage::getModel('customer/customer') ->setData($customerData) @@ -142,6 +161,8 @@ public function items($filters) */ public function update($customerId, $customerData) { + $customerData = $this->_prepareData($customerData); + $customer = Mage::getModel('customer/customer')->load($customerId); if (!$customer->getId()) { diff --git a/app/code/core/Mage/Customer/Model/Customer/Api/V2.php b/app/code/core/Mage/Customer/Model/Customer/Api/V2.php index 701a24d0f1..511ef759da 100644 --- a/app/code/core/Mage/Customer/Model/Customer/Api/V2.php +++ b/app/code/core/Mage/Customer/Model/Customer/Api/V2.php @@ -43,30 +43,11 @@ class Mage_Customer_Model_Customer_Api_V2 extends Mage_Customer_Model_Customer_A protected function _prepareData($data) { if (null !== ($_data = get_object_vars($data))) { - return $_data; + return parent::_prepareData($_data); } return array(); } - /** - * Create new customer - * - * @param array $customerData - * @return int - */ - public function create($customerData) - { - $customerData = $this->_prepareData($customerData); - try { - $customer = Mage::getModel('customer/customer') - ->setData($customerData) - ->save(); - } catch (Mage_Core_Exception $e) { - $this->_fault('data_invalid', $e->getMessage()); - } - return $customer->getId(); - } - /** * Retrieve cutomers data * @@ -126,29 +107,4 @@ public function items($filters) return $result; } - - /** - * Update customer data - * - * @param int $customerId - * @param array $customerData - * @return boolean - */ - public function update($customerId, $customerData) - { - $customer = Mage::getModel('customer/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; - } } diff --git a/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php b/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php index b32c679da3..ff7ecf2eb7 100644 --- a/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php +++ b/app/code/core/Mage/Customer/Model/Customer/Attribute/Backend/Password.php @@ -33,11 +33,17 @@ */ class Mage_Customer_Model_Customer_Attribute_Backend_Password extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract { + /** + * Special processing before attribute save: + * a) check some rules for password + * b) transform temporary attribute 'password' into real attribute 'password_hash' + */ public function beforeSave($object) { $password = trim($object->getPassword()); - if ($password) { - if(Mage::helper('core/string')->strlen($password)<6){ + $len = Mage::helper('core/string')->strlen($password); + if ($len) { + if ($len < 6) { Mage::throwException(Mage::helper('customer')->__('The password must have at least 6 characters. Leading or trailing spaces will be ignored.')); } $object->setPasswordHash($object->hashPassword($password)); diff --git a/app/code/core/Mage/Customer/Model/Entity/Address/Attribute/Collection.php b/app/code/core/Mage/Customer/Model/Entity/Address/Attribute/Collection.php index 12e073eff9..4e4957ab4e 100644 --- a/app/code/core/Mage/Customer/Model/Entity/Address/Attribute/Collection.php +++ b/app/code/core/Mage/Customer/Model/Entity/Address/Attribute/Collection.php @@ -32,38 +32,12 @@ * @package Mage_Customer * @author Magento Core Team */ -class Mage_Customer_Model_Entity_Address_Attribute_Collection extends Mage_Eav_Model_Mysql4_Entity_Attribute_Collection +class Mage_Customer_Model_Entity_Address_Attribute_Collection extends Mage_Customer_Model_Entity_Attribute_Collection { - protected function _initSelect() - { - $this->getSelect()->from(array('main_table' => $this->getResource()->getMainTable())) - ->where('main_table.entity_type_id=?', Mage::getModel('eav/entity')->setType('customer_address')->getTypeId()) - ->join( - array('additional_table' => $this->getTable('customer/eav_attribute')), - 'additional_table.attribute_id=main_table.attribute_id' - ); - return $this; - } - - /** - * Specify attribute entity type filter - * - * @param int $typeId - * @return Mage_Customer_Model_Entity_Address_Attribute_Collection - */ - public function setEntityTypeFilter($typeId) - { - return $this; - } - /** - * Specify filter by "is_visible" field + * Default attribute entity type code * - * @return Mage_Customer_Model_Entity_Address_Attribute_Collection + * @var string */ - public function addVisibleFilter() - { - $this->getSelect()->where('additional_table.is_visible=?', 1); - return $this; - } + protected $_entityTypeCode = 'customer_address'; } diff --git a/app/code/core/Mage/Customer/Model/Entity/Attribute.php b/app/code/core/Mage/Customer/Model/Entity/Attribute.php index d09ed738e4..2c96112475 100644 --- a/app/code/core/Mage/Customer/Model/Entity/Attribute.php +++ b/app/code/core/Mage/Customer/Model/Entity/Attribute.php @@ -42,12 +42,140 @@ class Mage_Customer_Model_Entity_Attribute extends Mage_Eav_Model_Mysql4_Entity_ */ protected function _beforeSave(Mage_Core_Model_Abstract $object) { - $inputFilter = $object->getInputFilter(); - if (is_array($inputFilter)) { - $object->setInputFilter(implode(',', $inputFilter)); + $validateRules = $object->getData('validate_rules'); + if (is_array($validateRules)) { + $object->setData('validate_rules', serialize($validateRules)); } return parent::_beforeSave($object); } + /** + * Retrieve select object for load object data + * + * @param string $field + * @param mixed $value + * @return Zend_Db_Select + */ + protected function _getLoadSelect($field, $value, $object) + { + $select = parent::_getLoadSelect($field, $value, $object); + if ($object->getWebsite()->getId()) { + $columns = array(); + $describe = $this->_getReadAdapter()->describeTable($this->getTable('customer/eav_attribute_website')); + unset($describe['attribute_id']); + foreach (array_keys($describe) as $columnName) { + if ($columnName == 'attribute_id') { + continue; + } + $columns['scope_' . $columnName] = $columnName; + } + + $select->joinLeft( + array('scope_table' => $this->getTable('customer/eav_attribute_website')), + $this->getMainTable() . '.attribute_id = scope_table.attribute_id AND scope_table.website_id = ' + . (int)$object->getWebsite()->getId(), + $columns + ); + } + + return $select; + } + + /** + * Save attribute/form relations after attribute save + * + * @param Mage_Core_Model_Abstract $object + * @return Mage_Customer_Model_Entity_Attribute + */ + protected function _afterSave(Mage_Core_Model_Abstract $object) + { + $forms = $object->getData('used_in_forms'); + if (is_array($forms)) { + $where = array('attribute_id=?' => $object->getId()); + $this->_getWriteAdapter()->delete($this->getTable('customer/form_attribute'), $where); + + $data = array(); + foreach ($forms as $formCode) { + $data[] = array( + 'form_code' => $formCode, + 'attribute_id' => intval($object->getId()) + ); + } + + if ($data) { + $this->_getWriteAdapter()->insertMultiple($this->getTable('customer/form_attribute'), $data); + } + } + + // update sort order + if (!$object->isObjectNew() && $object->dataHasChangedFor('sort_order')) { + $bind = array( + 'sort_order' => $object->getSortOrder() + ); + $where = $this->_getWriteAdapter()->quoteInto('attribute_id=?', $object->getId()); + $this->_getWriteAdapter()->update($this->getTable('eav/entity_attribute'), $bind, $where); + } + + // save scope attributes + $websiteId = $object->getWebsite()->getId(); + if ($websiteId) { + $table = $this->getTable('customer/eav_attribute_website'); + $describe = $this->_getReadAdapter()->describeTable($table); + $data = array(); + if (!$object->getScopeWebsiteId() || $object->getScopeWebsiteId() != $websiteId) { + $data = $this->getScopeValues($object); + } + $data['attribute_id'] = $object->getId(); + $data['website_id'] = $websiteId; + + $updateColumns = array(); + foreach (array_keys($describe) as $columnName) { + if ($columnName != 'attribute_id' && $columnName != 'website_id') { + $data[$columnName] = $object->getData('scope_' . $columnName); + $updateColumns[] = $columnName; + } + } + + $this->_getWriteAdapter()->insertOnDuplicate($table, $data, $updateColumns); + } + + return parent::_afterSave($object); + } + + /** + * Return scope values for attribute and website + * + * @param Mage_Customer_Model_Attribute $object + * @return array + */ + public function getScopeValues(Mage_Customer_Model_Attribute $object) + { + $select = $this->_getReadAdapter()->select() + ->from($this->getTable('customer/eav_attribute_website')) + ->where('attribute_id = ?', $object->getId()) + ->where('website_id = ?', $object->getWebsite()->getId()) + ->limit(1); + $result = $this->_getReadAdapter()->fetchRow($select); + + if (!$result) { + $result = array(); + } + + return $result; + } + + /** + * Return forms in which the attribute + * + * @param Mage_Core_Model_Abstract $object + * @return array + */ + public function getUsedInForms(Mage_Core_Model_Abstract $object) + { + $select = $this->_getReadAdapter()->select() + ->from($this->getTable('customer/form_attribute'), 'form_code') + ->where('attribute_id = ?', (int)$object->getId()); + return $this->_getReadAdapter()->fetchCol($select); + } } diff --git a/app/code/core/Mage/Customer/Model/Entity/Attribute/Collection.php b/app/code/core/Mage/Customer/Model/Entity/Attribute/Collection.php index aa24181e20..0e6e32bc31 100644 --- a/app/code/core/Mage/Customer/Model/Entity/Attribute/Collection.php +++ b/app/code/core/Mage/Customer/Model/Entity/Attribute/Collection.php @@ -34,24 +34,144 @@ */ class Mage_Customer_Model_Entity_Attribute_Collection extends Mage_Eav_Model_Mysql4_Entity_Attribute_Collection { + /** + * Current website scope instance + * + * @var Mage_Core_Model_Website + */ + protected $_website; + + /** + * Attribute Entity Type Filter + * + * @var Mage_Eav_Model_Entity_Type + */ + protected $_entityType; + + /** + * Default attribute entity type code + * + * @var string + */ + protected $_entityTypeCode = 'customer'; + + /** + * Return customer entity type instance + * + * @return Mage_Eav_Model_Entity_Type + */ + public function getEntityType() + { + if (is_null($this->_entityType)) { + $this->_entityType = Mage::getSingleton('eav/config')->getEntityType($this->_entityTypeCode); + } + return $this->_entityType; + } + + /** + * Set Website scope + * + * @param Mage_Core_Model_Website|int $website + * @return Mage_Customer_Model_Entity_Attribute_Collection + */ + public function setWebsite($website) + { + $this->_website = Mage::app()->getWebsite($website); + $this->addBindParam(':scope_website_id', $this->_website->getId()); + return $this; + } + + /** + * Return current website scope instance + * + * @return Mage_Core_Model_Website + */ + public function getWebsite() + { + if (is_null($this->_website)) { + $this->_website = Mage::app()->getStore()->getWebsite(); + } + return $this->_website; + } + + /** + * Initialize collection select + * + * @return Mage_Customer_Model_Entity_Attribute_Collection + */ protected function _initSelect() { - $this->getSelect()->from(array('main_table' => $this->getResource()->getMainTable())) - ->where('main_table.entity_type_id=?', Mage::getModel('eav/entity')->setType('customer')->getTypeId()) - ->join( - array('additional_table' => $this->getTable('customer/eav_attribute')), - 'additional_table.attribute_id=main_table.attribute_id' - ); + $entityType = $this->getEntityType(); + $extraTable = $entityType->getAdditionalAttributeTable(); + $mainDescribe = $this->getConnection()->describeTable($this->getResource()->getMainTable()); + $mainColumns = array(); + + foreach (array_keys($mainDescribe) as $columnName) { + $mainColumns[$columnName] = $columnName; + } + + $this->getSelect()->from(array('main_table' => $this->getResource()->getMainTable()), $mainColumns); + + // additional attribute data table + $extraDescribe = $this->getConnection()->describeTable($this->getTable($extraTable)); + $extraColumns = array(); + foreach (array_keys($extraDescribe) as $columnName) { + if (isset($mainColumns[$columnName])) { + continue; + } + $extraColumns[$columnName] = $columnName; + } + + $this->getSelect()->join( + array('additional_table' => $this->getTable($extraTable)), + 'additional_table.attribute_id = main_table.attribute_id', + $extraColumns) + ->where('main_table.entity_type_id = ?', $entityType->getId()); + + // scope values + + $scopeDescribe = $this->getConnection()->describeTable($this->getTable('customer/eav_attribute_website')); + $scopeColumns = array(); + foreach (array_keys($scopeDescribe) as $columnName) { + if ($columnName == 'attribute_id') { + continue; + } else if ($columnName == 'website_id') { + $scopeColumns['scope_website_id'] = $columnName; + } else { + if (isset($mainColumns[$columnName])) { + $alias = sprintf('scope_%s', $columnName); + $expression = new Zend_Db_Expr(sprintf('IFNULL(main_table.%s, scope_table.%s)', + $columnName, $columnName)); + $this->addFilterToMap($columnName, $expression); + $scopeColumns[$alias] = $columnName; + } else if (isset($extraColumns[$columnName])) { + $alias = sprintf('scope_%s', $columnName); + $expression = new Zend_Db_Expr(sprintf('IFNULL(additional_table.%s, scope_table.%s)', + $columnName, $columnName)); + $this->addFilterToMap($columnName, $expression); + $scopeColumns[$alias] = $columnName; + } + } + } + + $this->getSelect()->joinLeft( + array('scope_table' => $this->getTable('customer/eav_attribute_website')), + 'scope_table.attribute_id = main_table.attribute_id AND scope_table.website_id = :scope_website_id', + $scopeColumns + ); + $this->addBindParam(':scope_website_id', $this->getWebsite()->getId()); + return $this; } /** * Specify attribute entity type filter + * Entity type is defined * * @param int $typeId * @return Mage_Customer_Model_Entity_Attribute_Collection */ - public function setEntityTypeFilter($typeId) + public function setEntityTypeFilter($type) { return $this; } @@ -63,7 +183,29 @@ public function setEntityTypeFilter($typeId) */ public function addVisibleFilter() { - $this->getSelect()->where('additional_table.is_visible=?', 1); + $this->addFieldToFilter('is_visible', 1); return $this; } + + /** + * Exclude system hidden attributes + * + * @return Mage_Customer_Model_Entity_Attribute_Collection + */ + public function addSystemHiddenFilter() + { + $field = '(CASE WHEN additional_table.is_system = 1 AND additional_table.is_visible = 0 THEN 1 ELSE 0 END)'; + $this->addFieldToFilter($field, 0); + return $this; + } + + /** + * Add exclude hidden frontend input attribute filter to collection + * + * @return Mage_Customer_Model_Entity_Attribute_Collection + */ + public function addExcludeHiddenFrontendFilter() + { + return $this->addFieldToFilter('main_table.frontend_input', array('neq' => 'hidden')); + } } diff --git a/app/code/core/Mage/Customer/Model/Entity/Customer/Collection.php b/app/code/core/Mage/Customer/Model/Entity/Customer/Collection.php index bb79495463..224f1fc562 100644 --- a/app/code/core/Mage/Customer/Model/Entity/Customer/Collection.php +++ b/app/code/core/Mage/Customer/Model/Entity/Customer/Collection.php @@ -60,9 +60,9 @@ public function addNameToSelect() } $expr = 'CONCAT(' - .(isset($fields['prefix']) ? 'IF({{prefix}} IS NOT NULL AND {{prefix}} != "", CONCAT({{prefix}}," "), ""),' : '') - .'{{firstname}}'.(isset($fields['middlename']) ? ',IF({{middlename}} IS NOT NULL AND {{middlename}} != "", CONCAT(" ",{{middlename}}), "")' : '').'," ",{{lastname}}' - .(isset($fields['suffix']) ? ',IF({{suffix}} IS NOT NULL AND {{suffix}} != "", CONCAT(" ",{{suffix}}), "")' : '') + .(isset($fields['prefix']) ? 'IF({{prefix}} IS NOT NULL AND {{prefix}} != "", CONCAT(TRIM({{prefix}})," "), ""),' : '') + .'TRIM({{firstname}})'.(isset($fields['middlename']) ? ',IF({{middlename}} IS NOT NULL AND {{middlename}} != "", CONCAT(" ",TRIM({{middlename}})), "")' : '').'," ",TRIM({{lastname}})' + .(isset($fields['suffix']) ? ',IF({{suffix}} IS NOT NULL AND {{suffix}} != "", CONCAT(" ",TRIM({{suffix}})), "")' : '') .')'; $this->addExpressionAttributeToSelect('name', $expr, $fields); diff --git a/app/code/core/Mage/Customer/Model/Entity/Form/Attribute.php b/app/code/core/Mage/Customer/Model/Entity/Form/Attribute.php new file mode 100644 index 0000000000..fb1e8b8465 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Entity/Form/Attribute.php @@ -0,0 +1,59 @@ + + */ +class Mage_Customer_Model_Entity_Form_Attribute extends Mage_Core_Model_Mysql4_Abstract +{ + /** + * Initialize connection and define main table + * + */ + protected function _construct() + { + $this->_init('customer/form_attribute', 'attribute_id'); + } + + /** + * Return form attribute IDs by form code + * + * @param string $formCode + * @return array + */ + public function getFormAttributeIds($formCode) + { + $select = $this->_getReadAdapter()->select() + ->from($this->getMainTable(), 'attribute_id') + ->where('form_code=?', $formCode); + return $this->_getReadAdapter()->fetchCol($select); + } +} diff --git a/app/code/core/Mage/Customer/Model/Entity/Form/Attribute/Collection.php b/app/code/core/Mage/Customer/Model/Entity/Form/Attribute/Collection.php new file mode 100644 index 0000000000..5ba96dff12 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Entity/Form/Attribute/Collection.php @@ -0,0 +1,225 @@ + + */ +class Mage_Customer_Model_Entity_Form_Attribute_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract +{ + /** + * Current store instance + * + * @var Mage_Core_Model_Store + */ + protected $_store; + + /** + * Eav Entity Type instance + * + * @var Mage_Eav_Model_Entity_Type + */ + protected $_entityType; + + /** + * Define resource model + * + */ + protected function _construct() + { + $this->_init('eav/attribute', 'customer/form_attribute'); + } + + /** + * Set current store to collection + * + * @param Mage_Core_Model_Store|string|int $store + * @return Mage_Customer_Model_Entity_Form_Attribute_Collection + */ + public function setStore($store) + { + $this->_store = Mage::app()->getStore($store); + return $this; + } + + /** + * Return current store instance + * + * @return Mage_Core_Model_Store + */ + public function getStore() + { + if (is_null($this->_store)) { + $this->_store = Mage::app()->getStore(); + } + return $this->_store; + } + + /** + * Set entity type instance to collection + * + * @param Mage_Eav_Model_Entity_Type|string|int $entityType + * @return Mage_Customer_Model_Entity_Form_Attribute_Collection + */ + public function setEntityType($entityType) + { + $this->_entityType = Mage::getSingleton('eav/config')->getEntityType($entityType); + return $this; + } + + /** + * Return current entity type instance + * + * @return Mage_Eav_Model_Entity_Type + */ + public function getEntityType() + { + if (is_null($this->_entityType)) { + $this->setEntityType('customer'); + } + return $this->_entityType; + } + + /** + * Add Form Code filter to collection + * + * @param string $code + * @return Mage_Customer_Model_Entity_Form_Attribute_Collection + */ + public function addFormCodeFilter($code) + { + return $this->addFieldToFilter('main_table.form_code', $code); + } + + /** + * Set order by attribute sort order + * + * @param string $direction + * @return Mage_Customer_Model_Entity_Form_Attribute_Collection + */ + public function setSortOrder($direction = self::SORT_ORDER_ASC) + { + $this->setOrder('ea.is_user_defined', self::SORT_ORDER_ASC); + return $this->setOrder('ca.sort_order', $direction); + } + + /** + * Add joins to select + * + * @return Mage_Customer_Model_Entity_Form_Attribute_Collection + */ + protected function _beforeLoad() + { + $entityType = $this->getEntityType(); + $this->setItemObjectClass($entityType->getAttributeModel()); + + $eaColumns = array(); + $caColumns = array(); + $saColumns = array(); + + $eaDescribe = $this->getConnection()->describeTable($this->getTable('eav/attribute')); + foreach (array_keys($eaDescribe) as $columnName) { + if ($columnName == 'attribute_id') { + continue; + } + $eaColumns[$columnName] = $columnName; + } + + $this->_select->join( + array('ea' => $this->getTable('eav/attribute')), + 'main_table.attribute_id = ea.attribute_id', + $eaColumns + ); + + // join additional attribute data table + $additionalTable = $entityType->getAdditionalAttributeTable(); + if ($additionalTable) { + $caDescribe = $this->getConnection()->describeTable($this->getTable($additionalTable)); + foreach (array_keys($caDescribe) as $columnName) { + if ($columnName == 'attribute_id') { + continue; + } + $caColumns[$columnName] = $columnName; + } + + $this->_select->join( + array('ca' => $this->getTable($additionalTable)), + 'main_table.attribute_id = ca.attribute_id', + $caColumns + ); + } + + // add scope values + $saDescribe = $this->getConnection()->describeTable($this->getTable('customer/eav_attribute_website')); + foreach (array_keys($saDescribe) as $columnName) { + if ($columnName == 'attribute_id') { + continue; + } else if ($columnName == 'website_id') { + $saColumns['scope_website_id'] = $columnName; + } else { + if (isset($eaColumns[$columnName])) { + $code = sprintf('scope_%s', $columnName); + $saColumns[$code] = new Zend_Db_Expr(sprintf('IFNULL(sa.%s, ea.%s)', + $columnName, $columnName)); + } else if (isset($caColumns[$columnName])) { + $code = sprintf('scope_%s', $columnName); + $saColumns[$code] = new Zend_Db_Expr(sprintf('IFNULL(sa.%s, ca.%s)', + $columnName, $columnName)); + } + } + } + + $store = $this->getStore(); + + $this->_select->joinLeft( + array('sa' => $this->getTable('customer/eav_attribute_website')), + 'main_table.attribute_id = sa.attribute_id AND sa.website_id = :scope_website_id', + $saColumns + ); + $this->addBindParam(':scope_website_id', $store->getWebsiteId()); + + // add store attribute label + if ($store->isAdmin()) { + $this->_select->columns(array('store_label' => 'ea.frontend_label')); + } else { + $this->_select->joinLeft( + array('al' => $this->getTable('eav/attribute_label')), + 'al.attribute_id = main_table.attribute_id AND al.store_id = :label_store_id', + array('store_label' => new Zend_Db_Expr('IFNULL(al.value, ea.frontend_label)')) + ); + $this->addBindParam(':label_store_id', $store->getId()); + } + + // add entity type filter + $this->_select->where('ea.entity_type_id = ?', (int)$entityType->getId()); + + return parent::_beforeLoad(); + } +} diff --git a/app/code/core/Mage/Customer/Model/Entity/Setup.php b/app/code/core/Mage/Customer/Model/Entity/Setup.php index 67ce2c15b6..5c7defee63 100644 --- a/app/code/core/Mage/Customer/Model/Entity/Setup.php +++ b/app/code/core/Mage/Customer/Model/Entity/Setup.php @@ -63,7 +63,7 @@ public function getDefaultEntities() 'increment_model' => 'eav/entity_increment_numeric', 'increment_per_store' => false, 'additional_attribute_table' => 'customer/eav_attribute', - 'entity_attribute_collection' => 'customer/eav_attribute', + 'entity_attribute_collection' => 'customer/attribute_collection', 'attributes' => array( // 'entity_id' => array('type'=>'static'), // 'entity_type_id' => array('type'=>'static'), @@ -180,7 +180,7 @@ public function getDefaultEntities() 'entity_model' =>'customer/customer_address', 'table' => 'customer/address_entity', 'additional_attribute_table' => 'customer/eav_attribute', - 'entity_attribute_collection' => 'customer/eav_attribute', + 'entity_attribute_collection' => 'customer/address_attribute_collection', 'attributes' => array( // 'entity_id' => array('type'=>'static'), // 'entity_type_id' => array('type'=>'static'), diff --git a/app/code/core/Mage/Customer/Model/Form.php b/app/code/core/Mage/Customer/Model/Form.php new file mode 100644 index 0000000000..7bbe0fcc26 --- /dev/null +++ b/app/code/core/Mage/Customer/Model/Form.php @@ -0,0 +1,513 @@ + + */ +class Mage_Customer_Model_Form +{ + /** + * Current store instance + * + * @var Mage_Core_Model_Store + */ + protected $_store; + + /** + * Current entity type instance + * + * @var Mage_Eav_Model_Entity_Type + */ + protected $_entityType; + + /** + * Current entity instance + * + * @var Mage_Core_Model_Abstract + */ + protected $_entity; + + /** + * Current form code + * + * @var string + */ + protected $_formCode; + + /** + * Array of form attributes + * + * @var array + */ + protected $_attributes; + + /** + * Array of form system attributes + * + * @var array + */ + protected $_systemAttributes; + + /** + * Array of form user defined attributes + * + * @var array + */ + protected $_userAttributes; + + /** + * Is AJAX request flag + * + * @var boolean + */ + protected $_isAjax = false; + + /** + * Whether the invisible form fields need to be filtered/ignored + * + * @var bool + */ + protected $_ignoreInvisible = true; + + /** + * Set current store + * + * @param Mage_Core_Model_Store|string|int $store + * @return Mage_Customer_Model_Form + */ + public function setStore($store) + { + $this->_store = Mage::app()->getStore($store); + return $this; + } + + /** + * Set entity instance + * + * @param Mage_Core_Model_Abstract $entity + * @return Mage_Customer_Model_Form + */ + public function setEntity(Mage_Core_Model_Abstract $entity) + { + $this->_entity = $entity; + if ($entity->getEntityTypeId()) { + $this->setEntityType($entity->getEntityTypeId()); + } + return $this; + } + + /** + * Set entity type instance + * + * @param Mage_Eav_Model_Entity_Type|string|int $entityType + * @return Mage_Customer_Model_Form + */ + public function setEntityType($entityType) + { + $this->_entityType = Mage::getSingleton('eav/config')->getEntityType($entityType); + return $this; + } + + /** + * Set form code + * + * @param string $formCode + * @return Mage_Customer_Model_Form + */ + public function setFormCode($formCode) + { + $this->_formCode = $formCode; + return $this; + } + + /** + * Return current store instance + * + * @return Mage_Core_Model_Store + */ + public function getStore() + { + if (is_null($this->_store)) { + $this->_store = Mage::app()->getStore(); + } + return $this->_store; + } + + /** + * Return current form code + * + * @throws Mage_Core_Exception + * @return string + */ + public function getFormCode() + { + if (empty($this->_formCode)) { + Mage::throwException(Mage::helper('customer')->__('Form code is not defined')); + } + return $this->_formCode; + } + + /** + * Return entity type instance + * Return customer entity type if entity type is not defined + * + * @return Mage_Eav_Model_Entity_Type + */ + public function getEntityType() + { + if (is_null($this->_entityType)) { + $this->setEntityType('customer'); + } + return $this->_entityType; + } + + /** + * Return current entity instance + * + * @throws Mage_Core_Exception + * @return Mage_Core_Model_Abstract + */ + public function getEntity() + { + if (is_null($this->_entity)) { + Mage::throwException(Mage::helper('customer')->__('Entity instance is not defined')); + } + return $this->_entity; + } + + /** + * Return array of form attributes + * + * @return array + */ + public function getAttributes() + { + if (is_null($this->_attributes)) { + /* @var $collection Mage_Customer_Model_Entity_Form_Attribute_Collection */ + $collection = Mage::getResourceModel('customer/form_attribute_collection'); + $collection->setStore($this->getStore()) + ->setEntityType($this->getEntityType()) + ->addFormCodeFilter($this->getFormCode()) + ->setSortOrder(); + $this->_attributes = array(); + $this->_userAttributes = array(); + foreach ($collection as $attribute) { + /* @var $attribute Mage_Eav_Model_Entity_Attribute */ + $this->_attributes[$attribute->getAttributeCode()] = $attribute; + if ($attribute->getIsUserDefined()) { + $this->_userAttributes[$attribute->getAttributeCode()] = $attribute; + } else { + $this->_systemAttributes[$attribute->getAttributeCode()] = $attribute; + } + } + } + + return $this->_attributes; + } + + /** + * Return attribute instance by code or false + * + * @param string $attributeCode + * @return Mage_Eav_Model_Entity_Attribute|false + */ + public function getAttribute($attributeCode) + { + $attributes = $this->getAttributes(); + if (isset($attributes[$attributeCode])) { + return $attributes[$attributeCode]; + } + return false; + } + + /** + * Return array of form user defined attributes + * + * @return array + */ + public function getUserAttributes() + { + if (is_null($this->_userAttributes)) { + // load attributes + $this->getAttributes(); + } + return $this->_userAttributes; + } + + /** + * Return array of form system attributes + * + * @return array + */ + public function getSystemAttributes() + { + if (is_null($this->_systemAttributes)) { + // load attributes + $this->getAttributes(); + } + return $this->_systemAttributes; + } + + /** + * Return attribute data model by attribute + * + * @param Mage_Eav_Model_Entity_Attribute $attribute + * @return Mage_Customer_Model_Attribute_Data_Abstract + */ + protected function _getAttributeDataModel(Mage_Eav_Model_Entity_Attribute $attribute) + { + $dataModel = Mage_Customer_Model_Attribute_Data::factory($attribute, $this->getEntity()); + $dataModel->setIsAjaxRequest($this->getIsAjaxRequest()); + + return $dataModel; + } + + /** + * Prepare request with data and returns it + * + * @param array $data + * @return Zend_Controller_Request_Http + */ + public function prepareRequest(array $data) + { + $request = clone Mage::app()->getRequest(); + $request->setParamSources(); + $request->clearParams(); + $request->setParams($data); + + return $request; + } + + /** + * Extract data from request and return associative data array + * + * @param Zend_Controller_Request_Http $request + * @param string $scope the request scope + * @param boolean $scopeOnly search value only in scope or search value in global too + * @return array + */ + public function extractData(Zend_Controller_Request_Http $request, $scope = null, $scopeOnly = true) + { + $data = array(); + foreach ($this->getAttributes() as $attribute) { + if ($this->_isAttributeOmitted($attribute)) { + continue; + } + $dataModel = $this->_getAttributeDataModel($attribute); + $dataModel->setRequestScope($scope); + $dataModel->setRequestScopeOnly($scopeOnly); + $data[$attribute->getAttributeCode()] = $dataModel->extractValue($request); + } + return $data; + } + + /** + * Validate data array and return true or array of errors + * + * @param array $data + * @return boolean|array + */ + public function validateData(array $data) + { + $errors = array(); + foreach ($this->getAttributes() as $attribute) { + if ($this->_isAttributeOmitted($attribute)) { + continue; + } + $dataModel = $this->_getAttributeDataModel($attribute); + $dataModel->setExtractedData($data); + if (!isset($data[$attribute->getAttributeCode()])) { + $data[$attribute->getAttributeCode()] = null; + } + $result = $dataModel->validateValue($data[$attribute->getAttributeCode()]); + if ($result !== true) { + $errors = array_merge($errors, $result); + } + } + + if (count($errors) == 0) { + return true; + } + + return $errors; + } + + /** + * Compact data array to current entity + * + * @param array $data + * @return Mage_Customer_Model_Form + */ + public function compactData(array $data) + { + foreach ($this->getAttributes() as $attribute) { + if ($this->_isAttributeOmitted($attribute)) { + continue; + } + $dataModel = $this->_getAttributeDataModel($attribute); + $dataModel->setExtractedData($data); + if (!isset($data[$attribute->getAttributeCode()])) { + $data[$attribute->getAttributeCode()] = false; + } + $dataModel->compactValue($data[$attribute->getAttributeCode()]); + } + + return $this; + } + + /** + * Restore data array from SESSION to current entity + * + * @param array $data + * @return Mage_Customer_Model_Form + */ + public function restoreData(array $data) + { + foreach ($this->getAttributes() as $attribute) { + if ($this->_isAttributeOmitted($attribute)) { + continue; + } + $dataModel = $this->_getAttributeDataModel($attribute); + $dataModel->setExtractedData($data); + if (!isset($data[$attribute->getAttributeCode()])) { + $data[$attribute->getAttributeCode()] = false; + } + $dataModel->restoreValue($data[$attribute->getAttributeCode()]); + } + return $this; + } + + /** + * Return array of entity formated values + * + * @param string $format + * @return array + */ + public function outputData($format = Mage_Customer_Model_Attribute_Data::OUTPUT_FORMAT_TEXT) + { + $data = array(); + foreach ($this->getAttributes() as $attribute) { + if ($this->_isAttributeOmitted($attribute)) { + continue; + } + $dataModel = $this->_getAttributeDataModel($attribute); + $dataModel->setExtractedData($data); + $data[$attribute->getAttributeCode()] = $dataModel->outputValue($format); + } + return $data; + } + + /** + * Restore entity original data + * + * @return Mage_Customer_Model_Form + */ + public function resetEntityData() + { + foreach ($this->getAttributes() as $attribute) { + if ($this->_isAttributeOmitted($attribute)) { + continue; + } + $value = $this->getEntity()->getOrigData($attribute->getAttributeCode()); + $this->getEntity()->setData($attribute->getAttributeCode(), $value); + } + return $this; + } + + /** + * Set is AJAX Request flag + * + * @param boolean $flag + * @return Mage_Customer_Model_Form + */ + public function setIsAjaxRequest($flag = true) + { + $this->_isAjax = (bool)$flag; + return $this; + } + + /** + * Return is AJAX Request + * + * @return boolean + */ + public function getIsAjaxRequest() + { + return $this->_isAjax; + } + + /** + * Set default attribute values for new entity + * + * @return Mage_Customer_Model_Form + */ + public function initDefaultValues() + { + if (!$this->getEntity()->getId()) { + foreach ($this->getAttributes() as $attribute) { + $default = $attribute->getDefaultValue(); + if ($default != '') { + $this->getEntity()->setData($attribute->getAttributeCode(), $default); + } + } + } + return $this; + } + + /** + * Combined getter/setter whether to omit invisible attributes during rendering/validation + * + * @param $setValue + * @return bool|Mage_Customer_Model_Form + */ + public function ignoreInvisible($setValue = null) + { + if (null !== $setValue) { + $this->_ignoreInvisible = (bool)$setValue; + return $this; + } + return $this->_ignoreInvisible; + } + + /** + * Whether the specified attribute needs to skip rendering/validation + * + * @param Mage_Customer_Model_Attribute $attribute + * @return bool + */ + protected function _isAttributeOmitted($attribute) + { + if ($this->_ignoreInvisible && !$attribute->getIsVisible()) { + return true; + } + return false; + } +} diff --git a/app/code/core/Mage/Customer/controllers/AccountController.php b/app/code/core/Mage/Customer/controllers/AccountController.php index 14763067be..54408e2a61 100644 --- a/app/code/core/Mage/Customer/controllers/AccountController.php +++ b/app/code/core/Mage/Customer/controllers/AccountController.php @@ -168,23 +168,21 @@ protected function _loginPostRedirect() { $session = $this->_getSession(); - if (!$session->getBeforeAuthUrl() || $session->getBeforeAuthUrl() == Mage::getBaseUrl() ) { + if (!$session->getBeforeAuthUrl() || $session->getBeforeAuthUrl() == Mage::getBaseUrl()) { // Set default URL to redirect customer to $session->setBeforeAuthUrl(Mage::helper('customer')->getAccountUrl()); - // Redirect customer to the last page visited after logging in - if ($session->isLoggedIn()) - { + if ($session->isLoggedIn()) { if (!Mage::getStoreConfigFlag('customer/startup/redirect_dashboard')) { - if ($referer = $this->getRequest()->getParam(Mage_Customer_Helper_Data::REFERER_QUERY_PARAM_NAME)) { + $referer = $this->getRequest()->getParam(Mage_Customer_Helper_Data::REFERER_QUERY_PARAM_NAME); + if ($referer) { $referer = Mage::helper('core')->urlDecode($referer); if ($this->_isUrlInternal($referer)) { $session->setBeforeAuthUrl($referer); } } - } - else if ($session->getAfterAuthUrl()) { + } else if ($session->getAfterAuthUrl()) { $session->setBeforeAuthUrl($session->getAfterAuthUrl(true)); } } else { @@ -192,8 +190,7 @@ protected function _loginPostRedirect() } } else if ($session->getBeforeAuthUrl() == Mage::helper('customer')->getLogoutUrl()) { $session->setBeforeAuthUrl(Mage::helper('customer')->getDashboardUrl()); - } - else { + } else { if (!$session->getAfterAuthUrl()) { $session->setAfterAuthUrl($session->getBeforeAuthUrl()); } @@ -257,16 +254,12 @@ public function createPostAction() $customer = Mage::getModel('customer/customer')->setId(null); } - $data = $this->_filterPostData($this->getRequest()->getPost()); + /* @var $customerForm Mage_Customer_Model_Form */ + $customerForm = Mage::getModel('customer/form'); + $customerForm->setFormCode('customer_account_create') + ->setEntity($customer); - foreach (Mage::getConfig()->getFieldset('customer_account') as $code=>$node) { - if ($node->is('create') && isset($data[$code])) { - if ($code == 'email') { - $data[$code] = trim($data[$code]); - } - $customer->setData($code, $data[$code]); - } - } + $customerData = $customerForm->extractData($this->getRequest()); if ($this->getRequest()->getParam('is_subscribed', false)) { $customer->setIsSubscribed(1); @@ -278,24 +271,45 @@ public function createPostAction() $customer->getGroupId(); if ($this->getRequest()->getPost('create_address')) { - $address = Mage::getModel('customer/address') - ->setData($this->getRequest()->getPost()) - ->setIsDefaultBilling($this->getRequest()->getParam('default_billing', false)) - ->setIsDefaultShipping($this->getRequest()->getParam('default_shipping', false)) - ->setId(null); - $customer->addAddress($address); - - $errors = $address->validate(); - if (!is_array($errors)) { - $errors = array(); + /* @var $address Mage_Customer_Model_Address */ + $address = Mage::getModel('customer/address'); + /* @var $addressForm Mage_Customer_Model_Form */ + $addressForm = Mage::getModel('customer/form'); + $addressForm->setFormCode('customer_register_address') + ->setEntity($address); + + $addressData = $addressForm->extractData($this->getRequest(), 'address', false); + $addressErrors = $addressForm->validateData($addressData); + if ($addressErrors === true) { + $address->setId(null) + ->setIsDefaultBilling($this->getRequest()->getParam('default_billing', false)) + ->setIsDefaultShipping($this->getRequest()->getParam('default_shipping', false)); + $addressForm->compactData($addressData); + $customer->addAddress($address); + + $addressErrors = $address->validate(); + if (is_array($addressErrors)) { + $errors = array_merge($errors, $addressErrors); + } + } else { + $errors = array_merge($errors, $addressErrors); } } try { - $validationCustomer = $customer->validate(); - if (is_array($validationCustomer)) { - $errors = array_merge($validationCustomer, $errors); + $customerErrors = $customerForm->validateData($customerData); + if ($customerErrors !== true) { + $errors = array_merge($customerErrors, $errors); + } else { + $customerForm->compactData($customerData); + $customer->setPassword($this->getRequest()->getPost('password')); + $customer->setConfirmation($this->getRequest()->getPost('confirmation')); + $customerErrors = $customer->validate(); + if (is_array($customerErrors)) { + $errors = array_merge($customerErrors, $errors); + } } + $validationResult = count($errors) == 0; if (true === $validationResult) { @@ -306,8 +320,7 @@ public function createPostAction() $session->addSuccess($this->__('Account confirmation is required. Please, check your email for the confirmation link. To resend the confirmation email please click here.', Mage::helper('customer')->getEmailConfirmationUrl($customer->getEmail()))); $this->_redirectSuccess(Mage::getUrl('*/*/index', array('_secure'=>true))); return; - } - else { + } else { $session->setCustomerAsLoggedIn($customer); $url = $this->_welcomeCustomer($customer); $this->_redirectSuccess($url); @@ -319,29 +332,26 @@ public function createPostAction() foreach ($errors as $errorMessage) { $session->addError($errorMessage); } - } - else { + } else { $session->addError($this->__('Invalid customer data')); } } - } - catch (Mage_Core_Exception $e) { + } catch (Mage_Core_Exception $e) { $session->setCustomerFormData($this->getRequest()->getPost()); if ($e->getCode() === Mage_Customer_Model_Customer::EXCEPTION_EMAIL_EXISTS) { $url = Mage::getUrl('customer/account/forgotpassword'); $message = $this->__('There is already an account with this email address. If you are sure that it is your email address, click here to get your password and access your account.', $url); $session->setEscapeMessages(false); - } - else { + } else { $message = $e->getMessage(); } $session->addError($message); - } - catch (Exception $e) { + } catch (Exception $e) { $session->setCustomerFormData($this->getRequest()->getPost()) ->addException($e, $this->__('Cannot save the customer.')); } } + $this->_redirectError(Mage::getUrl('*/*/create', array('_secure' => true))); } @@ -450,15 +460,13 @@ public function confirmationAction() if ($customer->getConfirmation()) { $customer->sendNewAccountEmail('confirmation'); $this->_getSession()->addSuccess($this->__('Please, check your email for confirmation key.')); - } - else { + } else { $this->_getSession()->addSuccess($this->__('This email does not require confirmation.')); } $this->_getSession()->setUsername($email); $this->_redirectSuccess(Mage::getUrl('*/*/index', array('_secure' => true))); - } - catch (Exception $e) { - $this->_getSession()->addError($this->__('Wrong email.')); + } catch (Exception $e) { + $this->_getSession()->addException($e, $this->__('Wrong email.')); $this->_redirectError(Mage::getUrl('*/*/*', array('email' => $email, '_secure' => true))); } return; @@ -521,8 +529,7 @@ public function forgotPasswordPostAction() catch (Exception $e){ $this->_getSession()->addError($e->getMessage()); } - } - else { + } else { $this->_getSession()->addError($this->__('This email address was not found in our records.')); $this->_getSession()->setForgottenEmail($email); } @@ -544,7 +551,8 @@ public function editAction() $this->_initLayoutMessages('customer/session'); $this->_initLayoutMessages('catalog/session'); - if ($block = $this->getLayout()->getBlock('customer_edit')) { + $block = $this->getLayout()->getBlock('customer_edit'); + if ($block) { $block->setRefererUrl($this->_getRefererUrl()); } $data = $this->_getSession()->getCustomerFormData(true); @@ -552,7 +560,7 @@ public function editAction() if (!empty($data)) { $customer->addData($data); } - if($this->getRequest()->getParam('changepass')==1){ + if ($this->getRequest()->getParam('changepass')==1){ $customer->setChangePassword(1); } @@ -571,55 +579,54 @@ public function editPostAction() } if ($this->getRequest()->isPost()) { - $customer = Mage::getModel('customer/customer') - ->setId($this->_getSession()->getCustomerId()) - ->setWebsiteId($this->_getSession()->getCustomer()->getWebsiteId()); + /* @var $customer Mage_Customer_Model_Customer */ + $customer = $this->_getSession()->getCustomer(); - $fields = Mage::getConfig()->getFieldset('customer_account'); - $data = $this->_filterPostData($this->getRequest()->getPost()); + /* @var $customerForm Mage_Customer_Model_Form */ + $customerForm = Mage::getModel('customer/form'); + $customerForm->setFormCode('customer_account_edit') + ->setEntity($customer); - foreach ($fields as $code=>$node) { - if ($node->is('update') && isset($data[$code])) { - $customer->setData($code, $data[$code]); - } - } + $customerData = $customerForm->extractData($this->getRequest()); - $errors = $customer->validate(); - if (!is_array($errors)) { + $errors = array(); + $customerErrors = $customerForm->validateData($customerData); + if ($customerErrors !== true) { + $errors = array_merge($customerErrors, $errors); + } else { + $customerForm->compactData($customerData); $errors = array(); - } - - /** - * we would like to preserver the existing group id - */ - if ($this->_getSession()->getCustomerGroupId()) { - $customer->setGroupId($this->_getSession()->getCustomerGroupId()); - } - if ($this->getRequest()->getParam('change_password')) { - $currPass = $this->getRequest()->getPost('current_password'); - $newPass = $this->getRequest()->getPost('password'); - $confPass = $this->getRequest()->getPost('confirmation'); - - if (empty($currPass) || empty($newPass) || empty($confPass)) { - $errors[] = $this->__('The password fields cannot be empty.'); - } - - if ($newPass != $confPass) { - $errors[] = $this->__('Please make sure your passwords match.'); - } + // If password change was requested then add it to common validation scheme + if ($this->getRequest()->getParam('change_password')) { + $currPass = $this->getRequest()->getPost('current_password'); + $newPass = $this->getRequest()->getPost('password'); + $confPass = $this->getRequest()->getPost('confirmation'); + + $oldPass = $this->_getSession()->getCustomer()->getPasswordHash(); + if (Mage::helper('core/string')->strpos($oldPass, ':')) { + list($_salt, $salt) = explode(':', $oldPass); + } else { + $salt = false; + } - $oldPass = $this->_getSession()->getCustomer()->getPasswordHash(); - if (strpos($oldPass, ':')) { - list($_salt, $salt) = explode(':', $oldPass); - } else { - $salt = false; + if ($customer->hashPassword($currPass, $salt) == $oldPass) { + if (strlen($newPass)) { + // Set entered password and its confirmation - they will be validated later to match each other and be of right length + $customer->setPassword($newPass); + $customer->setConfirmation($confPass); + } else { + $errors[] = $this->__('New password field cannot be empty.'); + } + } else { + $errors[] = $this->__('Invalid current password'); + } } - if ($customer->hashPassword($currPass, $salt) == $oldPass) { - $customer->setPassword($newPass); - } else { - $errors[] = $this->__('Invalid current password'); + // Validate account and compose list of errors if any + $customerErrors = $customer->validate(); + if (is_array($customerErrors)) { + $errors = array_merge($errors, $customerErrors); } } @@ -639,12 +646,10 @@ public function editPostAction() $this->_redirect('customer/account'); return; - } - catch (Mage_Core_Exception $e) { + } catch (Mage_Core_Exception $e) { $this->_getSession()->setCustomerFormData($this->getRequest()->getPost()) ->addError($e->getMessage()); - } - catch (Exception $e) { + } catch (Exception $e) { $this->_getSession()->setCustomerFormData($this->getRequest()->getPost()) ->addException($e, $this->__('Cannot save the customer.')); } diff --git a/app/code/core/Mage/Customer/controllers/AddressController.php b/app/code/core/Mage/Customer/controllers/AddressController.php index e70d117612..c416601f22 100644 --- a/app/code/core/Mage/Customer/controllers/AddressController.php +++ b/app/code/core/Mage/Customer/controllers/AddressController.php @@ -63,12 +63,12 @@ public function indexAction() $this->_initLayoutMessages('customer/session'); $this->_initLayoutMessages('catalog/session'); - if ($block = $this->getLayout()->getBlock('address_book')) { + $block = $this->getLayout()->getBlock('address_book'); + if ($block) { $block->setRefererUrl($this->_getRefererUrl()); } $this->renderLayout(); - } - else { + } else { $this->getResponse()->setRedirect(Mage::getUrl('*/*/new')); } } @@ -90,7 +90,8 @@ public function formAction() { $this->loadLayout(); $this->_initLayoutMessages('customer/session'); - if ($navigationBlock = $this->getLayout()->getBlock('customer_account_navigation')) { + $navigationBlock = $this->getLayout()->getBlock('customer_account_navigation'); + if ($navigationBlock) { $navigationBlock->setActive('customer/address'); } $this->renderLayout(); @@ -103,52 +104,61 @@ public function formPostAction() } // Save data if ($this->getRequest()->isPost()) { - $address = Mage::getModel('customer/address') - ->setData($this->getRequest()->getPost()) - ->setCustomerId(Mage::getSingleton('customer/session')->getCustomerId()) - ->setIsDefaultBilling($this->getRequest()->getParam('default_billing', false)) - ->setIsDefaultShipping($this->getRequest()->getParam('default_shipping', false)); + $customer = $this->_getSession()->getCustomer(); + /* @var $address Mage_Customer_Model_Address */ + $address = Mage::getModel('customer/address'); $addressId = $this->getRequest()->getParam('id'); if ($addressId) { - $customerAddress = $this->_getSession()->getCustomer()->getAddressById($addressId); - if ($customerAddress->getId() && $customerAddress->getCustomerId() == $this->_getSession()->getCustomerId()) { - $address->setId($addressId); - } - else { - $address->setId(null); + $existsAddress = $customer->getAddressById($addressId); + if ($existsAddress->getId() && $existsAddress->getCustomerId() == $customer->getId()) { + $address->setId($existsAddress->getId()); } } - else { - $address->setId(null); + + $errors = array(); + + /* @var $addressForm Mage_Customer_Model_Form */ + $addressForm = Mage::getModel('customer/form'); + $addressForm->setFormCode('customer_address_edit') + ->setEntity($address); + $addressData = $addressForm->extractData($this->getRequest()); + $addressErrors = $addressForm->validateData($addressData); + if ($addressErrors !== true) { + $errors = $addressErrors; } + try { - $accressValidation = $address->validate(); - if (true === $accressValidation) { + $addressForm->compactData($addressData); + $address->setCustomerId($customer->getId()) + ->setIsDefaultBilling($this->getRequest()->getParam('default_billing', false)) + ->setIsDefaultShipping($this->getRequest()->getParam('default_shipping', false)); + + $addressErrors = $address->validate(); + if ($addressErrors !== true) { + $errors = array_merge($errors, $addressErrors); + } + + if (count($errors) === 0) { $address->save(); $this->_getSession()->addSuccess($this->__('The address has been saved.')); $this->_redirectSuccess(Mage::getUrl('*/*/index', array('_secure'=>true))); return; } else { $this->_getSession()->setAddressFormData($this->getRequest()->getPost()); - if (is_array($accressValidation)) { - foreach ($accressValidation as $errorMessage) { - $this->_getSession()->addError($errorMessage); - } - } else { - $this->_getSession()->addError($this->__('Cannot save the address.')); + foreach ($errors as $errorMessage) { + $this->_getSession()->addError($errorMessage); } } - } - catch (Mage_Core_Exception $e) { + } catch (Mage_Core_Exception $e) { $this->_getSession()->setAddressFormData($this->getRequest()->getPost()) ->addException($e, $e->getMessage()); - } - catch (Exception $e) { + } catch (Exception $e) { $this->_getSession()->setAddressFormData($this->getRequest()->getPost()) ->addException($e, $this->__('Cannot save address.')); } } - $this->_redirectError(Mage::getUrl('*/*/edit', array('id'=>$address->getId()))); + + return $this->_redirectError(Mage::getUrl('*/*/edit', array('id' => $address->getId()))); } public function deleteAction() @@ -168,9 +178,8 @@ public function deleteAction() try { $address->delete(); $this->_getSession()->addSuccess($this->__('The address has been deleted.')); - } - catch (Exception $e){ - $this->_getSession()->addError($this->__('An error occurred while deleting the address.')); + } catch (Exception $e){ + $this->_getSession()->addException($e, $this->__('An error occurred while deleting the address.')); } } $this->getResponse()->setRedirect(Mage::getUrl('*/*/index')); diff --git a/app/code/core/Mage/Customer/etc/config.xml b/app/code/core/Mage/Customer/etc/config.xml index 4494f99b87..6e449974a2 100644 --- a/app/code/core/Mage/Customer/etc/config.xml +++ b/app/code/core/Mage/Customer/etc/config.xml @@ -28,7 +28,7 @@ - 1.4.0.0.7 + 1.4.0.0.13 @@ -94,68 +94,24 @@ 11 -
    Text - Text One Line - true - - - HTML true - -{{depend company}}{{var company}}
    {{/depend}} -{{if street1}}{{var street1}}
    {{/if}} -{{depend street2}}{{var street2}}
    {{/depend}} -{{depend street3}}{{var street3}}
    {{/depend}} -{{depend street4}}{{var street4}}
    {{/depend}} -{{if city}}{{var city}}, {{/if}}{{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}
    -{{var country}}
    -{{depend telephone}}T: {{var telephone}}{{/depend}} -{{depend fax}}
    F: {{var fax}}{{/depend}} - ]]>
    PDF - F: {{var fax}}{{/depend}}| - ]]> - Javascript Template - #{company}
    #{street0}
    #{street1}
    #{street2}
    #{street3}
    #{city}, #{region}, #{postcode}
    #{country_id}
    T: #{telephone}
    F: #{fax}]]>
    + JavaScript Template
    @@ -186,6 +142,12 @@ T: {{var telephone}} customer_eav_attribute
    + + customer_eav_attribute_website
    +
    + + customer_form_attribute
    +
    @@ -312,6 +274,42 @@ T: {{var telephone}} 1 + + + + +{{depend company}}{{var company}}
    {{/depend}} +{{if street1}}{{var street1}}
    {{/if}} +{{depend street2}}{{var street2}}
    {{/depend}} +{{depend street3}}{{var street3}}
    {{/depend}} +{{depend street4}}{{var street4}}
    {{/depend}} +{{if city}}{{var city}}, {{/if}}{{if region}}{{var region}}, {{/if}}{{if postcode}}{{var postcode}}{{/if}}
    +{{var country}}
    +{{depend telephone}}T: {{var telephone}}{{/depend}} +{{depend fax}}
    F: {{var fax}}{{/depend}}]]> + F: {{var fax}}{{/depend}}|]]> + #{company}
    #{street0}
    #{street1}
    #{street2}
    #{street3}
    #{city}, #{region}, #{postcode}
    #{country_id}
    T: #{telephone}
    F: #{fax}]]>
    +
    diff --git a/app/code/core/Mage/Customer/etc/system.xml b/app/code/core/Mage/Customer/etc/system.xml index a4b85ea61e..e00ded1a2a 100644 --- a/app/code/core/Mage/Customer/etc/system.xml +++ b/app/code/core/Mage/Customer/etc/system.xml @@ -203,6 +203,7 @@ 1 1 0 + adminhtml/system_config_backend_customer_address_street Leave empty for default (2). Valid range: 1-4 @@ -210,6 +211,7 @@ select adminhtml/system_config_source_nooptreq 20 + adminhtml/system_config_backend_customer_show_address The title that goes before name (Mr., Mrs., etc.) 1 1 @@ -228,6 +230,7 @@ select adminhtml/system_config_source_yesno Always optional. + adminhtml/system_config_backend_customer_show_address 40 1 1 @@ -238,6 +241,7 @@ select adminhtml/system_config_source_nooptreq The suffix that goes after name (Jr., Sr., etc.) + adminhtml/system_config_backend_customer_show_address 50 1 1 @@ -256,6 +260,7 @@ select adminhtml/system_config_source_nooptreq 70 + adminhtml/system_config_backend_customer_show_customer 1 1 0 @@ -264,6 +269,7 @@ select adminhtml/system_config_source_nooptreq + adminhtml/system_config_backend_customer_show_customer 80 1 1 @@ -273,6 +279,7 @@ select adminhtml/system_config_source_nooptreq + adminhtml/system_config_backend_customer_show_customer 90 1 1 @@ -299,6 +306,56 @@ + + + text + 100 + 1 + 1 + 1 + + + + textarea + 1 + 1 + 1 + 1 + + + + textarea + 2 + 1 + 1 + 1 + + + + textarea + 3 + 1 + 1 + 1 + + + + textarea + 4 + 1 + 1 + 1 + + + + textarea + 5 + 1 + 1 + 1 + + + diff --git a/app/code/core/Mage/Customer/etc/wsdl.xml b/app/code/core/Mage/Customer/etc/wsdl.xml index a02542d8fb..133b887639 100644 --- a/app/code/core/Mage/Customer/etc/wsdl.xml +++ b/app/code/core/Mage/Customer/etc/wsdl.xml @@ -7,6 +7,7 @@ + @@ -27,8 +28,14 @@ + + + + + + diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.11-1.4.0.0.12.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.11-1.4.0.0.12.php new file mode 100644 index 0000000000..6fe926dad4 --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.11-1.4.0.0.12.php @@ -0,0 +1,43 @@ +getAttribute('customer_address', $attributeCode); + $usedInForms = $attribute->getUsedInForms(); + if (!in_array('customer_register_address', $usedInForms)) { + $usedInForms[] = 'customer_register_address'; + $attribute->setData('used_in_forms', $usedInForms); + $attribute->save(); + } +} diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.7-1.4.0.0.8.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.7-1.4.0.0.8.php new file mode 100644 index 0000000000..b543390d37 --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.7-1.4.0.0.8.php @@ -0,0 +1,351 @@ +getStore(Mage_Core_Model_App::ADMIN_STORE_ID); + +/* @var $eavConfig Mage_Eav_Model_Config */ +$eavConfig = Mage::getSingleton('eav/config'); + +// update customer system attributes data +$attributes = array( + 'confirmation' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 0, + 'sort_order' => 0 + ), + 'default_billing' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 0, + 'sort_order' => 0 + ), + 'default_shipping' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 0, + 'sort_order' => 0 + ), + 'password_hash' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 0, + 'sort_order' => 0 + ), + 'website_id' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 10, + 'adminhtml_only' => 1 + ), + 'created_in' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 20, + 'is_required' => 0, + 'adminhtml_only' => 1 + ), + 'store_id' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 0, + 'sort_order' => 0 + ), + 'group_id' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 25, + 'adminhtml_only' => 1, + 'admin_checkout' => 1 + ), + 'prefix' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('prefix_show', $store) == '' ? 0 : 1, + 'sort_order' => 30, + 'is_required' => $addressHelper->getConfig('prefix_show', $store) == 'req' ? 1 : 0 + ), + 'firstname' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 40, + 'is_required' => 1, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'middlename' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('middlename_show', $store) == '' ? 0 : 1, + 'sort_order' => 50, + 'is_required' => $addressHelper->getConfig('middlename_show', $store) == 'req' ? 1 : 0 + ), + 'lastname' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 60, + 'is_required' => 1, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'suffix' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('suffix_show', $store) == '' ? 0 : 1, + 'sort_order' => 70, + 'is_required' => $addressHelper->getConfig('suffix_show', $store) == 'req' ? 1 : 0 + ), + 'email' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 80, + 'is_required' => 1, + 'validate_rules' => array( + 'input_validation' => 'email' + ), + 'admin_checkout' => 1 + ), + 'dob' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('dob_show', $store) == '' ? 0 : 1, + 'sort_order' => 90, + 'is_required' => $addressHelper->getConfig('dob_show', $store) == 'req' ? 1 : 0, + 'validate_rules' => array( + 'input_validation' => 'date' + ), + 'input_filter' => 'date', + 'admin_checkout' => 1 + ), + 'taxvat' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('dob_show', $store) == '' ? 0 : 1, + 'sort_order' => 100, + 'is_required' => $addressHelper->getConfig('dob_show', $store) == 'req' ? 1 : 0, + 'validate_rules' => array( + 'max_text_length' => 255, + ), + 'admin_checkout' => 1 + ), + 'gender' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('gender_show', $store) == '' ? 0 : 1, + 'sort_order' => 110, + 'is_required' => $addressHelper->getConfig('gender_show', $store) == 'req' ? 1 : 0, + 'validate_rules' => array(), + 'admin_checkout' => 1 + ), +); + +foreach ($attributes as $attributeCode => $data) { + $attribute = $eavConfig->getAttribute('customer', $attributeCode); + $attribute->setWebsite($store->getWebsite()); + $attribute->addData($data); + if (false === ($data['is_system'] == 1 && $data['is_visible'] == 0)) { + $usedInForms = array( + 'customer_account_create', + 'customer_account_edit', + 'checkout_register', + ); + if (!empty($data['adminhtml_only'])) { + $usedInForms = array('adminhtml_customer'); + } else { + $usedInForms[] = 'adminhtml_customer'; + } + if (!empty($data['admin_checkout'])) { + $usedInForms[] = 'adminhtml_checkout'; + } + + $attribute->setData('used_in_forms', $usedInForms); + } + $attribute->save(); +} + +// update customer address system attributes data +$attributes = array( + 'prefix' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('prefix_show', $store) == '' ? 0 : 1, + 'sort_order' => 10, + 'is_required' => $addressHelper->getConfig('prefix_show', $store) == 'req' ? 1 : 0, + ), + 'firstname' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 20, + 'is_required' => 1, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'middlename' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('middlename_show', $store) == '' ? 0 : 1, + 'sort_order' => 30, + 'is_required' => $addressHelper->getConfig('middlename_show', $store) == 'req' ? 1 : 0, + ), + 'lastname' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 40, + 'is_required' => 1, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'suffix' => array( + 'is_user_defined' => 0, + 'is_system' => 0, + 'is_visible' => $addressHelper->getConfig('suffix_show', $store) == '' ? 0 : 1, + 'sort_order' => 50, + 'is_required' => $addressHelper->getConfig('suffix_show', $store) == 'req' ? 1 : 0, + ), + 'company' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 60, + 'is_required' => 0, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'street' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 70, + 'multiline_count' => $addressHelper->getConfig('street_lines', $store), + 'is_required' => 1, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'city' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 80, + 'is_required' => 1, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'country_id' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 90, + 'is_required' => 1, + ), + 'region' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 100, + 'is_required' => 0, + ), + 'region_id' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 100, + 'is_required' => 0, + ), + 'postcode' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 110, + 'is_required' => 1, + 'validate_rules' => array( + ), + ), + 'telephone' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 120, + 'is_required' => 1, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), + 'fax' => array( + 'is_user_defined' => 0, + 'is_system' => 1, + 'is_visible' => 1, + 'sort_order' => 130, + 'is_required' => 0, + 'validate_rules' => array( + 'max_text_length' => 255, + 'min_text_length' => 1 + ), + ), +); + +foreach ($attributes as $attributeCode => $data) { + $attribute = $eavConfig->getAttribute('customer_address', $attributeCode); + $attribute->setWebsite($store->getWebsite()); + $attribute->addData($data); + if (false === ($data['is_system'] == 1 && $data['is_visible'] == 0)) { + $usedInForms = array( + 'adminhtml_customer_address', + 'customer_address_edit', + 'customer_register_address' + ); + $attribute->setData('used_in_forms', $usedInForms); + } + $attribute->save(); +} diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.8-1.4.0.0.9.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.8-1.4.0.0.9.php new file mode 100644 index 0000000000..8197c07567 --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-data-upgrade-1.4.0.0.8-1.4.0.0.9.php @@ -0,0 +1,119 @@ +getWebsites(false); +foreach ($websites as $website) { + /* @var $website Mage_Core_Model_Website */ + $store = $website->getDefaultStore(); + if (!$store) { + continue; + } + + // customer attributes + $attributes = array( + 'prefix', + 'middlename', + 'suffix', + 'dob', + 'taxvat', + 'gender' + ); + + foreach ($attributes as $attributeCode) { + $attribute = $eavConfig->getAttribute('customer', $attributeCode); + $configValue = $addressHelper->getConfig($attributeCode . '_show', $store); + $isVisible = $attribute->getData('is_visible'); + $isRequired = $attribute->getData('is_required'); + + if ($configValue == 'opt' || $configValue == '1') { + $scopeIsVisible = '1'; + $scopeIsRequired = '0'; + } else if ($configValue == 'req') { + $scopeIsVisible = '1'; + $scopeIsRequired = '1'; + } else { + $scopeIsVisible = '0'; + $scopeIsRequired = '0'; + } + + if ($isVisible != $scopeIsVisible || $isRequired != $scopeIsRequired) { + $attribute->setWebsite($website); + $attribute->setScopeIsVisible($scopeIsVisible); + $attribute->setScopeIsRequired($scopeIsRequired); + $attribute->save(); + } + } + + // customer address attributes + $attributes = array( + 'prefix', + 'middlename', + 'suffix', + ); + + foreach ($attributes as $attributeCode) { + $attribute = $eavConfig->getAttribute('customer_address', $attributeCode); + $configValue = $addressHelper->getConfig($attributeCode . '_show', $store); + $isVisible = $attribute->getData('is_visible'); + $isRequired = $attribute->getData('is_required'); + + if ($configValue == 'opt' || $configValue == '1') { + $scopeIsVisible = '1'; + $scopeIsRequired = '0'; + } else if ($configValue == 'req') { + $scopeIsVisible = '1'; + $scopeIsRequired = '1'; + } else { + $scopeIsVisible = '0'; + $scopeIsRequired = '0'; + } + + if ($isVisible != $scopeIsVisible || $isRequired != $scopeIsRequired) { + $attribute->setWebsite($website); + $attribute->setScopeIsVisible($scopeIsVisible); + $attribute->setScopeIsRequired($scopeIsRequired); + $attribute->save(); + } + } + + $attribute = $eavConfig->getAttribute('customer_address', 'street'); + $value = $addressHelper->getConfig('street_lines', $store); + if ($attribute->getData('multiline_count') != $value) { + $attribute->setWebsite($website); + $attribute->setScopeMultilineCount($value); + $attribute->save(); + } +} diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.10-1.4.0.0.11.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.10-1.4.0.0.11.php new file mode 100644 index 0000000000..9d65766fcc --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.10-1.4.0.0.11.php @@ -0,0 +1,34 @@ +getConnection()->addColumn($installer->getTable('customer/eav_attribute'), 'data_model', + 'varchar(255) default NULL'); + +$installer->updateAttribute('customer_address', 'postcode', 'data_model', 'customer/attribute_data_postcode'); diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.12-1.4.0.0.13.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.12-1.4.0.0.13.php new file mode 100644 index 0000000000..671ce3771b --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.12-1.4.0.0.13.php @@ -0,0 +1,50 @@ +startSetup(); + +$installer->getConnection()->dropForeignKey( + $installer->getTable('customer_eav_attribute_website'), + 'FK_CUSTOMER_EAV_ATTRIBUTE_WEBSITE_ATTRIBUTE_EAV_ATTRIBUTE' +); +$installer->getConnection()->dropForeignKey( + $installer->getTable('customer_eav_attribute_website'), + 'FK_CUSTOMER_EAV_ATTRIBUTE_WEBSITE_WEBSITE_CORE_WEBSITE' +); + +$installer->getConnection()->addConstraint('FK_CUST_EAV_ATTR_WEBST_ATTR_EAV_ATTR', + $installer->getTable('customer_eav_attribute_website'), 'attribute_id', + $installer->getTable('eav_attribute'), 'attribute_id' +); +$installer->getConnection()->addConstraint('FK_CUST_EAV_ATTR_WEBST_WEBST_CORE_WEBST', + $installer->getTable('customer_eav_attribute_website'), 'website_id', + $installer->getTable('core_website'), 'website_id' +); + +$installer->endSetup(); diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.7-1.4.0.0.8.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.7-1.4.0.0.8.php new file mode 100644 index 0000000000..0cd85540a9 --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.7-1.4.0.0.8.php @@ -0,0 +1,56 @@ +run(" +CREATE TABLE `{$installer->getTable('customer/form_attribute')}` ( + `form_code` char(32) NOT NULL, + `attribute_id` smallint UNSIGNED NOT NULL, + PRIMARY KEY(`form_code`, `attribute_id`), + KEY `IDX_CUSTOMER_FORM_ATTRIBUTE_ATTRIBUTE` (`attribute_id`), + CONSTRAINT `FK_CUSTOMER_FORM_ATTRIBUTE_ATTRIBUTE` FOREIGN KEY (`attribute_id`) REFERENCES `{$installer->getTable('eav_attribute')}` (`attribute_id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Customer attributes/forms relations'; +"); + +$installer->getConnection()->dropColumn($installer->getTable('customer/eav_attribute'), 'is_visible_on_front'); +$installer->getConnection()->changeColumn($installer->getTable('customer/eav_attribute'), 'lines_to_divide_multiline', + 'multiline_count', 'TINYINT UNSIGNED NOT NULL DEFAULT 1'); +$installer->getConnection()->dropColumn($installer->getTable('customer/eav_attribute'), 'min_text_length'); +$installer->getConnection()->dropColumn($installer->getTable('customer/eav_attribute'), 'max_text_length'); +$installer->getConnection()->modifyColumn($installer->getTable('customer/eav_attribute'), 'input_filter', + 'varchar(255) DEFAULT NULL'); +$installer->getConnection()->addColumn($installer->getTable('customer/eav_attribute'), 'validate_rules', + 'text DEFAULT NULL'); +$installer->getConnection()->addColumn($installer->getTable('customer/eav_attribute'), 'is_system', + 'TINYINT UNSIGNED NOT NULL DEFAULT 0'); +$installer->getConnection()->addColumn($installer->getTable('customer/eav_attribute'), 'sort_order', + 'INT UNSIGNED NOT NULL DEFAULT 0'); + +$installer->updateEntityType('customer', 'attribute_model', 'customer/attribute'); +$installer->updateEntityType('customer_address', 'attribute_model', 'customer/attribute'); diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.8-1.4.0.0.9.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.8-1.4.0.0.9.php new file mode 100644 index 0000000000..a58e39d182 --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.8-1.4.0.0.9.php @@ -0,0 +1,48 @@ +startSetup(); +$installer->run(" +CREATE TABLE `{$installer->getTable('customer/eav_attribute_website')}` ( + `attribute_id` smallint(5) unsigned NOT NULL, + `website_id` smallint(5) unsigned NOT NULL, + `is_visible` tinyint(1) unsigned DEFAULT NULL, + `is_required` tinyint(1) unsigned DEFAULT NULL, + `default_value` text, + `multiline_count` tinyint(3) unsigned DEFAULT NULL, + PRIMARY KEY (`attribute_id`, `website_id`), + KEY `IDX_WEBSITE` (`website_id`), + CONSTRAINT `FK_CUSTOMER_EAV_ATTRIBUTE_WEBSITE_ATTRIBUTE_EAV_ATTRIBUTE` FOREIGN KEY (`attribute_id`) + REFERENCES `{$installer->getTable('eav/attribute')}` (`attribute_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `FK_CUSTOMER_EAV_ATTRIBUTE_WEBSITE_WEBSITE_CORE_WEBSITE` FOREIGN KEY (`website_id`) + REFERENCES `{$installer->getTable('core/website')}` (`website_id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +"); +$installer->endSetup(); diff --git a/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.9-1.4.0.0.10.php b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.9-1.4.0.0.10.php new file mode 100644 index 0000000000..6ce087d0c3 --- /dev/null +++ b/app/code/core/Mage/Customer/sql/customer_setup/mysql4-upgrade-1.4.0.0.9-1.4.0.0.10.php @@ -0,0 +1,32 @@ +updateEntityType('customer', 'entity_attribute_collection', 'customer/attribute_collection'); +$installer->updateEntityType('customer_address', 'entity_attribute_collection', 'customer/address_attribute_collection'); diff --git a/app/code/core/Mage/Dataflow/Model/Profile.php b/app/code/core/Mage/Dataflow/Model/Profile.php index 3f68e0a23b..6bf7a03efc 100644 --- a/app/code/core/Mage/Dataflow/Model/Profile.php +++ b/app/code/core/Mage/Dataflow/Model/Profile.php @@ -109,6 +109,15 @@ protected function _afterSave() rename($path.$uploadFile, $path.$newFilename); } } + //BOM deleting for UTF files + if (isset($newFilename) && $newFilename) { + $contents = file_get_contents($path.$newFilename); + if (ord($contents[0]) == 0xEF && ord($contents[1]) == 0xBB && ord($contents[2]) == 0xBF) { + $contents = substr($contents, 3); + file_put_contents($path.$newFilename, $contents); + } + unset($contents); + } } } parent::_afterSave(); diff --git a/app/code/core/Mage/Dataflow/etc/config.xml b/app/code/core/Mage/Dataflow/etc/config.xml index bcd4af6314..cd878be0f4 100644 --- a/app/code/core/Mage/Dataflow/etc/config.xml +++ b/app/code/core/Mage/Dataflow/etc/config.xml @@ -72,4 +72,13 @@ + + + + + dataflow.xml + + + +
    diff --git a/app/code/core/Mage/Directory/etc/config.xml b/app/code/core/Mage/Directory/etc/config.xml index 13a3042563..ba29413c68 100644 --- a/app/code/core/Mage/Directory/etc/config.xml +++ b/app/code/core/Mage/Directory/etc/config.xml @@ -28,7 +28,7 @@ - 0.8.10 + 0.8.11 diff --git a/app/code/core/Mage/Directory/sql/directory_setup/mysql4-upgrade-0.8.10-0.8.11.php b/app/code/core/Mage/Directory/sql/directory_setup/mysql4-upgrade-0.8.10-0.8.11.php new file mode 100644 index 0000000000..c281a6af60 --- /dev/null +++ b/app/code/core/Mage/Directory/sql/directory_setup/mysql4-upgrade-0.8.10-0.8.11.php @@ -0,0 +1,219 @@ +getConnection(); + +$regionTable = $installer->getTable('directory/country_region'); + +$regionsToIns = array( + //After reform of 2010 January + array('FI', 'Lappi', 'Lappi'), + array('FI', 'Pohjois-Pohjanmaa', 'Pohjois-Pohjanmaa'), + array('FI', 'Kainuu', 'Kainuu'), + array('FI', 'Pohjois-Karjala', 'Pohjois-Karjala'), + array('FI', 'Pohjois-Savo', 'Pohjois-Savo'), + array('FI', 'Etelä-Savo', 'Etelä-Savo'), + array('FI', 'Etelä-Pohjanmaa', 'Etelä-Pohjanmaa'), + array('FI', 'Pohjanmaa', 'Pohjanmaa'), + array('FI', 'Pirkanmaa', 'Pirkanmaa'), + array('FI', 'Satakunta', 'Satakunta'), + array('FI', 'Keski-Pohjanmaa', 'Keski-Pohjanmaa'), + array('FI', 'Keski-Suomi', 'Keski-Suomi'), + array('FI', 'Varsinais-Suomi', 'Varsinais-Suomi'), + array('FI', 'Etelä-Karjala', 'Etelä-Karjala'), + array('FI', 'Päijät-Häme', 'Päijät-Häme'), + array('FI', 'Kanta-Häme', 'Kanta-Häme'), + array('FI', 'Uusimaa', 'Uusimaa'), + array('FI', 'Itä-Uusimaa', 'Itä-Uusimaa'), + array('FI', 'Kymenlaakso', 'Kymenlaakso'), + array('FI', 'Ahvenanmaa', 'Ahvenanmaa'), + + //ISO-3166-2:EE + array('EE', 'EE-37', 'Harjumaa'), + array('EE', 'EE-39', 'Hiiumaa'), + array('EE', 'EE-44', 'Ida-Virumaa'), + array('EE', 'EE-49', 'Jõgevamaa'), + array('EE', 'EE-51', 'Järvamaa'), + array('EE', 'EE-57', 'Läänemaa'), + array('EE', 'EE-59', 'Lääne-Virumaa'), + array('EE', 'EE-65', 'Põlvamaa'), + array('EE', 'EE-67', 'Pärnumaa'), + array('EE', 'EE-70', 'Raplamaa'), + array('EE', 'EE-74', 'Saaremaa'), + array('EE', 'EE-78', 'Tartumaa'), + array('EE', 'EE-82', 'Valgamaa'), + array('EE', 'EE-84', 'Viljandimaa'), + array('EE', 'EE-86', 'Võrumaa'), + + //After reform of 2009 July + array('LV', 'LV-DGV', 'Daugavpils'),//now become good + array('LV', 'LV-JEL', 'Jelgava'), + array('LV', 'JÄ“kabpils', 'JÄ“kabpils'), + array('LV', 'LV-JUR', 'JÅ«rmala'), + array('LV', 'LV-LPX', 'LiepÄja'), + array('LV', 'LV-LE', 'LiepÄjas novads'), + array('LV', 'LV-REZ', 'RÄ“zekne'), + array('LV', 'LV-RIX', 'RÄ«ga'), + array('LV', 'LV-RI', 'RÄ«gas novads'), + array('LV', 'Valmiera', 'Valmiera'), + array('LV', 'LV-VEN', 'Ventspils'), + array('LV', 'Aglonas novads', 'Aglonas novads'), + array('LV', 'LV-AI', 'Aizkraukles novads'), + array('LV', 'Aizputes novads', 'Aizputes novads'), + array('LV', 'AknÄ«stes novads', 'AknÄ«stes novads'), + array('LV', 'Alojas novads', 'Alojas novads'), + array('LV', 'Alsungas novads', 'Alsungas novads'), + array('LV', 'LV-AL', 'AlÅ«ksnes novads'), + array('LV', 'Amatas novads', 'Amatas novads'), + array('LV', 'Apes novads', 'Apes novads'), + array('LV', 'Auces novads', 'Auces novads'), + array('LV', 'BabÄ«tes novads', 'BabÄ«tes novads'), + array('LV', 'Baldones novads', 'Baldones novads'), + array('LV', 'Baltinavas novads', 'Baltinavas novads'), + array('LV', 'LV-BL', 'Balvu novads'), + array('LV', 'LV-BU', 'Bauskas novads'), + array('LV', 'BeverÄ«nas novads', 'BeverÄ«nas novads'), + array('LV', 'BrocÄ“nu novads', 'BrocÄ“nu novads'), + array('LV', 'Burtnieku novads', 'Burtnieku novads'), + array('LV', 'Carnikavas novads', 'Carnikavas novads'), + array('LV', 'Cesvaines novads', 'Cesvaines novads'), + array('LV', 'Ciblas novads', 'Ciblas novads'), + array('LV', 'LV-CE', 'CÄ“su novads'), + array('LV', 'Dagdas novads', 'Dagdas novads'), + array('LV', 'LV-DA', 'Daugavpils novads'), + array('LV', 'LV-DO', 'Dobeles novads'), + array('LV', 'Dundagas novads', 'Dundagas novads'), + array('LV', 'Durbes novads', 'Durbes novads'), + array('LV', 'Engures novads', 'Engures novads'), + array('LV', 'Garkalnes novads', 'Garkalnes novads'), + array('LV', 'Grobiņas novads', 'Grobiņas novads'), + array('LV', 'LV-GU', 'Gulbenes novads'), + array('LV', 'Iecavas novads', 'Iecavas novads'), + array('LV', 'IkÅ¡Ä·iles novads', 'IkÅ¡Ä·iles novads'), + array('LV', 'IlÅ«kstes novads', 'IlÅ«kstes novads'), + array('LV', 'InÄukalna novads', 'InÄukalna novads'), + array('LV', 'Jaunjelgavas novads', 'Jaunjelgavas novads'), + array('LV', 'Jaunpiebalgas novads', 'Jaunpiebalgas novads'), + array('LV', 'Jaunpils novads', 'Jaunpils novads'), + array('LV', 'LV-JL', 'Jelgavas novads'), + array('LV', 'LV-JK', 'JÄ“kabpils novads'), + array('LV', 'Kandavas novads', 'Kandavas novads'), + array('LV', 'Kokneses novads', 'Kokneses novads'), + array('LV', 'Krimuldas novads', 'Krimuldas novads'), + array('LV', 'Krustpils novads', 'Krustpils novads'), + array('LV', 'LV-KR', 'KrÄslavas novads'), + array('LV', 'LV-KU', 'KuldÄ«gas novads'), + array('LV', 'KÄrsavas novads', 'KÄrsavas novads'), + array('LV', 'LielvÄrdes novads', 'LielvÄrdes novads'), + array('LV', 'LV-LM', 'Limbažu novads'), + array('LV', 'LubÄnas novads', 'LubÄnas novads'), + array('LV', 'LV-LU', 'Ludzas novads'), + array('LV', 'LÄ«gatnes novads', 'LÄ«gatnes novads'), + array('LV', 'LÄ«vÄnu novads', 'LÄ«vÄnu novads'), + array('LV', 'LV-MA', 'Madonas novads'), + array('LV', 'Mazsalacas novads', 'Mazsalacas novads'), + array('LV', 'MÄlpils novads', 'MÄlpils novads'), + array('LV', 'MÄrupes novads', 'MÄrupes novads'), + array('LV', 'NaukÅ¡Ä“nu novads', 'NaukÅ¡Ä“nu novads'), + array('LV', 'Neretas novads', 'Neretas novads'), + array('LV', 'NÄ«cas novads', 'NÄ«cas novads'), + array('LV', 'LV-OG', 'Ogres novads'), + array('LV', 'Olaines novads', 'Olaines novads'), + array('LV', 'Ozolnieku novads', 'Ozolnieku novads'), + array('LV', 'LV-PR', 'Preiļu novads'), + array('LV', 'Priekules novads', 'Priekules novads'), + array('LV', 'Priekuļu novads', 'Priekuļu novads'), + array('LV', 'PÄrgaujas novads', 'PÄrgaujas novads'), + array('LV', 'PÄvilostas novads', 'PÄvilostas novads'), + array('LV', 'Pļaviņu novads', 'Pļaviņu novads'), + array('LV', 'Raunas novads', 'Raunas novads'), + array('LV', 'Riebiņu novads', 'Riebiņu novads'), + array('LV', 'Rojas novads', 'Rojas novads'), + array('LV', 'Ropažu novads', 'Ropažu novads'), + array('LV', 'Rucavas novads', 'Rucavas novads'), + array('LV', 'RugÄju novads', 'RugÄju novads'), + array('LV', 'RundÄles novads', 'RundÄles novads'), + array('LV', 'LV-RE', 'RÄ“zeknes novads'), + array('LV', 'RÅ«jienas novads', 'RÅ«jienas novads'), + array('LV', 'SalacgrÄ«vas novads', 'SalacgrÄ«vas novads'), + array('LV', 'Salas novads', 'Salas novads'), + array('LV', 'Salaspils novads', 'Salaspils novads'), + array('LV', 'LV-SA', 'Saldus novads'), + array('LV', 'Saulkrastu novads', 'Saulkrastu novads'), + array('LV', 'Siguldas novads', 'Siguldas novads'), + array('LV', 'Skrundas novads', 'Skrundas novads'), + array('LV', 'SkrÄ«veru novads', 'SkrÄ«veru novads'), + array('LV', 'Smiltenes novads', 'Smiltenes novads'), + array('LV', 'Stopiņu novads', 'Stopiņu novads'), + array('LV', 'StrenÄu novads', 'StrenÄu novads'), + array('LV', 'SÄ“jas novads', 'SÄ“jas novads'), + array('LV', 'LV-TA', 'Talsu novads'), + array('LV', 'LV-TU', 'Tukuma novads'), + array('LV', 'TÄ“rvetes novads', 'TÄ“rvetes novads'), + array('LV', 'Vaiņodes novads', 'Vaiņodes novads'), + array('LV', 'LV-VK', 'Valkas novads'), + array('LV', 'LV-VM', 'Valmieras novads'), + array('LV', 'VarakļÄnu novads', 'VarakļÄnu novads'), + array('LV', 'Vecpiebalgas novads', 'Vecpiebalgas novads'), + array('LV', 'Vecumnieku novads', 'Vecumnieku novads'), + array('LV', 'LV-VE', 'Ventspils novads'), + array('LV', 'ViesÄ«tes novads', 'ViesÄ«tes novads'), + array('LV', 'Viļakas novads', 'Viļakas novads'), + array('LV', 'ViļÄnu novads', 'ViļÄnu novads'), + array('LV', 'VÄrkavas novads', 'VÄrkavas novads'), + array('LV', 'Zilupes novads', 'Zilupes novads'), + array('LV', 'Ä€dažu novads', 'Ä€dažu novads'), + array('LV', 'Ä’rgļu novads', 'Ä’rgļu novads'), + array('LV', 'Ķeguma novads', 'Ķeguma novads'), + array('LV', 'Ķekavas novads', 'Ķekavas novads'), + + //ISO-3166-2:LT + array('LT', 'LT-AL', 'Alytaus Apskritis'), + array('LT', 'LT-KU', 'Kauno Apskritis'), + array('LT', 'LT-KL', 'KlaipÄ—dos Apskritis'), + array('LT', 'LT-MR', 'MarijampolÄ—s Apskritis'), + array('LT', 'LT-PN', 'Panevėžio Apskritis'), + array('LT', 'LT-SA', 'Å iaulių Apskritis'), + array('LT', 'LT-TA', 'TauragÄ—s Apskritis'), + array('LT', 'LT-TE', 'TelÅ¡ių Apskritis'), + array('LT', 'LT-UT', 'Utenos Apskritis'), + array('LT', 'LT-VL', 'Vilniaus Apskritis'), +); + +foreach ($regionsToIns as $row) { + if (! ($connection->fetchOne("SELECT 1 FROM `{$regionTable}` WHERE `country_id` = :country_id && `code` = :code", array('country_id' => $row[0], 'code' => $row[1])))) { + $connection->insert($regionTable, array( + 'country_id' => $row[0], + 'code' => $row[1], + 'default_name' => $row[2] + )); + } +} + 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 177bac7617..43899bfd1c 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 @@ -126,7 +126,7 @@ public function getLinksTitle() */ public function getUsedDefault() { - return is_null($this->getProduct()->getAttributeDefaultValue('links_title')); + return $this->getProduct()->getAttributeDefaultValue('links_title') === false; } /** diff --git a/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Samples.php b/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Samples.php index 85755a1925..9ee24d6565 100644 --- a/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Samples.php +++ b/app/code/core/Mage/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/Samples.php @@ -125,7 +125,7 @@ public function getSampleData() */ public function getUsedDefault() { - return is_null($this->getProduct()->getAttributeDefaultValue('samples_title')); + return $this->getProduct()->getAttributeDefaultValue('samples_title') === false; } /** diff --git a/app/code/core/Mage/Downloadable/Model/Mysql4/Sample.php b/app/code/core/Mage/Downloadable/Model/Mysql4/Sample.php index 39c5ce04ac..f0348f3fe1 100644 --- a/app/code/core/Mage/Downloadable/Model/Mysql4/Sample.php +++ b/app/code/core/Mage/Downloadable/Model/Mysql4/Sample.php @@ -87,20 +87,21 @@ public function saveItemTitle($sampleObject) */ public function deleteItems($items) { + $adapter = $this->_getWriteAdapter(); $where = ''; if ($items instanceof Mage_Downloadable_Model_Sample) { - $where = $this->_getReadAdapter()->quoteInto('sample_id = ?', $items->getId()); + $where = $adapter->quoteInto('sample_id = ?', $items->getId()); } elseif (is_array($items)) { - $where = $this->_getReadAdapter()->quoteInto('sample_id in (?)', $items); + $where = $adapter->quoteInto('sample_id in (?)', $items); } else { - $where = $this->_getReadAdapter()->quoteInto('sample_id = ?', $items); + $where = $adapter->quoteInto('sample_id = ?', $items); } if ($where) { - $this->_getReadAdapter()->delete( + $adapter->delete( $this->getTable('downloadable/sample'),$where); - $this->_getReadAdapter()->delete( + $adapter->delete( $this->getTable('downloadable/sample_title'), $where); } return $this; diff --git a/app/code/core/Mage/Downloadable/Model/Product/Type.php b/app/code/core/Mage/Downloadable/Model/Product/Type.php index e8810a25b2..1ebe384c83 100644 --- a/app/code/core/Mage/Downloadable/Model/Product/Type.php +++ b/app/code/core/Mage/Downloadable/Model/Product/Type.php @@ -287,7 +287,10 @@ public function prepareForCart(Varien_Object $buyRequest, $product = null) return $result; } // if adding product from admin area we add all links to product + $originalLinksPurchasedSeparately = null; if ($this->getProduct($product)->getSkipCheckRequiredOption()) { + $originalLinksPurchasedSeparately = $this->getProduct($product) + ->getLinksPurchasedSeparately(); $this->getProduct($product)->setLinksPurchasedSeparately(false); } $preparedLinks = array(); @@ -304,6 +307,10 @@ public function prepareForCart(Varien_Object $buyRequest, $product = null) $preparedLinks[] = $link->getId(); } } + if (null !== $originalLinksPurchasedSeparately) { + $this->getProduct($product) + ->setLinksPurchasedSeparately($originalLinksPurchasedSeparately); + } if ($preparedLinks) { $this->getProduct($product)->addCustomOption('downloadable_link_ids', implode(',', $preparedLinks)); return $result; diff --git a/app/code/core/Mage/Downloadable/controllers/CustomerController.php b/app/code/core/Mage/Downloadable/controllers/CustomerController.php index 652e703cc0..3135b09fd1 100644 --- a/app/code/core/Mage/Downloadable/controllers/CustomerController.php +++ b/app/code/core/Mage/Downloadable/controllers/CustomerController.php @@ -59,6 +59,10 @@ public function productsAction() if ($block = $this->getLayout()->getBlock('downloadable_customer_products_list')) { $block->setRefererUrl($this->_getRefererUrl()); } + $headBlock = $this->getLayout()->getBlock('head'); + if ($headBlock) { + $headBlock->setTitle(Mage::helper('downloadable')->__('My Downloadable Products')); + } $this->renderLayout(); } diff --git a/app/code/core/Mage/Downloadable/etc/config.xml b/app/code/core/Mage/Downloadable/etc/config.xml index b0e0e5981b..41e03535b4 100644 --- a/app/code/core/Mage/Downloadable/etc/config.xml +++ b/app/code/core/Mage/Downloadable/etc/config.xml @@ -127,6 +127,7 @@ downloadable/catalogIndex_data_downloadable 0 downloadable/indexer_price + 0 diff --git a/app/code/core/Mage/Downloadable/etc/system.xml b/app/code/core/Mage/Downloadable/etc/system.xml index f0918e1150..19d42d6562 100644 --- a/app/code/core/Mage/Downloadable/etc/system.xml +++ b/app/code/core/Mage/Downloadable/etc/system.xml @@ -88,7 +88,7 @@ 1 0 - + select downloadable/system_config_source_contentdisposition diff --git a/app/code/core/Mage/Eav/Model/Config.php b/app/code/core/Mage/Eav/Model/Config.php index ee224c9988..e8ede89c2c 100644 --- a/app/code/core/Mage/Eav/Model/Config.php +++ b/app/code/core/Mage/Eav/Model/Config.php @@ -353,7 +353,7 @@ protected function _initAttributes($entityType) } Varien_Profiler::start('EAV: '.__METHOD__); - $attributesInfo = Mage::getResourceModel('eav/entity_attribute_collection') + $attributesInfo = Mage::getResourceModel($entityType->getEntityAttributeCollection()) ->setEntityTypeFilter($entityType) // ->addSetInfo() ->getData(); @@ -473,7 +473,7 @@ public function getEntityAttributeCodes($entityType, $object=null) if ($attributeSetId) { - $attributesInfo = Mage::getResourceModel('eav/entity_attribute_collection') + $attributesInfo = Mage::getResourceModel($entityType->getEntityAttributeCollection()) ->setEntityTypeFilter($entityType) ->setAttributeSetFilter($attributeSetId) // ->addSetInfo() @@ -523,7 +523,7 @@ public function preloadAttributes($entityType, $attributes) } Varien_Profiler::start('EAV: '.__METHOD__ . ':'.$entityTypeCode); - $attributesInfo = Mage::getResourceModel('eav/entity_attribute_collection') + $attributesInfo = Mage::getResourceModel($entityType->getEntityAttributeCollection()) ->setEntityTypeFilter($entityType) ->setCodeFilter($attributes) // ->addSetInfo() diff --git a/app/code/core/Mage/Eav/Model/Convert/Adapter/Entity.php b/app/code/core/Mage/Eav/Model/Convert/Adapter/Entity.php index 638b146ac3..938cc5de13 100644 --- a/app/code/core/Mage/Eav/Model/Convert/Adapter/Entity.php +++ b/app/code/core/Mage/Eav/Model/Convert/Adapter/Entity.php @@ -146,6 +146,12 @@ public function setFilter($attrFilterArray, $attrToDb = null, $bind = null, $joi 'like' => '%'.$val.'%' ); break; + case 'startsWith': + $attr = array( + 'attribute' => $keyDB, + 'like' => $val.'%' + ); + break; case 'fromTo': $attr = array( 'attribute' => $keyDB, diff --git a/app/code/core/Mage/Eav/Model/Entity/Abstract.php b/app/code/core/Mage/Eav/Model/Entity/Abstract.php index 7c5a6b30e3..c87709c55a 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Abstract.php +++ b/app/code/core/Mage/Eav/Model/Entity/Abstract.php @@ -84,6 +84,13 @@ abstract class Mage_Eav_Model_Entity_Abstract * @var array */ protected $_staticAttributes = array(); + + /** + * Default Attributes that are static + * + * @var array + */ + protected static $_defaultAttributes = array(); /** * Enter description here... @@ -405,6 +412,28 @@ public function getAttribute($attribute) return $attribute; } + + /** + * Return default static virtual attribute that doesn't exists in EAV attributes + * + * @param string $attributeCode + * @return Mage_Eav_Model_Entity_Attribute + */ + protected function _getDefaultAttribute($attributeCode) + { + $entityTypeId = $this->getEntityType()->getId(); + if (!isset(self::$_defaultAttributes[$entityTypeId][$attributeCode])) { + $attribute = Mage::getModel($this->getEntityType()->getAttributeModel()) + ->setAttributeCode($attributeCode) + ->setBackendType(Mage_Eav_Model_Entity_Attribute_Abstract::TYPE_STATIC) + ->setIsGlobal(1) + ->setEntityType($this->getEntityType()) + ->setEntityTypeId($this->getEntityType()->getId()); + self::$_defaultAttributes[$entityTypeId][$attributeCode] = $attribute; + } + + return self::$_defaultAttributes[$entityTypeId][$attributeCode]; + } /** * Adding attribute to entity @@ -478,13 +507,7 @@ public function loadAllAttributes($object=null) $this->getAttribute($attributeCodes[$attributeIndex]); unset($attributeCodes[$attributeIndex]); } else { - $attribute = Mage::getModel($this->getEntityType()->getAttributeModel()); - $attribute->setAttributeCode($attributeCode) - ->setBackendType(Mage_Eav_Model_Entity_Attribute_Abstract::TYPE_STATIC) - ->setIsGlobal(1) - ->setEntityType($this->getEntityType()) - ->setEntityTypeId($this->getEntityType()->getId()); - $this->addAttribute($attribute); + $this->addAttribute($this->_getDefaultAttribute($attributeCode)); } } @@ -792,8 +815,8 @@ public function checkAttributeUniqueValue(Mage_Eav_Model_Entity_Attribute_Abstra ->where($attribute->getAttributeCode().'=?', $object->getData($attribute->getAttributeCode())); } else { $value = $object->getData($attribute->getAttributeCode()); - if ($attribute->getBackend()->getType() == 'datetime'){ - $date = new Zend_Date($value); + if ($attribute->getBackend()->getType() == 'datetime') { + $date = new Zend_Date($value, Varien_Date::DATE_INTERNAL_FORMAT); $value = $date->toString(Varien_Date::DATETIME_INTERNAL_FORMAT); } @@ -864,7 +887,8 @@ public function load($object, $entityId, $attributes=array()) $selects[] = $this->_getLoadAttributesSelect($object, $table); } if (!empty($selects)) { - $values = $this->_getReadAdapter()->fetchAll(implode(' UNION ', $selects)); + $select = $this->_prepareLoadSelect($selects); + $values = $this->_getReadAdapter()->fetchAll($select); foreach ($values as $valueRow) { $this->_setAttribteValue($object, $valueRow); } @@ -881,6 +905,18 @@ public function load($object, $entityId, $attributes=array()) return $this; } + /** + * Prepare select object for loading entity attributes values + * + * @param array $selects + * @return Zend_Db_Select + */ + protected function _prepareLoadSelect(array $selects) + { + $select = $this->_getReadAdapter()->select()->union($selects); + return $select; + } + /** * Retrieve select object for loading base entity row * diff --git a/app/code/core/Mage/Eav/Model/Entity/Attribute.php b/app/code/core/Mage/Eav/Model/Entity/Attribute.php index cbea42e9c7..7ade42c8f1 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Attribute.php +++ b/app/code/core/Mage/Eav/Model/Entity/Attribute.php @@ -101,6 +101,23 @@ protected function _beforeSave() Mage::throwException(Mage::helper('eav')->__('The attribute code \'%s\' is reserved by system. Please try another attribute code.', $this->_data['attribute_code'])); } + $defaultValue = $this->getDefaultValue(); + $hasDefaultValue = ((string)$defaultValue != ''); + + if ($this->getBackendType() == 'decimal' && $hasDefaultValue) { + if (!Zend_Locale_Format::isNumber($defaultValue, array('locale' => Mage::app()->getLocale()->getLocaleCode()))) { + throw new Exception('Invalid default decimal value.'); + } + try { + $filter = new Zend_Filter_LocalizedToNormalized( + array('locale' => Mage::app()->getLocale()->getLocaleCode()) + ); + $this->setDefaultValue($filter->filter($defaultValue)); + } catch (Exception $e) { + throw new Exception('Invalid default decimal value.'); + } + } + if ($this->getBackendType() == 'datetime') { if (!$this->getBackendModel()) { $this->setBackendModel('eav/entity_attribute_backend_datetime'); @@ -111,7 +128,7 @@ protected function _beforeSave() } // save default date value as timestamp - if ($defaultValue = $this->getDefaultValue()) { + if ($hasDefaultValue) { $format = Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT); try { $defaultValue = Mage::app()->getLocale()->date($defaultValue, $format, null, false)->toValue(); diff --git a/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php b/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php index 7bf1188da1..9e9c7ced91 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php +++ b/app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php @@ -370,15 +370,21 @@ public function getSource() if (!$this->getSourceModel()) { $this->setSourceModel($this->_getDefaultSourceModel()); } - $this->_source = Mage::getModel($this->getSourceModel()) - ->setAttribute($this); + $source = Mage::getModel($this->getSourceModel()); + if (!$source) { + throw new Exception(sprintf('Source model "%s" not found for attribute "%s".', + $this->getSourceModel(), $this->getAttributeCode() + )); + } + $this->_source = $source->setAttribute($this); } return $this->_source; } public function usesSource() { - return $this->getFrontendInput()==='select' || $this->getFrontendInput()==='multiselect'; + return $this->getFrontendInput() === 'select' || $this->getFrontendInput() === 'multiselect' + || $this->getData('source_model') != ''; } protected function _getDefaultBackendModel() diff --git a/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Datetime.php b/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Datetime.php index c9a80fd218..77dc27591a 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Datetime.php +++ b/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Datetime.php @@ -59,6 +59,11 @@ public function formatDate($date) if (preg_match('/^[0-9]+$/', $date)) { $date = new Zend_Date((int)$date); } + // international format + else if (preg_match('#^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$#', $date)) { + $zendDate = new Zend_Date(); + $date = $zendDate->setIso($date); + } // parse this date in current locale, do not apply GMT offset else { $date = Mage::app()->getLocale()->date($date, diff --git a/app/code/core/Mage/Eav/Model/Entity/Attribute/Set.php b/app/code/core/Mage/Eav/Model/Entity/Attribute/Set.php index 6af8c1485b..98234567f8 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Attribute/Set.php +++ b/app/code/core/Mage/Eav/Model/Entity/Attribute/Set.php @@ -233,4 +233,23 @@ public function addSetInfo($entityType, array $attributes, $setId = null) return $this; } + + /** + * Return default Group Id for current or defined Attribute Set + * + * @param int $setId + * @return int|null + */ + public function getDefaultGroupId($setId = null) + { + if (is_null($setId)) { + $setId = $this->getId(); + } + if ($setId) { + $groupId = $this->_getResource()->getDefaultGroupId($setId); + } else { + $groupId = null; + } + return $groupId; + } } diff --git a/app/code/core/Mage/Eav/Model/Entity/Attribute/Source/Table.php b/app/code/core/Mage/Eav/Model/Entity/Attribute/Source/Table.php index 3850cd7165..de7e3677d1 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Attribute/Source/Table.php +++ b/app/code/core/Mage/Eav/Model/Entity/Attribute/Source/Table.php @@ -111,29 +111,37 @@ public function getOptionText($value) */ public function addValueSortToCollection($collection, $dir = 'asc') { - $valueTable1 = $this->getAttribute()->getAttributeCode() . '_t1'; - $valueTable2 = $this->getAttribute()->getAttributeCode() . '_t2'; - $collection->getSelect() - ->joinLeft( - array($valueTable1 => $this->getAttribute()->getBackend()->getTable()), - "`e`.`entity_id`=`{$valueTable1}`.`entity_id`" - . " AND `{$valueTable1}`.`attribute_id`='{$this->getAttribute()->getId()}'" - . " AND `{$valueTable1}`.`store_id`='0'", - array()) - ->joinLeft( + $adminStore = Mage_Core_Model_App::ADMIN_STORE_ID; + $valueTable1 = $this->getAttribute()->getAttributeCode() . '_t1'; + $valueTable2 = $this->getAttribute()->getAttributeCode() . '_t2'; + + $collection->getSelect()->joinLeft( + array($valueTable1 => $this->getAttribute()->getBackend()->getTable()), + "`e`.`entity_id`=`{$valueTable1}`.`entity_id`" + . " AND `{$valueTable1}`.`attribute_id`='{$this->getAttribute()->getId()}'" + . " AND `{$valueTable1}`.`store_id`='{$adminStore}'", + array() + ); + + if ($collection->getStoreId() != $adminStore) { + $collection->getSelect()->joinLeft( array($valueTable2 => $this->getAttribute()->getBackend()->getTable()), "`e`.`entity_id`=`{$valueTable2}`.`entity_id`" . " AND `{$valueTable2}`.`attribute_id`='{$this->getAttribute()->getId()}'" . " AND `{$valueTable2}`.`store_id`='{$collection->getStoreId()}'", array() ); - $valueExpr = new Zend_Db_Expr("IF(`{$valueTable2}`.`value_id`>0, `{$valueTable2}`.`value`, `{$valueTable1}`.`value`)"); + $valueExpr = new Zend_Db_Expr("IF(`{$valueTable2}`.`value_id`>0, `{$valueTable2}`.`value`, `{$valueTable1}`.`value`)"); + + } else { + $valueExpr = new Zend_Db_Expr("`{$valueTable1}`.`value`"); + } Mage::getResourceModel('eav/entity_attribute_option') ->addOptionValueToCollection($collection, $this->getAttribute(), $valueExpr); $collection->getSelect() - ->order("{$this->getAttribute()->getAttributeCode()} {$dir}"); + ->order("{$this->getAttribute()->getAttributeCode()}_value {$dir}"); return $this; } diff --git a/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php b/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php index 889005f3b3..c56a84f46f 100644 --- a/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php +++ b/app/code/core/Mage/Eav/Model/Entity/Collection/Abstract.php @@ -31,7 +31,7 @@ * @package Mage_Eav * @author Magento Core Team */ -class Mage_Eav_Model_Entity_Collection_Abstract extends Varien_Data_Collection_Db +abstract class Mage_Eav_Model_Entity_Collection_Abstract extends Varien_Data_Collection_Db { /** * Array of items with item id key @@ -268,15 +268,14 @@ public function getAttribute($attributeCode) */ public function addAttributeToFilter($attribute, $condition=null, $joinType='inner') { - if($attribute===null) { + if ($attribute===null) { $this->getSelect(); return $this; } if (is_numeric($attribute)) { $attribute = $this->getEntity()->getAttribute($attribute)->getAttributeCode(); - } - elseif ($attribute instanceof Mage_Eav_Model_Entity_Attribute_Interface) { + } else if ($attribute instanceof Mage_Eav_Model_Entity_Attribute_Interface) { $attribute = $attribute->getAttributeCode(); } @@ -294,7 +293,7 @@ public function addAttributeToFilter($attribute, $condition=null, $joinType='inn } if (!empty($conditionSql)) { - $this->getSelect()->where($conditionSql); + $this->getSelect()->where($conditionSql, null, Varien_Db_Select::TYPE_CONDITION); } else { Mage::throwException('Invalid attribute identifier for filter ('.get_class($attribute).')'); } @@ -789,6 +788,8 @@ public function load($printQuery = false, $logQuery = false) $this->_beforeLoad(); Varien_Profiler::stop('__EAV_COLLECTION_BEFORE_LOAD__'); + $this->_renderFilters(); + Varien_Profiler::start('__EAV_COLLECTION_LOAD_ENT__'); $this->_loadEntities($printQuery, $logQuery); Varien_Profiler::stop('__EAV_COLLECTION_LOAD_ENT__'); diff --git a/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Option.php b/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Option.php index af0438c219..faed05b554 100644 --- a/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Option.php +++ b/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Option.php @@ -48,22 +48,26 @@ public function _construct() * @return Mage_Eav_Model_Mysql4_Entity_Attribute_Option */ public function addOptionValueToCollection($collection, $attribute, $valueExpr) { - $attributeCode = $attribute->getAttributeCode(); - $optionTable1 = $attributeCode . '_option_value_t1'; - $optionTable2 = $attributeCode . '_option_value_t2'; + $adminStore = Mage_Core_Model_App::ADMIN_STORE_ID; + $attributeCode = $attribute->getAttributeCode(); + $optionTable1 = $attributeCode . '_option_value_t1'; + $optionTable2 = $attributeCode . '_option_value_t2'; - $collection->getSelect() - ->joinLeft( - array($optionTable1 => $this->getTable('eav/attribute_option_value')), - "`{$optionTable1}`.`option_id`={$valueExpr}" - . " AND `{$optionTable1}`.`store_id`='0'", - array()) - ->joinLeft( + $collection->getSelect()->joinLeft( + array($optionTable1 => $this->getTable('eav/attribute_option_value')), + "`{$optionTable1}`.`option_id`={$valueExpr}" + . " AND `{$optionTable1}`.`store_id`='{$adminStore}'", + ($collection->getStoreId() != $adminStore) ? array() : array($attributeCode.'_value' => "{$optionTable1}.value") + ); + + if ($collection->getStoreId() != $adminStore) { + $collection->getSelect()->joinLeft( array($optionTable2 => $this->getTable('eav/attribute_option_value')), "`{$optionTable2}`.`option_id`={$valueExpr}" . " AND `{$optionTable1}`.`store_id`='{$collection->getStoreId()}'", - array($attributeCode => "IFNULL(`{$optionTable2}`.`value`, `{$optionTable1}`.`value`)") + array($attributeCode.'_value' => "IFNULL(`{$optionTable2}`.`value`, `{$optionTable1}`.`value`)") ); + } return $this; } diff --git a/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Set.php b/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Set.php index d9dc8d7c2e..ea5e11fd7c 100644 --- a/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Set.php +++ b/app/code/core/Mage/Eav/Model/Mysql4/Entity/Attribute/Set.php @@ -146,4 +146,20 @@ public function getSetInfo(array $attributeIds, $setId = null) return $setInfo; } + + /** + * Retrurn default attribute group id for attribute set id + * + * @param int $setId + * @return int|null + */ + public function getDefaultGroupId($setId) + { + $select = $this->_getReadAdapter()->select() + ->from($this->getTable('eav/attribute_group'), 'attribute_group_id') + ->where('attribute_set_id = ?', $setId) + ->where('default_id = ?', 1) + ->limit(1); + return $this->_getReadAdapter()->fetchOne($select); + } } diff --git a/app/code/core/Mage/GiftMessage/Block/Message/Inline.php b/app/code/core/Mage/GiftMessage/Block/Message/Inline.php index e0784ecb63..9bbe9fd4f2 100644 --- a/app/code/core/Mage/GiftMessage/Block/Message/Inline.php +++ b/app/code/core/Mage/GiftMessage/Block/Message/Inline.php @@ -45,60 +45,117 @@ protected function _construct() $this->setTemplate('giftmessage/inline.phtml'); } + /** + * Set entity + * + * @return mixed + */ public function setEntity($entity) { $this->_entity = $entity; return $this; } + /** + * Get entity + * + * @return mixed + */ public function getEntity() { return $this->_entity; } + /** + * Set type + * + * @param string $type + * @return Mage_GiftMessage_Block_Message_Inline + */ public function setType($type) { $this->_type = $type; return $this; } + /** + * Get type + * + * @return string + */ public function getType() { return $this->_type; } + /** + * Check if entity has gift message + * + * @return bool + */ public function hasGiftMessage() { return $this->getEntity()->getGiftMessageId() > 0; } + /** + * Init message + * + * @return Mage_GiftMessage_Block_Message_Inline + */ protected function _initMessage() { $this->_giftMessage = $this->helper('giftmessage/message')->getGiftMessage( - $this->getEntity()->getGiftMessageId() - ); + $this->getEntity()->getGiftMessageId() + ); return $this; } + /** + * Get default value for From field + * + * @return string + */ public function getDefaultFrom() { - return Mage::getSingleton('customer/session')->isLoggedIn() ? Mage::getSingleton('customer/session')->getCustomer()->getName() : $this->getEntity()->getBillingAddress()->getName(); + if (Mage::getSingleton('customer/session')->isLoggedIn()) { + return Mage::getSingleton('customer/session')->getCustomer()->getName(); + } else { + return $this->getEntity()->getBillingAddress()->getName(); + } } + /** + * Get default value for To field + * + * @return string + */ public function getDefaultTo() { - return $this->getEntity()->getShippingAddress() ? $this->getEntity()->getShippingAddress()->getName() : $this->getEntity()->getName(); + if ($this->getEntity()->getShippingAddress()) { + return $this->getEntity()->getShippingAddress()->getName(); + } else { + return $this->getEntity()->getName(); + } } + /** + * Retrieve message + * + * @param mixed $entity + * @return string + */ public function getMessage($entity=null) { - if(is_null($this->_giftMessage)) { + if (is_null($this->_giftMessage)) { $this->_initMessage(); } - if($entity) { - if(!$entity->getGiftMessage()) { - $entity->setGiftMessage($this->helper('giftmessage/message')->getGiftMessage($entity->getGiftMessageId())); + if ($entity) { + if (!$entity->getGiftMessage()) { + $entity->setGiftMessage( + $this->helper('giftmessage/message')->getGiftMessage($entity->getGiftMessageId()) + ); } return $entity->getGiftMessage(); } @@ -106,58 +163,103 @@ public function getMessage($entity=null) return $this->_giftMessage; } + /** + * Retrieve items + * + * @return array + */ public function getItems() { - if(!$this->getData('items')) { + if (!$this->getData('items')) { $items = array(); foreach ($this->getEntity()->getAllItems() as $item) { if ($item->getParentItem()) { continue; } - if($this->helper('giftmessage/message')->isMessagesAvailable( substr($this->getType(), 0, 5)=='multi' ? 'address_item' : 'item', $item)) { + $type = substr($this->getType(), 0, 5) == 'multi' ? 'address_item' : 'item'; + if ($this->helper('giftmessage/message')->isMessagesAvailable($type, $item)) { $items[] = $item; } } $this->setData('items', $items); } - return $this->getData('items'); } + /** + * Retrieve additional url + * + * @return bool + */ public function getAdditionalUrl() { return $this->getUrl('*/*/getAdditional'); } + /** + * Check if items are available + * + * @return bool + */ public function isItemsAvailable() { return count($this->getItems()) > 0; } + /** + * Return items count + * + * @return int + */ public function countItems() { return count($this->getItems()); } + /** + * Check if items has messages + * + * @return bool + */ public function getItemsHasMesssages() { - foreach($this->getItems() as $item) { - if($item->getGiftMessageId()) { + foreach ($this->getItems() as $item) { + if ($item->getGiftMessageId()) { return true; } } - return false; } + /** + * Check if entity has message + * + * @return bool + */ public function getEntityHasMessage() { return $this->getEntity()->getGiftMessageId() > 0; } + /** + * Return escaped value + * + * @param string $value + * @param string $defaultValue + * @return string + */ public function getEscaped($value, $defaultValue='') { return $this->htmlEscape(trim($value)!='' ? $value : $defaultValue); } + /** + * Check availability of giftmessages for specified entity + * + * @return bool + */ + public function isMessagesAvailable() + { + return Mage::helper('giftmessage/message')->isMessagesAvailable('quote', $this->getEntity()); + } } diff --git a/app/code/core/Mage/GiftMessage/Helper/Message.php b/app/code/core/Mage/GiftMessage/Helper/Message.php index 560293e92d..18bc40b751 100644 --- a/app/code/core/Mage/GiftMessage/Helper/Message.php +++ b/app/code/core/Mage/GiftMessage/Helper/Message.php @@ -85,11 +85,7 @@ public function getButton($type, Varien_Object $entity) */ public function getInline($type, Varien_Object $entity, $dontDisplayContainer=false) { - if (in_array($type, array('onepage_checkout','multishipping_adress'))) { - if (!$this->isMessagesAvailable('items', $entity)) { - return ''; - } - } elseif (!$this->isMessagesAvailable($type, $entity)) { + if (!in_array($type, array('onepage_checkout','multishipping_adress')) && !$this->isMessagesAvailable($type, $entity)) { return ''; } @@ -126,13 +122,13 @@ public function isMessagesAvailable($type, Varien_Object $entity, $store=null) } if ($type=='item') { - return !$entity->getProduct()->isVirtual() && $resultItems && $this->_getDependenceFromStoreConfig( + return !$entity->getProduct()->isVirtual() && $this->_getDependenceFromStoreConfig( $entity->getProduct()->getGiftMessageAvailable(), $store ); } elseif ($type=='order_item') { - return !$entity->getIsVirtual() && $resultItems && $this->_getDependenceFromStoreConfig( - (is_null($entity->getGiftMessageAvailable()) ? 2 : $entity->getGiftMessageAvailable()), + return !$entity->getIsVirtual() && $this->_getDependenceFromStoreConfig( + $entity->getGiftMessageAvailable(), $store ); } elseif ($type=='address_item') { diff --git a/app/code/core/Mage/GiftMessage/Model/Observer.php b/app/code/core/Mage/GiftMessage/Model/Observer.php index 9d001beac8..615c9c8bf2 100644 --- a/app/code/core/Mage/GiftMessage/Model/Observer.php +++ b/app/code/core/Mage/GiftMessage/Model/Observer.php @@ -162,17 +162,12 @@ public function checkoutEventCreateGiftMessage($observer) * Set giftmessage available default value to product * on catalog products collection load * + * @deprecated after 1.4.2.0-beta1 * @param Varien_Object $observer * @return Mage_GiftMessage_Model_Observer */ public function catalogEventProductCollectionAfterLoad($observer) { - $collection = $observer->getEvent()->getCollection(); - foreach ($collection as $item) { - if($item->getGiftMessageAvailable()===null) { - $item->setGiftMessageAvailable(2); - } - } return $this; } @@ -184,7 +179,12 @@ public function catalogEventProductCollectionAfterLoad($observer) */ public function salesEventOrderToQuote($observer) { - if($giftMessageId = $observer->getEvent()->getOrder()->getGiftMessageId()) { + $order = $observer->getEvent()->getOrder(); + if (!Mage::helper('giftmessage/message')->isMessagesAvailable('order', $order, $order->getStore())){ + return $this; + } + $giftMessageId = $order->getGiftMessageId(); + if($giftMessageId) { $giftMessage = Mage::getModel('giftmessage/message')->load($giftMessageId) ->setId(null) ->save(); @@ -202,17 +202,21 @@ public function salesEventOrderToQuote($observer) */ public function salesEventOrderItemToQuoteItem($observer) { + /** @var $orderItem Mage_Sales_Model_Order_Item */ $orderItem = $observer->getEvent()->getOrderItem(); + + if (!Mage::helper('giftmessage/message')->isMessagesAvailable('order_item', $orderItem, $orderItem->getStoreId())){ + return $this; + } + + /** @var $quoteItem Mage_Sales_Model_Quote_Item */ $quoteItem = $observer->getEvent()->getQuoteItem(); - /* @var $orderItem Mage_Sales_Model_Order_Item */ - /* @var $quoteItem Mage_Sales_Model_Quote_Item */ if ($giftMessageId = $orderItem->getGiftMessageId()) { $giftMessage = Mage::getModel('giftmessage/message')->load($giftMessageId) ->setId(null) ->save(); $quoteItem->setGiftMessageId($giftMessage->getId()); } - return $this; } } diff --git a/app/code/core/Mage/GiftMessage/etc/config.xml b/app/code/core/Mage/GiftMessage/etc/config.xml index e7388f0f84..33e7d21d7c 100644 --- a/app/code/core/Mage/GiftMessage/etc/config.xml +++ b/app/code/core/Mage/GiftMessage/etc/config.xml @@ -60,6 +60,15 @@ + + + + + + + + + @@ -185,15 +194,6 @@ - - - - model - giftmessage/observer - catalogEventProductCollectionAfterLoad - - - diff --git a/app/code/core/Mage/GiftRegistry/etc/config.xml b/app/code/core/Mage/GiftRegistry/etc/config.xml deleted file mode 100644 index 32e8f97fd1..0000000000 --- a/app/code/core/Mage/GiftRegistry/etc/config.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - 0.1.0 - - - - - - - - - - - Mage_GiftRegistry_Model - giftregistry_mysql4 - - - Mage_GiftRegistry_Model_Mysql4 - - - giftregistry_gift
    -
    -
    -
    -
    - - - Mage_GiftRegistry_Helper - - - - - - Mage_GiftRegistry - - - - - -
    - - - - - standard - - Mage_GiftRegistry - giftregistry - - - - - - - -
    diff --git a/app/code/core/Mage/GoogleAnalytics/Block/Ga.php b/app/code/core/Mage/GoogleAnalytics/Block/Ga.php index 5d2219a1af..0f7815795a 100644 --- a/app/code/core/Mage/GoogleAnalytics/Block/Ga.php +++ b/app/code/core/Mage/GoogleAnalytics/Block/Ga.php @@ -35,139 +35,124 @@ class Mage_GoogleAnalytics_Block_Ga extends Mage_Core_Block_Text { /** - * Retrieve Quote Data HTML - * + * @deprecated after 1.4.1.1 + * @see self::_getOrdersTrackingCode() * @return string */ public function getQuoteOrdersHtml() { - $quote = $this->getQuote(); - if (!$quote) { - return ''; - } - - if ($quote instanceof Mage_Sales_Model_Quote) { - $quoteId = $quote->getId(); - } else { - $quoteId = $quote; - } - - if (!$quoteId) { - return ''; - } - - $orders = Mage::getResourceModel('sales/order_collection') - ->addAttributeToFilter('quote_id', $quoteId) - ->load(); - - $html = ''; - foreach ($orders as $order) { - $html .= $this->setOrder($order)->getOrderHtml(); - } - - return $html; + return ''; } /** - * Retrieve Order Data HTML - * + * @deprecated after 1.4.1.1 + * self::_getOrdersTrackingCode() * @return string */ public function getOrderHtml() { + return ''; + } - $order = $this->getOrder(); - if (!$order) { - return ''; - } - - if (!$order instanceof Mage_Sales_Model_Order) { - $order = Mage::getModel('sales/order')->load($order); - } - - if (!$order) { - return ''; - } - - $address = $order->getBillingAddress(); - - $html = ''; + /** + * @deprecated after 1.4.1.1 + * @see _toHtml() + * @return string + */ + public function getAccount() + { + return ''; + } - return $html; + /** + * Get a specific page name (may be customized via layout) + * + * @return string|null + */ + public function getPageName() + { + return $this->_getData('page_name'); } /** - * Retrieve Google Account Identifier + * Render regular page tracking javascript code + * The custom "page name" may be set from layout or somewhere else. It must start from slash. * + * @see http://code.google.com/apis/analytics/docs/gaJS/gaJSApiBasicConfiguration.html#_gat.GA_Tracker_._trackPageview + * @see http://code.google.com/apis/analytics/docs/gaJS/gaJSApi_gaq.html + * @param string $accountId * @return string */ - public function getAccount() + protected function _getPageTrackingCode($accountId) { - if (!$this->hasData('account')) { - $this->setAccount(Mage::getStoreConfig('google/analytics/account')); + $optPageURL = trim($this->getPageName()); + if ($optPageURL && preg_match('/^\/.*/i', $optPageURL)) { + $optPageURL = "'{$this->jsQuoteEscape($optPageURL)}'"; } - return $this->getData('account'); + // the code compatible with google checkout shortcut (it requires a global pageTracker variable) + return " +_gaq.push(function() { + // the global variable is created intentionally + pageTracker = _gat._getTracker('{$this->jsQuoteEscape($accountId)}'); + pageTracker._trackPageview({$optPageURL}); +}); +"; } /** - * Retrieve current page URL + * Render information about specified orders and their items * + * @see http://code.google.com/apis/analytics/docs/gaJS/gaJSApiEcommerce.html#_gat.GA_Tracker_._addTrans * @return string */ - public function getPageName() + protected function _getOrdersTrackingCode() { - if (!$this->hasData('page_name')) { - //$queryStr = ''; - //if ($this->getRequest() && $this->getRequest()->getQuery()) { - // $queryStr = '?' . http_build_query($this->getRequest()->getQuery()); - //} - $this->setPageName(Mage::getSingleton('core/url')->escape($_SERVER['REQUEST_URI'])); + $orderIds = $this->getOrderIds(); + if (empty($orderIds) || !is_array($orderIds)) { + return; + } + $collection = Mage::getResourceModel('sales/order_collection') + ->addFieldToFilter('entity_id', array('in' => $orderIds)) + ; + $result = array(); + foreach ($collection as $order) { + if ($order->getIsVirtual()) { + $address = $order->getBillingAddress(); + } else { + $address = $order->getShippingAddress(); + } + $result[] = sprintf("_gaq.push(['_addTrans', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']);", + $order->getIncrementId(), Mage::app()->getStore()->getFrontendName(), $order->getBaseGrandTotal(), + $order->getBaseTaxAmount(), $order->getBaseShippingAmount(), + $this->jsQuoteEscape($address->getCity()), + $this->jsQuoteEscape($address->getRegion()), + $this->jsQuoteEscape($address->getCountry()) + ); + foreach ($order->getAllVisibleItems() as $item) { + $result[] = sprintf("_gaq.push(['_addItem', '%s', '%s', '%s', '%s', '%s', '%s']);", + $order->getIncrementId(), + $this->jsQuoteEscape($item->getSku()), $this->jsQuoteEscape($item->getName()), + null, // there is no "category" defined for the order item + $item->getBasePrice(), $item->getQtyOrdered() + ); + } + $result[] = "_gaq.push(['_trackTrans']);"; } - return $this->getData('page_name'); + return implode("\n", $result); } /** - * Prepare and return block's html output + * Render GA tracking scripts * * @return string */ protected function _toHtml() { - if (!Mage::getStoreConfigFlag('google/analytics/active')) { + if (!Mage::helper('googleanalytics')->isGoogleAnalyticsAvailable()) { return ''; } - - $this->addText(' + $accountId = Mage::getStoreConfig(Mage_GoogleAnalytics_Helper_Data::XML_PATH_ACCOUNT); + return ' - - '); - - $this->addText($this->getQuoteOrdersHtml()); - - if ($this->getGoogleCheckout()) { - $protocol = Mage::app()->getStore()->isCurrentlySecure() ? 'https' : 'http'; - $this->addText(''); - } - - return parent::_toHtml(); +'; } } diff --git a/app/code/core/Mage/GoogleAnalytics/Helper/Data.php b/app/code/core/Mage/GoogleAnalytics/Helper/Data.php index e0bc92aeb0..4c159f9469 100644 --- a/app/code/core/Mage/GoogleAnalytics/Helper/Data.php +++ b/app/code/core/Mage/GoogleAnalytics/Helper/Data.php @@ -33,5 +33,21 @@ */ class Mage_GoogleAnalytics_Helper_Data extends Mage_Core_Helper_Abstract { + /** + * Config paths for using throughout the code + */ + const XML_PATH_ACTIVE = 'google/analytics/active'; + const XML_PATH_ACCOUNT = 'google/analytics/account'; + /** + * Whether GA is ready to use + * + * @param mixed $store + * @return bool + */ + public function isGoogleAnalyticsAvailable($store = null) + { + $accountId = Mage::getStoreConfig(self::XML_PATH_ACCOUNT, $store); + return $accountId && Mage::getStoreConfigFlag(self::XML_PATH_ACTIVE, $store); + } } diff --git a/app/code/core/Mage/GoogleAnalytics/Model/Observer.php b/app/code/core/Mage/GoogleAnalytics/Model/Observer.php index 8ef59e8796..de42bc03ee 100644 --- a/app/code/core/Mage/GoogleAnalytics/Model/Observer.php +++ b/app/code/core/Mage/GoogleAnalytics/Model/Observer.php @@ -33,6 +33,11 @@ */ class Mage_GoogleAnalytics_Model_Observer { + /** + * Whether the google checkout inclusion link was rendered by this observer instance + * @var bool + */ + protected $_isGoogleCheckoutLinkAdded = false; /** * Create Google Analytics block for success page view @@ -46,21 +51,52 @@ public function order_success_page_view($observer) } /** - * Create Google Analytics block for success page view + * Add order information into GA block to render on checkout success pages * * @param Varien_Event_Observer $observer */ public function setGoogleAnalyticsOnOrderSuccessPageView(Varien_Event_Observer $observer) { - $quoteId = Mage::getSingleton('checkout/session')->getLastQuoteId(); - $analyticsBlock = Mage::app()->getFrontController()->getAction()->getLayout()->getBlock('google_analytics'); - if ($quoteId && ($analyticsBlock instanceof Mage_Core_Block_Abstract)) { - $quote = Mage::getModel('sales/quote')->load($quoteId); - if ($quoteId == $quote->getId()) { - $analyticsBlock->setQuote($quote); - } else { - $analyticsBlock->setQuote($quoteId); - } + $orderIds = $observer->getEvent()->getOrderIds(); + if (empty($orderIds) || !is_array($orderIds)) { + return; + } + $block = Mage::app()->getFrontController()->getAction()->getLayout()->getBlock('google_analytics'); + if ($block) { + $block->setOrderIds($orderIds); + } + } + + /** + * Add google analytics tracking to google checkout shortcuts + * + * If there is at least one GC button on the page, there should be the script for GA/GC integration included + * a each shortcut should track submits to GA + * There should be no tracking if there is no GA available + * This method assumes that the observer instance is run as a "singleton" (through Mage::getSingleton()) + * + * @param Varien_Event_Observer $observer + */ + public function injectAnalyticsInGoogleCheckoutLink(Varien_Event_Observer $observer) + { + $block = $observer->getEvent()->getBlock(); + if (!$block || !Mage::helper('googleanalytics')->isGoogleAnalyticsAvailable()) { + return; + } + + // make sure to track google checkout "onsubmit" + $onsubmitJs = $block->getOnsubmitJs(); + $block->setOnsubmitJs($onsubmitJs . ($onsubmitJs ? '; ' : '') . 'setUrchinInputCode(pageTracker);'); + + // add a link that includes google checkout/analytics script, to the first instance of the link block + if ($this->_isGoogleCheckoutLinkAdded) { + return; } + $beforeHtml = $block->getBeforeHtml(); + $protocol = Mage::app()->getStore()->isCurrentlySecure() ? 'https' : 'http'; + $block->setBeforeHtml($beforeHtml . '' + ); + $this->_isGoogleCheckoutLinkAdded = true; } } diff --git a/app/code/core/Mage/GoogleAnalytics/etc/config.xml b/app/code/core/Mage/GoogleAnalytics/etc/config.xml index 2b02fbc80a..2e89b3f2db 100644 --- a/app/code/core/Mage/GoogleAnalytics/etc/config.xml +++ b/app/code/core/Mage/GoogleAnalytics/etc/config.xml @@ -73,6 +73,14 @@
    + + + + googleanalytics/observer + injectAnalyticsInGoogleCheckoutLink + + + diff --git a/app/code/core/Mage/GoogleBase/Model/Mysql4/Item/Collection.php b/app/code/core/Mage/GoogleBase/Model/Mysql4/Item/Collection.php index 0fb92947c9..1b239b32a0 100644 --- a/app/code/core/Mage/GoogleBase/Model/Mysql4/Item/Collection.php +++ b/app/code/core/Mage/GoogleBase/Model/Mysql4/Item/Collection.php @@ -78,7 +78,7 @@ public function addFieldToFilter($field, $condition=null) { if ($field == 'name') { $conditionSql = $this->_getConditionSql('IFNULL(p.value, p_d.value)', $condition); - $this->getSelect()->where($conditionSql); + $this->getSelect()->where($conditionSql, null, Varien_Db_Select::TYPE_CONDITION); } else { parent::addFieldToFilter($field, $condition); } diff --git a/app/code/core/Mage/GoogleBase/Model/Service/Feed.php b/app/code/core/Mage/GoogleBase/Model/Service/Feed.php index 76d202b019..6fed027134 100644 --- a/app/code/core/Mage/GoogleBase/Model/Service/Feed.php +++ b/app/code/core/Mage/GoogleBase/Model/Service/Feed.php @@ -106,32 +106,32 @@ public function getItemTypes($targetCountry) $locale = Mage::getSingleton('googlebase/config')->getCountryInfo($targetCountry, 'locale'); $location = self::ITEM_TYPES_LOCATION . '/' . $locale; - $feed = $this->getGuestService()->getFeed($location); - $itemTypes = array(); - foreach ($feed->entries as $entry) { - $type = $entry->extensionElements[0]->text; - $item = new Varien_Object(); - $item->setId($type); - $item->setName($entry->title->text); - $item->setLocation($entry->id->text); - $itemTypes[$type] = $item; + foreach ($this->getGuestService()->getFeed($location)->entries as $entry) { + if (isset($entry->extensionElements[1])) { // has attributes node? + $typeAttributes = $entry->extensionElements[1]->extensionElements; + if (is_array($typeAttributes) && !empty($typeAttributes)) { // only items with attributes allowed + $type = $entry->extensionElements[0]->text; + $item = new Varien_Object(); + $item->setId($type); + $item->setName($entry->title->text); + $item->setLocation($entry->id->text); + $itemTypes[$type] = $item; - $typeAttributes = $entry->extensionElements[1]->extensionElements; - $attributes = array(); - if (is_array($typeAttributes)) { - foreach($typeAttributes as $attr) { - $name = $attr->extensionAttributes['name']['value']; - $type = $attr->extensionAttributes['type']['value']; - $attribute = new Varien_Object(); - $attribute->setId($name); - $attribute->setName($name); - $attribute->setType($type); - $attributes[$name] = $attribute; + $attributes = array(); + foreach($typeAttributes as $attr) { + $name = $attr->extensionAttributes['name']['value']; + $type = $attr->extensionAttributes['type']['value']; + $attribute = new Varien_Object(); + $attribute->setId($name); + $attribute->setName($name); + $attribute->setType($type); + $attributes[$name] = $attribute; + } + ksort($attributes); + $item->setAttributes($attributes); } } - ksort($attributes); - $item->setAttributes($attributes); } ksort($itemTypes); $this->_itemTypes = $itemTypes; diff --git a/app/code/core/Mage/GoogleBase/Model/Service/Item.php b/app/code/core/Mage/GoogleBase/Model/Service/Item.php index bfc0d81986..38187fdef5 100644 --- a/app/code/core/Mage/GoogleBase/Model/Service/Item.php +++ b/app/code/core/Mage/GoogleBase/Model/Service/Item.php @@ -241,6 +241,20 @@ protected function _prepareEnrtyForSave() return $this; } + /** + * Remove characters and words not allowed by Google Base in title and content (description). + * + * (to avoid "Expected response code 200, got 400. + * Reason: There is a problem with the character encoding of this attribute") + * + * @param string $string + * @return string + */ + protected function _cleanAtomAttribute($string) + { + return Mage::helper('core/string')->substr(preg_replace('/[\pC¢€•—™°½]|shipping/ui', '', $string), 0, 3500); + } + /** * Assign values to universal attribute of entry * @@ -251,13 +265,19 @@ protected function _setUniversalData() $service = $this->getService(); $object = $this->getObject(); $entry = $this->getEntry(); + $attributeValues = $this->getAttributeValues(); $this->_setAttribute('id', $object->getId() . '_' . $this->getStoreId(), 'text'); - if ($object->getName()) { - $title = $service->newTitle()->setText( $object->getName() ); - $entry->setTitle($title); + if (isset($attributeValues['title']['value'])) { + $titleText = $attributeValues['title']['value']; + unset($attributeValues['title']); // to prevent "Reason: Duplicate title" error + } elseif ($object->getName()) { + $titleText = $object->getName(); + } else { + $titleText = 'no title'; } + $entry->setTitle($service->newTitle()->setText($this->_cleanAtomAttribute($titleText))); if ($object->getUrl()) { $links = $entry->getLink(); @@ -275,13 +295,16 @@ protected function _setUniversalData() $entry->setLink($links); } - if ($object->getDescription()) { - $content = $service->newContent()->setText( $object->getDescription() ); - $entry->setContent($content); + if (isset($attributeValues['description']['value'])) { + $descrText = $attributeValues['description']['value']; + unset($attributeValues['description']); // to prevent "Reason: Duplicate description" error + } elseif ($object->getDescription()) { + $descrText = $object->getDescription(); + } else { + $descrText = 'no description'; } + $entry->setContent($service->newContent()->setText($this->_cleanAtomAttribute($descrText))); - $attributeValues = $this->getAttributeValues(); - if (isset($attributeValues['price']['value']) && floatval($attributeValues['price']['value']) > 0) { $price = $attributeValues['price']['value']; } else { @@ -304,6 +327,8 @@ protected function _setUniversalData() $this->_setAttribute('condition', 'new', 'text'); $this->_setAttribute('target_country', $targetCountry, 'text'); $this->_setAttribute('item_language', $this->getConfig()->getCountryInfo($targetCountry, 'language'), 'text'); + // set new 'attribute_values' with removed 'title' and/or 'description' keys to avoid 'duplicate' errors + $this->setAttributeValues($attributeValues); return $this; } diff --git a/app/code/core/Mage/GoogleCheckout/Block/Link.php b/app/code/core/Mage/GoogleCheckout/Block/Link.php index 8b57476ecb..d8339d0ed1 100644 --- a/app/code/core/Mage/GoogleCheckout/Block/Link.php +++ b/app/code/core/Mage/GoogleCheckout/Block/Link.php @@ -58,9 +58,13 @@ public function getCheckoutUrl() return $this->getUrl('googlecheckout/redirect/checkout'); } + /** + * @deprecated after 1.4.1.1 + * @return bool + */ public function getIsActiveAanalytics() { - return Mage::getStoreConfig('google/analytics/active'); + return false; } public function getImageWidth() @@ -83,6 +87,7 @@ public function _toHtml() { $quote = Mage::getSingleton('checkout/session')->getQuote(); if (Mage::getModel('googlecheckout/payment')->isAvailable($quote) && $quote->validateMinimumAmount()) { + Mage::dispatchEvent('googlecheckout_block_link_html_before', array('block' => $this)); return parent::_toHtml(); } return ''; diff --git a/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Callback.php b/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Callback.php index 5f776c297a..958bff55de 100644 --- a/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Callback.php +++ b/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Callback.php @@ -26,6 +26,8 @@ class Mage_GoogleCheckout_Model_Api_Xml_Callback extends Mage_GoogleCheckout_Model_Api_Xml_Abstract { + protected $_cachedShippingInfo = array(); // Cache of possible shipping carrier-methods combinations per storeId + /** * Process notification from google * @return Mage_GoogleCheckout_Model_Api_Xml_Callback @@ -56,8 +58,30 @@ public function process() } $this->setRootName($root)->setRoot($data[$root]); - - $this->getGResponse()->setSerialNumber($this->getData('root/serial-number')); + $serialNumber = $this->getData('root/serial-number'); + $this->getGResponse()->setSerialNumber($serialNumber); + + /* + * Prevent multiple notification processing + */ + $notification = Mage::getModel('googlecheckout/notification') + ->setSerialNumber($serialNumber) + ->loadNotificationData(); + + if ($notification->getStartedAt()) { + if ($notification->isProcessed()) { + $this->getGResponse()->SendAck(); + return; + } + if ($notification->isTimeout()) { + $notification->updateProcess(); + } else { + $this->getGResponse()->SendServerErrorStatus(); + return; + } + } else { + $notification->startProcess(); + } $method = '_response'.uc_words($root, '', '-'); if (method_exists($this, $method)) { @@ -65,6 +89,7 @@ public function process() try { $this->$method(); + $notification->stopProcess(); } catch (Exception $e) { $this->getGResponse()->log->logError($e->__toString()); } @@ -78,6 +103,26 @@ public function process() return $this; } + /** + * Load quote from request and make sure the proper payment method is set + * + * @return Mage_Sales_Model_Quote + */ + protected function _loadQuote() + { + $quoteId = $this->getData('root/shopping-cart/merchant-private-data/quote-id/VALUE'); + $storeId = $this->getData('root/shopping-cart/merchant-private-data/store-id/VALUE'); + $quote = Mage::getModel('sales/quote') + ->setStoreId($storeId) + ->load($quoteId); + if ($quote->isVirtual()) { + $quote->getBillingAddress()->setPaymentMethod('googlecheckout'); + } else { + $quote->getShippingAddress()->setPaymentMethod('googlecheckout'); + } + return $quote; + } + protected function _getApiUrl() { return null; @@ -115,11 +160,8 @@ protected function _responseMerchantCalculationCallback() { $merchantCalculations = new GoogleMerchantCalculations($this->getCurrency()); - $quoteId = $this->getData('root/shopping-cart/merchant-private-data/quote-id/VALUE'); - $storeId = $this->getData('root/shopping-cart/merchant-private-data/store-id/VALUE'); - $quote = Mage::getModel('sales/quote') - ->setStoreId($storeId) - ->load($quoteId); + $quote = $this->_loadQuote(); + $storeId = $quote->getStoreId(); $billingAddress = $quote->getBillingAddress(); $address = $quote->getShippingAddress(); @@ -139,9 +181,10 @@ protected function _responseMerchantCalculationCallback() foreach ($methods['method'] as $method) { if ($method) { list($carrierCode, $methodCode) = explode('/', $method); - $limitCarrier[] = $carrierCode; + $limitCarrier[$carrierCode] = $carrierCode; } } + $limitCarrier = array_values($limitCarrier); foreach($googleAddresses as $googleAddress) { $addressId = $googleAddress['id']; @@ -163,90 +206,53 @@ protected function _responseMerchantCalculationCallback() ->setPostcode($googleAddress['postal-code']['VALUE']) ->setLimitCarrier($limitCarrier); - $address->setCollectShippingRates(true) - ->collectShippingRates() - ->collectTotals(); $billingAddress->collectTotals(); - if ($gRequestMethods = $this->getData('root/calculate/shipping/method')) { - $carriers = array(); - $errors = array(); - foreach (Mage::getStoreConfig('carriers', $storeId) as $carrierCode=>$carrierConfig) { - if (!isset($carrierConfig['title'])) { - continue; - } - $title = $carrierConfig['title']; - foreach ($gRequestMethods as $method) { - $methodName = is_array($method) ? $method['name'] : $method; - if ($title && $method && strpos($methodName, $title)===0) { - $carriers[$carrierCode] = $title; - $errors[$title] = true; - } - } + $gRequestMethods = $this->getData('root/calculate/shipping/method'); + if ($gRequestMethods) { + // Make stable format of $gRequestMethods for convenient usage + if (array_key_exists('VALUE', $gRequestMethods)) { + $gRequestMethods = array($gRequestMethods); } - $result = Mage::getModel('shipping/shipping') - ->collectRatesByAddress($address, array_keys($carriers)) - ->getResult(); - + // Form list of mapping Google method names to applicable address rates $rates = array(); - $rateCodes = array(); - foreach ($result->getAllRates() as $rate) { + $address->setCollectShippingRates(true) + ->collectShippingRates(); + foreach ($address->getAllShippingRates() as $rate) { if ($rate instanceof Mage_Shipping_Model_Rate_Result_Error) { - $errors[$rate->getCarrierTitle()] = 1; - } else { - $k = $rate->getCarrierTitle().' - '.$rate->getMethodTitle(); - if ($address->getFreeShipping()) { - $price = 0; - } else { - $price = $rate->getPrice(); - } - - if ($price) { - $price = Mage::helper('tax')->getShippingPrice($price, false, $address, null, $storeId); - } - - $rates[$k] = $price; - $rateCodes[$k] = $rate->getCarrier() . '_' . $rate->getMethod(); - unset($errors[$rate->getCarrierTitle()]); + continue; } + $methodName = sprintf('%s - %s', $rate->getCarrierTitle(), $rate->getMethodTitle()); + $rates[$methodName] = $rate; } foreach ($gRequestMethods as $method) { - $methodName = is_array($method) ? $method['name'] : $method; $result = new GoogleResult($addressId); - - if (!empty($errors)) { - $continue = false; - foreach ($errors as $carrier=>$dummy) { - if (strpos($methodName, $carrier)===0) { - $result->SetShippingDetails($methodName, 0, "false"); - $merchantCalculations->AddResult($result); - $continue = true; - break; - } - } - if ($continue) { - continue; - } - } + $methodName = $method['name']; if (isset($rates[$methodName])) { - if ($this->getData('root/calculate/tax/VALUE')=='true') { - $address->setShippingMethod($rateCodes[$methodName]); - $address->collectTotals(); + $rate = $rates[$methodName]; + + $address->setShippingMethod($rate->getCode()) + ->setLimitCarrier($rate->getCarrier()) + ->setCollectShippingRates(true) + ->collectTotals(); + $shippingRate = $address->getBaseShippingAmount() - $address->getBaseShippingDiscountAmount(); + $result->SetShippingDetails($methodName, $shippingRate, "true"); + if ($this->getData('root/calculate/tax/VALUE') == 'true') { $taxAmount = $address->getBaseTaxAmount(); $taxAmount += $billingAddress->getBaseTaxAmount(); - $result->setTaxDetails($taxAmount); } - - $result->SetShippingDetails($methodName, $rates[$methodName], "true"); - $merchantCalculations->AddResult($result); + } else { + $result->SetShippingDetails($methodName, 0, "false"); } + $merchantCalculations->AddResult($result); } - } elseif ($this->getData('root/calculate/tax/VALUE')=='true') { + + } else if ($this->getData('root/calculate/tax/VALUE')=='true') { $address->setShippingMethod(null); $address->setCollectShippingRates(true)->collectTotals(); $billingAddress->setCollectShippingRates(true)->collectTotals(); @@ -279,13 +285,10 @@ protected function _responseNewOrderNotification() } // IMPORT GOOGLE ORDER DATA INTO QUOTE - $quoteId = $this->getData('root/shopping-cart/merchant-private-data/quote-id/VALUE'); - $storeId = $this->getData('root/shopping-cart/merchant-private-data/store-id/VALUE'); - $quote = Mage::getModel('sales/quote') - ->setStoreId($storeId) - ->load($quoteId) - ->setIsActive(true) - ->reserveOrderId(); + /* @var $quote Mage_Sales_Model_Quote */ + $quote = $this->_loadQuote(); + $quote->setIsActive(true)->reserveOrderId(); + $storeId = $quote->getStoreId(); Mage::app()->setCurrentStore(Mage::app()->getStore($storeId)); if ($quote->getQuoteCurrencyCode() != $quote->getBaseCurrencyCode()) { @@ -296,13 +299,17 @@ protected function _responseNewOrderNotification() $quote->setBillingAddress($billing); $shipping = $this->_importGoogleAddress($this->getData('root/buyer-shipping-address')); + $quote->setShippingAddress($shipping); + $this->_importGoogleTotals($quote->getShippingAddress()); + $quote->getPayment()->importData(array('method'=>'googlecheckout')); // CONVERT QUOTE TO ORDER $convertQuote = Mage::getSingleton('sales/convert_quote'); + /* @var $order Mage_Sales_Model_Order */ $order = $convertQuote->toOrder($quote); if ($quote->isVirtual()) { @@ -311,7 +318,6 @@ protected function _responseNewOrderNotification() $convertQuote->addressToOrder($quote->getShippingAddress(), $order); } - $order->setExtOrderId($this->getGoogleOrderNumber()); $order->setExtCustomerId($this->getData('root/buyer-id/VALUE')); @@ -325,6 +331,7 @@ protected function _responseNewOrderNotification() } $order->setBillingAddress($convertQuote->addressToOrderAddress($quote->getBillingAddress())); + if (!$quote->isVirtual()) { $order->setShippingAddress($convertQuote->addressToOrderAddress($quote->getShippingAddress())); } @@ -360,6 +367,8 @@ protected function _responseNewOrderNotification() Mage::getModel('newsletter/subscriber')->subscribe($order->getCustomerEmail()); } + Mage::dispatchEvent('checkout_submit_all_after', array('order' => $order, 'quote' => $quote)); + $this->getGRequest()->SendMerchantOrderNumber($order->getExtOrderId(), $order->getIncrementId()); } @@ -409,6 +418,101 @@ protected function _importGoogleAddress($gAddress, Varien_Object $qAddress=null) return $qAddress; } + /** + * Returns array of possible shipping methods combinations + * Includes internal GoogleCheckout shipping methods, that can be created + * after successful Google Checkout + * + * @return array + */ + protected function _getShippingInfos($storeId = null) + { + $cacheKey = ($storeId === null) ? 'nofilter' : $storeId; + if (!isset($this->_cachedShippingInfo[$cacheKey])) { + /* @var $shipping Mage_Shipping_Model_Shipping */ + $shipping = Mage::getModel('shipping/shipping'); + $carriers = Mage::getStoreConfig('carriers', $storeId); + $infos = array(); + + foreach (array_keys($carriers) as $carrierCode) { + $carrier = $shipping->getCarrierByCode($carrierCode); + if (!$carrier) { + continue; + } + + if ($carrierCode == 'googlecheckout') { + // Add info about internal google checkout methods + $methods = array_merge($carrier->getAllowedMethods(), $carrier->getInternallyAllowedMethods()); + $carrierName = 'Google Checkout'; + } else { + $methods = $carrier->getAllowedMethods(); + $carrierName = Mage::getStoreConfig('carriers/' . $carrierCode . '/title', $storeId); + } + + foreach ($methods as $methodCode => $methodName) { + $code = $carrierCode . '_' . $methodCode; + $name = sprintf('%s - %s', $carrierName, $methodName); + $infos[$code] = array( + 'code' => $code, + 'name' => $name, // Internal name for google checkout api - to distinguish it in google requests + 'carrier' => $carrierCode, + 'carrier_title' => $carrierName, + 'method' => $methodCode, + 'method_title' => $methodName + ); + } + } + $this->_cachedShippingInfo[$cacheKey] = $infos; + } + + return $this->_cachedShippingInfo[$cacheKey]; + } + + /** + * Return shipping method code by shipping method name received from Google + * + * @param string $name + * @param int|string|Mage_Core_Model_Store $storeId + * @return string|false + */ + protected function _getShippingMethodByName($name, $storeId = null) + { + $code = false; + $infos = $this->_getShippingInfos($storeId); + foreach ($infos as $info) { + if ($info['name'] == $name) { + $code = $info['code']; + break; + } + } + return $code; + } + + /** + * Creates rate by method code + * Sets shipping rate's accurate description, titles and so on, + * so it will get in order description properly + * + * @param string $code + * @return Mage_Sales_Model_Quote_Address_Rate + */ + protected function _createShippingRate($code, $storeId = null) + { + $rate = Mage::getModel('sales/quote_address_rate') + ->setCode($code); + + $infos = $this->_getShippingInfos($storeId); + if (isset($infos[$code])) { + $info = $infos[$code]; + $rate->setCarrier($info['carrier']) + ->setCarrierTitle($info['carrier_title']) + ->setMethod($info['method']) + ->setMethodTitle($info['method_title']); + } + + return $rate; + } + /** * Import totals information from google request to quote address * @@ -422,24 +526,29 @@ protected function _importGoogleTotals($qAddress) ); $qAddress->setBaseTaxAmount($this->getData('root/order-adjustment/total-tax/VALUE')); + $method = null; $prefix = 'root/order-adjustment/shipping/'; - if ($shipping = $this->getData($prefix.'carrier-calculated-shipping-adjustment')) { + if (null !== ($shipping = $this->getData($prefix.'carrier-calculated-shipping-adjustment'))) { $method = 'googlecheckout_carrier'; - } elseif ($shipping = $this->getData($prefix.'merchant-calculated-shipping-adjustment')) { - $method = 'googlecheckout_merchant'; - } elseif ($shipping = $this->getData($prefix.'flat-rate-shipping-adjustment')) { + } else if (null !== ($shipping = $this->getData($prefix.'merchant-calculated-shipping-adjustment'))) { + $method = $this->_getShippingMethodByName($shipping['shipping-name']['VALUE']); + if ($method === false) { + $method = 'googlecheckout_merchant'; + } + } else if (null !== ($shipping = $this->getData($prefix.'flat-rate-shipping-adjustment'))) { $method = 'googlecheckout_flatrate'; - } elseif ($shipping = $this->getData($prefix.'pickup-shipping-adjustment')) { + } else if (null !== ($shipping = $this->getData($prefix.'pickup-shipping-adjustment'))) { $method = 'googlecheckout_pickup'; } - if (!empty($method)) { + + if ($method) { Mage::getSingleton('tax/config')->setShippingPriceIncludeTax(false); - $rate = Mage::getModel('sales/quote_address_rate') - ->setCode($method) + $rate = $this->_createShippingRate($method) ->setPrice($shipping['shipping-cost']['VALUE']); $qAddress->addShippingRate($rate) ->setShippingMethod($method) - ->setShippingDescription($shipping['shipping-name']['VALUE']); + ->setShippingDescription($shipping['shipping-name']['VALUE']) + ->setShippingAmountForDiscount(0); // We get from Google price with discounts applied via merchant calculations /*if (!Mage::helper('tax')->shippingPriceIncludesTax($quote->getStore())) { $includingTax = Mage::helper('tax')->getShippingPrice($excludingTax, true, $qAddress, $quote->getCustomerTaxClassId()); @@ -556,7 +665,7 @@ protected function _responseChargeAmountNotification() $msg .= '
    '.$this->__('Latest Charge: %s', '' . $this->_formatAmount($latestCharged) . ''); $msg .= '
    '.$this->__('Total Charged: %s', '' . $this->_formatAmount($totalCharged) . ''); - if (!$order->hasInvoices() && abs($order->getGrandTotal()-$latestCharged)<.0001) { + if (!$order->hasInvoices() && abs($order->getBaseGrandTotal() - $latestCharged)<.0001) { $invoice = $this->_createInvoice(); $msg .= '
    '.$this->__('Invoice Auto-Created: %s', ''.$invoice->getIncrementId().''); } @@ -564,7 +673,7 @@ protected function _responseChargeAmountNotification() foreach ($order->getInvoiceCollection() as $orderInvoice) { $open = Mage_Sales_Model_Order_Invoice::STATE_OPEN; $paid = Mage_Sales_Model_Order_Invoice::STATE_PAID; - if ($orderInvoice->getState() == $open && $orderInvoice->getGrandTotal() == $latestCharged) { + if ($orderInvoice->getState() == $open && $orderInvoice->getBaseGrandTotal() == $latestCharged) { $orderInvoice->setState($paid)->save(); break; } @@ -580,11 +689,7 @@ protected function _createInvoice() $order = $this->getOrder(); $invoice = $order->prepareInvoice(); - - if (!empty($data['comment_text'])) { - $invoice->addComment(Mage::helper('googlecheckout')->__('Auto-generated from GoogleCheckout Charge')); - } - + $invoice->addComment(Mage::helper('googlecheckout')->__('Auto-generated from GoogleCheckout Charge')); $invoice->register(); $invoice->pay(); @@ -615,29 +720,68 @@ protected function _createShipment() return $shipment; } - + /** + * Process chargeback notification + */ protected function _responseChargebackAmountNotification() { $this->getGResponse()->SendAck(); + $latestChargeback = $this->getData('root/latest-chargeback-amount/VALUE'); + $totalChargeback = $this->getData('root/total-chargeback-amount/VALUE'); + + $order = $this->getOrder(); + if ($order->getBaseGrandTotal() == $totalChargeback) { + $creditmemo = Mage::getModel('sales/service_order', $order) + ->prepareCreditmemo() + ->setPaymentRefundDisallowed(true) + ->setAutomaticallyCreated(true) + ->register(); + + $creditmemo->addComment($this->__('Credit memo has been created automatically')); + $creditmemo->save(); + } + $msg = $this->__('Google Chargeback:'); + $msg .= '
    '.$this->__('Latest Chargeback: %s', '' . $this->_formatAmount($latestChargeback) . ''); + $msg .= '
    '.$this->__('Total Chargeback: %s', '' . $this->_formatAmount($totalChargeback) . ''); + + $order->addStatusToHistory($order->getStatus(), $msg); + $order->save(); } /** * Process refund notification - * */ protected function _responseRefundAmountNotification() { $this->getGResponse()->SendAck(); + $latestRefunded = $this->getData('root/latest-refund-amount/VALUE'); + $totalRefunded = $this->getData('root/total-refund-amount/VALUE'); + $order = $this->getOrder(); - $payment = $order->getPayment(); + $amountRefundLeft = $order->getBaseGrandTotal() - $order->getBaseTotalRefunded(); + if ($amountRefundLeft < $latestRefunded) { + $latestRefunded = $amountRefundLeft; + $totalRefunded = $order->getBaseGrandTotal(); + } - $totalRefunded = $this->getData('root/total-refund-amount/VALUE'); - $payment->setAmountCharged($totalRefunded); + if ($order->getBaseTotalRefunded() > 0) { + $adjustment = array('adjustment_positive' => $latestRefunded); + } else { + $adjustment = array('adjustment_negative' => $order->getBaseGrandTotal() - $latestRefunded); + } + + $creditmemo = Mage::getModel('sales/service_order', $order) + ->prepareCreditmemo($adjustment) + ->setPaymentRefundDisallowed(true) + ->setAutomaticallyCreated(true) + ->register() + ->addComment($this->__('Credit memo has been created automatically')) + ->save(); $msg = $this->__('Google Refund:'); - $msg .= '
    '.$this->__('Latest Refund: %s', '' . $this->_formatAmount($this->getData('root/latest-refund-amount/VALUE')) . ''); + $msg .= '
    '.$this->__('Latest Refund: %s', '' . $this->_formatAmount($latestRefunded) . ''); $msg .= '
    '.$this->__('Total Refunded: %s', '' . $this->_formatAmount($totalRefunded) . ''); $order->addStatusToHistory($order->getStatus(), $msg); diff --git a/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Checkout.php b/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Checkout.php index d06e20e574..0a4ef8d396 100644 --- a/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Checkout.php +++ b/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Checkout.php @@ -101,6 +101,10 @@ protected function _getItemsXml() $billingDiscount = (float)$this->getQuote()->getBillingAddress()->getBaseDiscountAmount(); $discount = $billingDiscount + $shippingDiscount; + // exclude shipping discount + // discount is negative value + $discount += $this->getQuote()->getShippingAddress()->getBaseShippingDiscountAmount(); + $discountItem = new Varien_Object(array( 'price' => $discount, 'name' => $this->__('Cart Discount'), @@ -114,8 +118,8 @@ protected function _getItemsXml() $xml .= << _INTERNAL_DISCOUNT_ - {$this->__('Cart Discount')} - {$this->__('Virtual item to reflect discount total')} + {$discountItem->getName()} + {$discountItem->getDescription()} {$discount} 1 diff --git a/app/code/core/Mage/GoogleCheckout/Model/Mysql4/Notification.php b/app/code/core/Mage/GoogleCheckout/Model/Mysql4/Notification.php new file mode 100644 index 0000000000..e2834af6bd --- /dev/null +++ b/app/code/core/Mage/GoogleCheckout/Model/Mysql4/Notification.php @@ -0,0 +1,104 @@ + + */ +class Mage_GoogleCheckout_Model_Mysql4_Notification extends Mage_Core_Model_Mysql4_Abstract +{ + /** + * Intialize resource model + */ + protected function _construct() + { + $this->_init('googlecheckout/notification', 'serial_number'); + } + + /** + * Return notification data by serial number + * + * @param string $serialNumber + * @return array + */ + public function getNotificationData($serialNumber) + { + $select = $this->_getWriteAdapter()->select() + ->from($this->getMainTable(), array('*')) + ->where($this->_getWriteAdapter()->quoteInto('serial_number = ?', $serialNumber)); + return $this->_getWriteAdapter()->fetchRow($select); + } + + /** + * Start notification processing + * + * @param string $serialNumber + * @return Mage_GoogleCheckout_Model_Mysql4_Notification + */ + public function startProcess($serialNumber) + { + $data = array( + 'serial_number' => $serialNumber, + 'started_at' => $this->formatDate(time()), + 'status' => Mage_GoogleCheckout_Model_Notification::STATUS_INPROCESS + ); + $this->_getWriteAdapter()->insert($this->getMainTable(), $data); + return $this; + } + + /** + * Stop notification processing + * + * @param string $serialNumber + * @return Mage_GoogleCheckout_Model_Mysql4_Notification + */ + public function stopProcess($serialNumber) + { + $this->_getWriteAdapter()->update($this->getMainTable(), + array('status' => Mage_GoogleCheckout_Model_Notification::STATUS_PROCESSED), + array($this->_getWriteAdapter()->quoteInto('serial_number = ?', $serialNumber)) + ); + return $this; + } + + /** + * Update notification processing + * + * @param string $serialNumber + * @return Mage_GoogleCheckout_Model_Mysql4_Notification + */ + public function updateProcess($serialNumber) + { + $this->_getWriteAdapter()->update($this->getMainTable(), + array('started_at' => $this->formatDate(time())), + array($this->_getWriteAdapter()->quoteInto('serial_number = ?', $serialNumber)) + ); + return $this; + } +} diff --git a/app/code/core/Mage/GoogleCheckout/Model/Notification.php b/app/code/core/Mage/GoogleCheckout/Model/Notification.php new file mode 100644 index 0000000000..fd5e1aadc0 --- /dev/null +++ b/app/code/core/Mage/GoogleCheckout/Model/Notification.php @@ -0,0 +1,120 @@ + + */ +class Mage_GoogleCheckout_Model_Notification extends Mage_Core_Model_Abstract +{ + const TIMEOUT_LIMIT = 3600; + const STATUS_INPROCESS = 0; + const STATUS_PROCESSED = 1; + + /** + * Intialize model + */ + function _construct() + { + $this->_init('googlecheckout/notification'); + } + + /** + * Assign previously saved notification data to model + * + * @return Mage_GoogleCheckout_Model_Notification + */ + public function loadNotificationData() + { + $data = $this->getResource()->getNotificationData($this->getSerialNumber()); + if (is_array($data)) { + $this->addData($data); + } + return $this; + } + + /** + * Check if current notification is already processed + * + * @return bool + */ + public function isProcessed() + { + return $this->getStatus() == self::STATUS_PROCESSED; + } + + /** + * Check if current notification is time out + * + * @return bool + */ + public function isTimeout() + { + $startedTime = strtotime($this->getStartedAt()); + $currentTime = time(); + + if ($currentTime - $startedTime > self::TIMEOUT_LIMIT) { + return true; + } + return false; + } + + /** + * Start process of current notification + * + * @return Mage_GoogleCheckout_Model_Notification + */ + public function startProcess() + { + $this->getResource()->startProcess($this->getSerialNumber()); + return $this; + } + + /** + * Update process of current notification + * + * @return Mage_GoogleCheckout_Model_Notification + */ + public function updateProcess() + { + $this->getResource()->updateProcess($this->getSerialNumber()); + return $this; + } + + /** + * Stop process of current notification + * + * @return Mage_GoogleCheckout_Model_Notification + */ + public function stopProcess() + { + $this->getResource()->stopProcess($this->getSerialNumber()); + return $this; + } +} diff --git a/app/code/core/Mage/GoogleCheckout/Model/Observer.php b/app/code/core/Mage/GoogleCheckout/Model/Observer.php index adb663945f..b64053e3ad 100644 --- a/app/code/core/Mage/GoogleCheckout/Model/Observer.php +++ b/app/code/core/Mage/GoogleCheckout/Model/Observer.php @@ -48,19 +48,35 @@ public function salesOrderShipmentTrackSaveAfter(Varien_Event_Observer $observer ->deliver($order->getExtOrderId(), $track->getCarrierCode(), $track->getNumber()); } + /* + * Performs specifical actions on Google Checkout internal shipments saving + * + * @param Varien_Event_Observer $observer + * @return void + */ public function salesOrderShipmentSaveAfter(Varien_Event_Observer $observer) { - $googleShipmentNames = array('googlecheckout_carrier', 'googlecheckout_merchant', 'googlecheckout_flatrate', 'googlecheckout_pickup'); - $shipment = $observer->getEvent()->getShipment(); $order = $shipment->getOrder(); + $shippingMethod = $order->getShippingMethod(); // String in format of 'carrier_method' + if (!$shippingMethod) { + return; + } - if (!in_array($order->getShippingMethod(), $googleShipmentNames)) { + // Process only Google Checkout internal methods + /* @var $gcCarrier Mage_GoogleCheckout_Model_Shipping */ + $gcCarrier = Mage::getModel('googlecheckout/shipping'); + list($carrierCode, $methodCode) = explode('_', $shippingMethod); + if ($gcCarrier->getCarrierCode() != $carrierCode) { + return; + } + $internalMethods = $gcCarrier->getInternallyAllowedMethods(); + if (!isset($internalMethods[$methodCode])) { return; } + // Process this saving $items = array(); - foreach ($shipment->getAllItems() as $item) { if ($item->getOrderItem()->getParentItemId()) { continue; diff --git a/app/code/core/Mage/GoogleCheckout/Model/Shipping.php b/app/code/core/Mage/GoogleCheckout/Model/Shipping.php index d395a544a5..28b69e5cfa 100644 --- a/app/code/core/Mage/GoogleCheckout/Model/Shipping.php +++ b/app/code/core/Mage/GoogleCheckout/Model/Shipping.php @@ -36,7 +36,7 @@ class Mage_GoogleCheckout_Model_Shipping extends Mage_Shipping_Model_Carrier_Abs protected $_code = 'googlecheckout'; /** - * Enter description here... + * Collects rates for user request * * @param Mage_Shipping_Model_Rate_Request $data * @return Mage_Shipping_Model_Rate_Result @@ -47,8 +47,30 @@ public function collectRates(Mage_Shipping_Model_Rate_Request $request) return $this; } + /** + * Returns array(methodCode => methodName) of possible methods for this carrier + * Used to automatically show it in config and so on + * + * @return array + */ public function getAllowedMethods() { return array(); } + + /** + * Returns array(methodCode => methodName) of internally used methods. + * They are possible only as result of completing Google Checkout. + * + * @return array + */ + public function getInternallyAllowedMethods() + { + return array( + 'carrier' => 'Carrier', + 'merchant' => 'Merchant', + 'flatrate' => 'Flat Rate', + 'pickup' => 'Pickup' + ); + } } diff --git a/app/code/core/Mage/GoogleCheckout/controllers/RedirectController.php b/app/code/core/Mage/GoogleCheckout/controllers/RedirectController.php index 2fb4b73f8e..511c1dfd21 100644 --- a/app/code/core/Mage/GoogleCheckout/controllers/RedirectController.php +++ b/app/code/core/Mage/GoogleCheckout/controllers/RedirectController.php @@ -32,45 +32,55 @@ class Mage_GoogleCheckout_RedirectController extends Mage_Core_Controller_Front_Action { /** - * Send request to Google Checkout and return Responce Api + * Send request to Google Checkout and return Response Api * * @return object Mage_GoogleCheckout_Model_Api_Xml_Checkout */ protected function _getApi () { $session = Mage::getSingleton('checkout/session'); - $api = Mage::getModel('googlecheckout/api'); + /* @var $quote Mage_Sales_Model_Quote */ + $quote = $session->getQuote(); - if (!$session->getQuote()->hasItems()) { + if (!$quote->hasItems()) { $this->getResponse()->setRedirect(Mage::getUrl('checkout/cart')); $api->setError(true); } $storeQuote = Mage::getModel('sales/quote')->setStoreId(Mage::app()->getStore()->getId()); - $storeQuote->merge($session->getQuote()); + $storeQuote->merge($quote); $storeQuote - ->setItemsCount($session->getQuote()->getItemsCount()) - ->setItemsQty($session->getQuote()->getItemsQty()) + ->setItemsCount($quote->getItemsCount()) + ->setItemsQty($quote->getItemsQty()) ->setChangedFlag(false); $storeQuote->save(); - $baseCurrency = $session->getQuote()->getBaseCurrencyCode(); - $currency = Mage::app()->getStore($session->getQuote()->getStoreId())->getBaseCurrency(); - $session->getQuote() - ->collectTotals() - ->save(); + $baseCurrency = $quote->getBaseCurrencyCode(); + $currency = Mage::app()->getStore($quote->getStoreId())->getBaseCurrency(); + + + /* + * Set payment method to google checkout, so all price rules will work out this case + * and will use right sales rules + */ + if ($quote->isVirtual()) { + $quote->getBillingAddress()->setPaymentMethod('googlecheckout'); + } else { + $quote->getShippingAddress()->setPaymentMethod('googlecheckout'); + } + + $quote->collectTotals()->save(); if (!$api->getError()) { $api = $api->setAnalyticsData($this->getRequest()->getPost('analyticsdata')) - ->checkout($session->getQuote()); + ->checkout($quote); $response = $api->getResponse(); if ($api->getError()) { Mage::getSingleton('checkout/session')->addError($api->getError()); } else { - $oldQuote = $session->getQuote(); - $oldQuote->setIsActive(false)->save(); + $quote->setIsActive(false)->save(); $session->replaceQuote($storeQuote); Mage::getModel('checkout/cart')->init()->save(); if (Mage::getStoreConfigFlag('google/checkout/hide_cart_contents')) { diff --git a/app/code/core/Mage/GoogleCheckout/etc/config.xml b/app/code/core/Mage/GoogleCheckout/etc/config.xml index c8fffbb190..b32e43441c 100644 --- a/app/code/core/Mage/GoogleCheckout/etc/config.xml +++ b/app/code/core/Mage/GoogleCheckout/etc/config.xml @@ -28,7 +28,7 @@ - 0.7.3 + 0.7.4 @@ -50,6 +50,7 @@ Mage_GoogleCheckout_Model_Mysql4 googlecheckout_api_debug
    + googlecheckout_notification
    @@ -166,6 +167,7 @@ Something like this is to be added to resolve bug #4890 0 0 1 + Google Checkout
    COMMERCIAL diff --git a/app/code/core/Mage/GoogleCheckout/etc/system.xml b/app/code/core/Mage/GoogleCheckout/etc/system.xml index a43cb0061f..e3b9494a9a 100644 --- a/app/code/core/Mage/GoogleCheckout/etc/system.xml +++ b/app/code/core/Mage/GoogleCheckout/etc/system.xml @@ -43,7 +43,7 @@ 20 1 1 - 0 + 1 @@ -54,6 +54,14 @@ 1 0 + + <label>Title</label> + <frontend_type>text</frontend_type> + <sort_order>11</sort_order> + <show_in_default>1</show_in_default> + <show_in_website>1</show_in_website> + <show_in_store>1</show_in_store> + select @@ -196,8 +204,9 @@ 1 0 - + + Warning! This option disables the merchant calculated shipping. With this option, Google API ignores any attempt to affect shipping prices.]]> select adminhtml/system_config_source_yesno 10 diff --git a/app/code/core/Mage/GoogleCheckout/sql/googlecheckout_setup/mysql4-upgrade-0.7.3-0.7.4.php b/app/code/core/Mage/GoogleCheckout/sql/googlecheckout_setup/mysql4-upgrade-0.7.3-0.7.4.php new file mode 100644 index 0000000000..403dbf2f83 --- /dev/null +++ b/app/code/core/Mage/GoogleCheckout/sql/googlecheckout_setup/mysql4-upgrade-0.7.3-0.7.4.php @@ -0,0 +1,38 @@ +run(" +CREATE TABLE `{$this->getTable('googlecheckout/notification')}` ( + `serial_number` varchar(30) NOT NULL, + `started_at` datetime default NULL, + `status` smallint(5) unsigned NOT NULL default '0', + PRIMARY KEY (`serial_number`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8;" +); + diff --git a/app/code/core/Mage/Index/Model/Process.php b/app/code/core/Mage/Index/Model/Process.php index 8f66e600e3..b7ab106d66 100644 --- a/app/code/core/Mage/Index/Model/Process.php +++ b/app/code/core/Mage/Index/Model/Process.php @@ -26,7 +26,7 @@ class Mage_Index_Model_Process extends Mage_Core_Model_Abstract { - const XML_PATH_INDEXER_DATA = 'global/index/indexer'; + const XML_PATH_INDEXER_DATA = 'global/index/indexer'; /** * Process statuses */ @@ -37,17 +37,17 @@ class Mage_Index_Model_Process extends Mage_Core_Model_Abstract /** * Process event statuses */ - const EVENT_STATUS_NEW = 'new'; - const EVENT_STATUS_DONE = 'done'; - const EVENT_STATUS_ERROR = 'error'; - const EVENT_STATUS_WORKING = 'working'; + const EVENT_STATUS_NEW = 'new'; + const EVENT_STATUS_DONE = 'done'; + const EVENT_STATUS_ERROR = 'error'; + const EVENT_STATUS_WORKING = 'working'; /** * Process modes * Process mode allow disable automatic process events processing */ - const MODE_MANUAL = 'manual'; - const MODE_REAL_TIME= 'real_time'; + const MODE_MANUAL = 'manual'; + const MODE_REAL_TIME = 'real_time'; /** * Indexer stategy object @@ -176,6 +176,7 @@ public function reindexEverything() public function processEvent(Mage_Index_Model_Event $event) { if ($this->getMode() == self::MODE_MANUAL) { + $this->changeStatus(self::STATUS_REQUIRE_REINDEX); return $this; } if (!$this->getIndexer()->matchEvent($event)) { diff --git a/app/code/core/Mage/Install/Block/State.php b/app/code/core/Mage/Install/Block/State.php index 4508daa57f..44ff2bcf8c 100644 --- a/app/code/core/Mage/Install/Block/State.php +++ b/app/code/core/Mage/Install/Block/State.php @@ -38,4 +38,34 @@ public function __construct() $this->setTemplate('install/state.phtml'); $this->assign('steps', Mage::getSingleton('install/wizard')->getSteps()); } + + /** + * Get previous downloader steps + * + * @return array + */ + public function getDownloaderSteps() + { + if ($this->isDownloaderInstall()) { + $steps = array( + Mage::helper('install')->__('Welcome'), + Mage::helper('install')->__('Validation'), + Mage::helper('install')->__('Magento Connect Manager Deployment'), + ); + return $steps; + } else { + return array(); + } + } + + /** + * Checks for Magento Connect Manager installation method + * + * @return bool + */ + public function isDownloaderInstall() + { + $session = Mage::app()->getCookie()->get('magento_downloader_session'); + return $session ? true : false; + } } diff --git a/app/code/core/Mage/Install/Model/Installer.php b/app/code/core/Mage/Install/Model/Installer.php index c7de515b4f..622b170512 100644 --- a/app/code/core/Mage/Install/Model/Installer.php +++ b/app/code/core/Mage/Install/Model/Installer.php @@ -168,6 +168,13 @@ public function installDb() $setupModel->setConfigData(Mage_Core_Model_Store::XML_PATH_USE_REWRITES, 1); } + if (!empty($data['enable_charts'])) { + $setupModel->setConfigData(Mage_Adminhtml_Block_Dashboard::XML_PATH_ENABLE_CHARTS, 1); + } else { + $setupModel->setConfigData(Mage_Adminhtml_Block_Dashboard::XML_PATH_ENABLE_CHARTS, 0); + } + + $unsecureBaseUrl = Mage::getBaseUrl('web'); if (!empty($data['unsecure_base_url'])) { $unsecureBaseUrl = $data['unsecure_base_url']; diff --git a/app/code/core/Mage/Install/Model/Installer/Config.php b/app/code/core/Mage/Install/Model/Installer/Config.php index 90ccbbf0b5..256f59dad4 100644 --- a/app/code/core/Mage/Install/Model/Installer/Config.php +++ b/app/code/core/Mage/Install/Model/Installer/Config.php @@ -73,12 +73,18 @@ public function install() if (isset($data['unsecure_base_url'])) { $data['unsecure_base_url'] .= substr($data['unsecure_base_url'],-1) != '/' ? '/' : ''; + if (strpos($data['unsecure_base_url'], 'http') !== 0) { + $data['unsecure_base_url'] = 'http://'.$data['unsecure_base_url']; + } if (!$this->_getInstaller()->getDataModel()->getSkipBaseUrlValidation()) { $this->_checkUrl($data['unsecure_base_url']); } } if (isset($data['secure_base_url'])) { $data['secure_base_url'] .= substr($data['secure_base_url'],-1) != '/' ? '/' : ''; + if (strpos($data['secure_base_url'], 'http') !== 0) { + $data['secure_base_url'] = 'https://'.$data['secure_base_url']; + } if (!empty($data['use_secure']) && !$this->_getInstaller()->getDataModel()->getSkipUrlValidation()) { @@ -122,6 +128,7 @@ public function getFormData() ->setSecureBaseUrl($baseSecureUrl) ->setUnsecureBaseUrl($baseUrl) ->setAdminFrontname('admin') + ->setEnableCharts('1') ; return $data; } @@ -140,8 +147,8 @@ protected function _checkHostsInfo($data) protected function _checkUrl($url, $secure=false) { $prefix = $secure ? 'install/wizard/checkSecureHost/' : 'install/wizard/checkHost/'; - $client = new Varien_Http_Client($url.'index.php/'.$prefix); try { + $client = new Varien_Http_Client($url.'index.php/'.$prefix); $response = $client->request('GET'); /* @var $responce Zend_Http_Response */ $body = $response->getBody(); @@ -153,7 +160,7 @@ protected function _checkUrl($url, $secure=false) if ($body != Mage_Install_Model_Installer::INSTALLER_HOST_RESPONSE) { $this->_getInstaller()->getDataModel()->addError(Mage::helper('install')->__('The URL "%s" is invalid.', $url)); - Mage::throwException(Mage::helper('install')->__('This URL is invalid.')); + Mage::throwException(Mage::helper('install')->__('Response from server isn\'t valid.')); } return $this; } diff --git a/app/code/core/Mage/Install/Model/Installer/Console.php b/app/code/core/Mage/Install/Model/Installer/Console.php index 79adfa638d..0a93b2cf24 100644 --- a/app/code/core/Mage/Install/Model/Installer/Console.php +++ b/app/code/core/Mage/Install/Model/Installer/Console.php @@ -94,6 +94,7 @@ protected function _getOptions() 'encryption_key' => array('comment' => ''), 'session_save' => array('comment' => ''), 'admin_frontname' => array('comment' => ''), + 'enable_charts' => array('comment' => ''), ); } return $this->_options; @@ -298,6 +299,7 @@ protected function _prepareData() 'session_save' => $this->_checkSessionSave($this->_args['session_save']), 'admin_frontname' => $this->_checkAdminFrontname($this->_args['admin_frontname']), 'skip_url_validation' => $this->_checkFlag($this->_args['skip_url_validation']), + 'enable_charts' => $this->_checkFlag($this->_args['enable_charts']), )); /** diff --git a/app/code/core/Mage/Install/Model/Installer/Db.php b/app/code/core/Mage/Install/Model/Installer/Db.php index 94c9ff5027..697b3fe225 100644 --- a/app/code/core/Mage/Install/Model/Installer/Db.php +++ b/app/code/core/Mage/Install/Model/Installer/Db.php @@ -47,6 +47,9 @@ class Mage_Install_Model_Installer_Db extends Mage_Install_Model_Installer_Abstr */ public function checkDatabase($data) { + if (!isset($data['db_name']) || empty($data['db_name'])) { + Mage::throwException(Mage::helper('install')->__('Database Name cannot be empty.')); + } $config = array( 'host' => $data['db_host'], 'username' => $data['db_user'], @@ -76,7 +79,7 @@ public function checkDatabase($data) } } catch (Exception $e){ - $this->_getInstaller()->getDataModel()->addError($e->getMessage()); + Mage::logException($e); Mage::throwException(Mage::helper('install')->__('Database connection error.')); } } diff --git a/app/code/core/Mage/Newsletter/Model/Mysql4/Queue.php b/app/code/core/Mage/Newsletter/Model/Mysql4/Queue.php index ae4b5bdb5f..ae1421fab2 100644 --- a/app/code/core/Mage/Newsletter/Model/Mysql4/Queue.php +++ b/app/code/core/Mage/Newsletter/Model/Mysql4/Queue.php @@ -106,43 +106,49 @@ public function setStores(Mage_Newsletter_Model_Queue $queue) $this->getTable('queue_store_link'), $this->_getWriteAdapter()->quoteInto('queue_id = ?', $queue->getId()) ); - - if (!is_array($queue->getStores())) { - $stores = array(); + + if (!is_array($queue->getStores())) { + $stores = array(); } else { $stores = $queue->getStores(); } - + foreach ($stores as $storeId) { $data = array(); $data['store_id'] = $storeId; $data['queue_id'] = $queue->getId(); $this->_getWriteAdapter()->insert($this->getTable('queue_store_link'), $data); } - $this->removeSubscribersFromQueue($queue); - if(count($stores)==0) { + if(count($stores) == 0) { return $this; } + $subscribers = Mage::getResourceSingleton('newsletter/subscriber_collection') ->addFieldToFilter('store_id', array('in'=>$stores)) ->useOnlySubscribed() ->load(); - + $subscriberIds = array(); - + foreach ($subscribers as $subscriber) { $subscriberIds[] = $subscriber->getId(); } - + if (count($subscriberIds) > 0) { $this->addSubscribersToQueue($queue, $subscriberIds); } - + return $this; } - + + /* + * Retrieving store id-s if they defined + * + * @param Mage_Newsletter_Model_Queue + * @return array + * */ public function getStores(Mage_Newsletter_Model_Queue $queue) { $select = $this->_getReadAdapter()->select() @@ -164,14 +170,9 @@ public function getStores(Mage_Newsletter_Model_Queue $queue) */ protected function _afterSave(Mage_Core_Model_Abstract $queue) { - if($queue->getSaveTemplateFlag()) { - $queue->getTemplate()->save(); - } - if($queue->getSaveStoresFlag()) { - $this->setStores($queue); + $this->setStores($queue); } - return $this; } diff --git a/app/code/core/Mage/Newsletter/Model/Mysql4/Queue/Collection.php b/app/code/core/Mage/Newsletter/Model/Mysql4/Queue/Collection.php index 891474f0ba..f8cb6a8025 100644 --- a/app/code/core/Mage/Newsletter/Model/Mysql4/Queue/Collection.php +++ b/app/code/core/Mage/Newsletter/Model/Mysql4/Queue/Collection.php @@ -49,11 +49,11 @@ protected function _construct() $this->_init('newsletter/queue'); } - /** * Joines templates information * * @return Mage_Newsletter_Model_Mysql4_Queue_Collection + * @deprecated since 1.4.0.1 */ public function addTemplateInfo() { $this->getSelect()->joinLeft(array('template'=>$this->getTable('template')), diff --git a/app/code/core/Mage/Newsletter/Model/Queue.php b/app/code/core/Mage/Newsletter/Model/Queue.php index 5eb32c7714..84cb0d4abe 100644 --- a/app/code/core/Mage/Newsletter/Model/Queue.php +++ b/app/code/core/Mage/Newsletter/Model/Queue.php @@ -29,9 +29,9 @@ * * @category Mage * @package Mage_Newsletter - * @author Magento Core Team + * @author Magento Core Team */ -class Mage_Newsletter_Model_Queue extends Mage_Core_Model_Abstract +class Mage_Newsletter_Model_Queue extends Mage_Core_Model_Template { /** * Newsletter Template object @@ -46,17 +46,27 @@ class Mage_Newsletter_Model_Queue extends Mage_Core_Model_Abstract */ protected $_subscribersCollection = null; + /** + * save template flag + * + * @var boolean + * @deprecated since 1.4.0.1 + */ protected $_saveTemplateFlag = false; + /** + * Save stores flag. + * + * @var boolean + */ protected $_saveStoresFlag = false; - protected $_stores = false; - /** - * Design changes object instance - * @var Varien_Object + * Stores assigned to queue. + * + * @var array */ - protected $_designConfig; + protected $_stores = array(); const STATUS_NEVER = 0; const STATUS_SENDING = 1; @@ -65,15 +75,23 @@ class Mage_Newsletter_Model_Queue extends Mage_Core_Model_Abstract const STATUS_PAUSE = 4; /** - * Default design area for emulation + * Initialize resource model */ - const DEFAULT_DESIGN_AREA = 'frontend'; - protected function _construct() { $this->_init('newsletter/queue'); } + /** + * Return: is this queue newly created or not. + * + * @return boolean + */ + public function isNew() + { + return (is_null($this->getQueueStatus())); + } + /** * Returns subscribers collection for this queue * @@ -92,11 +110,11 @@ public function getSubscribersCollection() /** * Add template data to queue. * - * @deprecated * @param Varien_Object $data * @return Mage_Newsletter_Model_Queue + * @deprecated since 1.4.0.1 */ - public function addTemplateData( $data ) + public function addTemplateData($data) { $template = $this->getTemplate(); if ($data->getTemplateId() && $data->getTemplateId() != $template->getId()) { @@ -106,11 +124,31 @@ public function addTemplateData( $data ) return $this; } + /** + * Set $_data['queue_start'] based on string from backend, which based on locale. + * + * @param string|null $startAt start date of the mailing queue + * @return Mage_Newsletter_Model_Queue + */ + public function setQueueStartAtByString($startAt) + { + if(is_null($startAt) || $startAt == '') { + $this->setQueueStartAt(null); + } else { + $locale = Mage::app()->getLocale(); + $format = $locale->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM); + $time = $locale->date($startAt, $format)->getTimestamp(); + $this->setQueueStartAt(Mage::getModel('core/date')->gmtDate(null, $time)); + } + return $this; + } + /** * Send messages to subscribers for this queue * * @param int $count * @param array $additionalVariables + * @return Mage_Newsletter_Model_Queue */ public function sendPerSubscriber($count=20, array $additionalVariables=array()) { @@ -129,27 +167,37 @@ public function sendPerSubscriber($count=20, array $additionalVariables=array()) ->setCurPage(1) ->load(); - if(!$this->getTemplate()) { - $this->addTemplateData($this); - if(!$this->getTemplate()->isPreprocessed()) { - $this->getTemplate()->preproccess(); - } - } + /* @var $sender Mage_Core_Model_Email_Template */ + $sender = Mage::getModel('core/email_template'); + $sender->setSenderName($this->getNewsletterSenderName()) + ->setSenderEmail($this->getNewsletterSenderEmail()) + ->setTemplateType(self::TYPE_HTML) + ->setTemplateSubject($this->getNewsletterSubject()) + ->setTemplateText($this->getNewsletterText()) + ->setTemplateStyles($this->getNewsletterStyles()) + ->setTemplateFilter(Mage::helper('newsletter')->getTemplateProcessor()); - // save current design settings - $currentDesignConfig = clone $this->_getDesignConfig(); foreach($collection->getItems() as $item) { - if ($this->_getDesignConfig()->getStore() != $item->getStoreId()) { - $this->_setDesignConfig(array('area' => self::DEFAULT_DESIGN_AREA, 'store' => $item->getStoreId())); - $this->_applyDesignConfig(); + $email = $item->getSubscriberEmail(); + $name = $item->getSubscriberFullName(); + + $sender->emulateDesign($item->getStoreId()); + $successSend = $sender->send($email, $name, array('subscriber'=>$item)); + $sender->revertDesign(); + + if($successSend) { + $item->received($this); + } else { + $problem = Mage::getModel('newsletter/problem'); + $problem->addSubscriberData($item) + ->addQueueData($queue) + ->addErrorData('Please refer to exeption.log') + ->save(); + + $item->received($this); } - $this->getTemplate()->send($item, array('subscriber'=>$item), null, $this); } - // restore previous design settings - $this->_setDesignConfig($currentDesignConfig->getData()); - $this->_applyDesignConfig(); - if(count($collection->getItems()) < $count-1 || count($collection->getItems()) == 0) { $this->setQueueFinishAt(now()); $this->setQueueStatus(self::STATUS_SENT); @@ -158,7 +206,13 @@ public function sendPerSubscriber($count=20, array $additionalVariables=array()) return $this; } - public function getDataForSave() { + /** + * Getter data for saving + * + * @return array + */ + public function getDataForSave() + { $data = array(); $data['template_id'] = $this->getTemplateId(); $data['queue_status'] = $this->getQueueStatus(); @@ -167,34 +221,72 @@ public function getDataForSave() { return $data; } + /** + * Add subscribers to queue. + * + * @param array $subscriberIds + * @return Mage_Newsletter_Model_Queue + */ public function addSubscribersToQueue(array $subscriberIds) { $this->_getResource()->addSubscribersToQueue($this, $subscriberIds); return $this; } + /** + * Setter for save template flag. + * + * @param boolean|integer|string $value + * @return Mage_Newsletter_Model_Queue + * @deprecated since 1.4.0.1 + */ public function setSaveTemplateFlag($value) { $this->_saveTemplateFlag = (boolean)$value; return $this; } + /** + * Getter for save template flag. + * + * @param void + * @return boolean + * @deprecated since 1.4.0.1 + */ public function getSaveTemplateFlag() { return $this->_saveTemplateFlag; } + /** + * Setter for save stores flag. + * + * @param boolean|integer|string $value + * @return Mage_Newsletter_Model_Queue + */ public function setSaveStoresFlag($value) { $this->_saveStoresFlag = (boolean)$value; return $this; } + /** + * Getter for save stores flag. + * + * @param void + * @return boolean + */ public function getSaveStoresFlag() { return $this->_saveStoresFlag; } + /** + * Setter for stores of queue. + * + * @param array + * @return Mage_Newsletter_Model_Queue + */ public function setStores(array $storesIds) { $this->setSaveStoresFlag(true); @@ -202,6 +294,11 @@ public function setStores(array $storesIds) return $this; } + /** + * Getter for stores of queue. + * + * @return array + */ public function getStores() { if(!$this->_stores) { @@ -226,67 +323,12 @@ public function getTemplate() } /** - * Setter for design changes + * Getter for template type * - * @param array $config - * @return Mage_Newsletter_Model_Queue + * @return int|string */ - protected function _setDesignConfig(array $config) - { - $this->_getDesignConfig()->setData($config); - return $this; + public function getType(){ + return $this->getNewsletterType(); } - /** - * Getter for design changes - * - * @return Varien_Object - */ - protected function _getDesignConfig() - { - if(is_null($this->_designConfig)) { - - $store = is_object(Mage::getDesign()->getStore()) - ? Mage::getDesign()->getStore()->getId() - : Mage::getDesign()->getStore(); - - $this->_designConfig = new Varien_Object(array( - 'area' => Mage::getDesign()->getArea(), - 'store' => $store - )); - } - return $this->_designConfig; - } - - protected function _applyDesignConfig() - { - $designConfig = $this->_getDesignConfig(); - - $design = Mage::getDesign(); - $designConfig->setOldArea($design->getArea()) - ->setOldStore($design->getStore()); - - if ($designConfig->hasData('area')) { - Mage::getDesign()->setArea($designConfig->getArea()); - } - - if ($designConfig->hasData('store')) { - $store = $designConfig->getStore(); - Mage::app()->setCurrentStore($store); - - $locale = new Zend_Locale(Mage::getStoreConfig(Mage_Core_Model_Locale::XML_PATH_DEFAULT_LOCALE, $store)); - Mage::app()->getLocale()->setLocale($locale); - Mage::app()->getLocale()->setLocaleCode($locale->toString()); - if ($designConfig->hasData('area')) { - Mage::getSingleton('core/translate')->setLocale($locale) - ->init($designConfig->getArea(), true); - } - - $design->setStore($store); - $design->setTheme(''); - $design->setPackageName(''); - } - - return $this; - } } diff --git a/app/code/core/Mage/Newsletter/Model/Subscriber.php b/app/code/core/Mage/Newsletter/Model/Subscriber.php index 37d6bb57fb..b50b147472 100644 --- a/app/code/core/Mage/Newsletter/Model/Subscriber.php +++ b/app/code/core/Mage/Newsletter/Model/Subscriber.php @@ -36,6 +36,7 @@ class Mage_Newsletter_Model_Subscriber extends Mage_Core_Model_Abstract const STATUS_SUBSCRIBED = 1; const STATUS_NOT_ACTIVE = 2; const STATUS_UNSUBSCRIBED = 3; + const STATUS_UNCONFIRMED = 4; const XML_PATH_CONFIRM_EMAIL_TEMPLATE = 'newsletter/subscription/confirm_email_template'; const XML_PATH_CONFIRM_EMAIL_IDENTITY = 'newsletter/subscription/confirm_email_identity'; @@ -46,6 +47,9 @@ class Mage_Newsletter_Model_Subscriber extends Mage_Core_Model_Abstract const XML_PATH_CONFIRMATION_FLAG = 'newsletter/subscription/confirm'; const XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG = 'newsletter/subscription/allow_guest_subscribe'; + /** + * @deprecated since 1.4.0.1 + */ const XML_PATH_SENDING_SET_RETURN_PATH = Mage_Core_Model_Email_Template::XML_PATH_SENDING_SET_RETURN_PATH; /** @@ -275,15 +279,17 @@ public function subscribe($email) } $isConfirmNeed = (Mage::getStoreConfig(self::XML_PATH_CONFIRMATION_FLAG) == 1) ? true : false; + $isOwnSubscribes = false; if (!$this->getId() || $this->getStatus() == self::STATUS_UNSUBSCRIBED || $this->getStatus() == self::STATUS_NOT_ACTIVE) { - if ($isConfirmNeed) { + if ($isConfirmNeed === true) { // if user subscribes own login email - confirmation is not needed $ownerId = Mage::getModel('customer/customer') ->setWebsiteId(Mage::app()->getStore()->getWebsiteId()) ->loadByEmail($email) ->getId(); - if ($customerSession->isLoggedIn() && $ownerId == $customerSession->getId()){ + $isOwnSubscribes = ($customerSession->isLoggedIn() && $ownerId == $customerSession->getId()); + if ($isOwnSubscribes == true){ $this->setStatus(self::STATUS_SUBSCRIBED); } else { @@ -307,7 +313,9 @@ public function subscribe($email) try { $this->save(); - if ($isConfirmNeed) { + if ($isConfirmNeed === true + && $isOwnSubscribes === false + ) { $this->sendConfirmationRequestEmail(); } else { $this->sendConfirmationSuccessEmail(); @@ -347,8 +355,8 @@ public function subscribeCustomer($customer) } if (!$customer->getIsSubscribed() && !$this->getId()) { - // If subscription flag not seted or customer not subscriber - // and no subscribe bellow + // If subscription flag not set or customer is not a subscriber + // and no subscribe below return $this; } @@ -356,21 +364,30 @@ public function subscribeCustomer($customer) $this->setSubscriberConfirmCode($this->randomSequence()); } + /* + * Logical mismatch between customer registration confirmation code and customer password confirmation + */ + $confirmation = null; + if ($customer->isConfirmationRequired() && ($customer->getConfirmation() != $customer->getPassword())) { + $confirmation = $customer->getConfirmation(); + } + + $subscribed_on_confirm = false; if($customer->hasIsSubscribed()) { - $status = $customer->getIsSubscribed() ? self::STATUS_SUBSCRIBED : self::STATUS_UNSUBSCRIBED; + $status = $customer->getIsSubscribed() ? (!is_null($confirmation) ? self::STATUS_UNCONFIRMED : self::STATUS_SUBSCRIBED) : self::STATUS_UNSUBSCRIBED; + } elseif (($this->getStatus() == self::STATUS_UNCONFIRMED) && (is_null($confirmation))) { + $status = self::STATUS_SUBSCRIBED; + $subscribed_on_confirm = true; } else { $status = ($this->getStatus() == self::STATUS_NOT_ACTIVE ? self::STATUS_UNSUBSCRIBED : $this->getStatus()); } - if($status != $this->getStatus()) { $this->setIsStatusChanged(true); } $this->setStatus($status); - - if(!$this->getId()) { $this->setStoreId($customer->getStoreId()) ->setCustomerId($customer->getId()) @@ -380,7 +397,7 @@ public function subscribeCustomer($customer) } $this->save(); - $sendSubscription = $customer->getData('sendSubscription'); + $sendSubscription = $customer->getData('sendSubscription') || $subscribed_on_confirm; if (is_null($sendSubscription) xor $sendSubscription) { if ($this->getIsStatusChanged() && $status == self::STATUS_UNSUBSCRIBED) { $this->sendUnsubscriptionEmail(); @@ -506,4 +523,18 @@ public function sendUnsubscriptionEmail() return $this; } + + /** + * Retrieve Subscribers Full Name if it was set + * + * @return string|null + */ + public function getSubscriberFullName() + { + $name = null; + if ($this->hasCustomerFirstname() || $this->hasCustomerLastname()) { + $name = $this->getCustomerFirstname() . ' ' . $this->getCustomerLastname(); + } + return $name; + } } diff --git a/app/code/core/Mage/Newsletter/Model/Template.php b/app/code/core/Mage/Newsletter/Model/Template.php index 869c8837cc..b69c925fb3 100644 --- a/app/code/core/Mage/Newsletter/Model/Template.php +++ b/app/code/core/Mage/Newsletter/Model/Template.php @@ -31,14 +31,8 @@ * @package Mage_Newsletter * @author Magento Core Team */ -class Mage_Newsletter_Model_Template extends Mage_Core_Model_Abstract +class Mage_Newsletter_Model_Template extends Mage_Core_Model_Template { - /** - * Types of template - */ - const TYPE_TEXT = 1; - const TYPE_HTML = 2; - /** * Template Text Preprocessed flag * @@ -107,7 +101,6 @@ public function validate() protected function _beforeSave() { $this->validate(); - $this->getTemplateTextPreprocessed(); return parent::_beforeSave(); } @@ -127,6 +120,7 @@ public function loadByCode($templateCode) * Return true if this template can be used for sending queue as main template * * @return boolean + * @deprecated since 1.4.0.1 */ public function isValidForSend() { @@ -137,13 +131,12 @@ public function isValidForSend() } /** - * Return true if template type eq text + * Getter for template type * - * @return boolean + * @return int|string */ - public function isPlain() - { - return $this->getTemplateType() == self::TYPE_TEXT; + public function getType(){ + return $this->getTemplateType(); } /** @@ -179,13 +172,19 @@ public function getTemplateTextPreprocessed() */ public function getProcessedTemplate(array $variables = array(), $usePreprocess = false) { - $processor = Mage::helper('newsletter')->getTemplateProcessor(); /* @var $processor Mage_Newsletter_Model_Template_Filter */ + $processor = Mage::helper('newsletter')->getTemplateProcessor(); if (!$this->_preprocessFlag) { $variables['this'] = $this; } + if (Mage::app()->isSingleStoreMode()) { + $processor->setStoreId(Mage::app()->getStore()); + } else { + $processor->setStoreId(Mage::app()->getRequest()->getParam('store_id')); + } + $processor ->setIncludeProcessor(array($this, 'getInclude')) ->setVariables($variables); @@ -233,6 +232,7 @@ public function getInclude($templateCode, array $variables) * Retrieve mail object instance * * @return Zend_Mail + * @deprecated since 1.4.0.1 */ public function getMail() { @@ -251,6 +251,7 @@ public function getMail() * @param string|null $name receiver name (if subscriber model not specified) * @param Mage_Newsletter_Model_Queue|null $queue queue model, used for problems reporting. * @return boolean + * @deprecated since 1.4.0.1 **/ public function send($subscriber, array $variables = array(), $name=null, Mage_Newsletter_Model_Queue $queue=null) { @@ -269,7 +270,7 @@ public function send($subscriber, array $variables = array(), $name=null, Mage_N $email = (string) $subscriber; } - if (Mage::getStoreConfigFlag(Mage_Newsletter_Model_Subscriber::XML_PATH_SENDING_SET_RETURN_PATH)) { + if (Mage::getStoreConfigFlag(Mage_Core_Model_Email_Template::XML_PATH_SENDING_SET_RETURN_PATH)) { $this->getMail()->setReturnPath($this->getTemplateSenderEmail()); } @@ -325,6 +326,7 @@ public function send($subscriber, array $variables = array(), $name=null, Mage_N * Prepare Process (with save) * * @return Mage_Newsletter_Model_Template + * @deprecated since 1.4.0.1 */ public function preprocess() { @@ -361,7 +363,7 @@ public function getTemplateText() { if (!$this->getData('template_text') && !$this->getId()) { $this->setData('template_text', - Mage::helper('newsletter')->__(' Follow this link to unsubscribe {{var subscriber.getUnsubscriptionLink()}}') + Mage::helper('newsletter')->__('Follow this link to unsubscribe {{var subscriber.getUnsubscriptionLink()}}') ); } diff --git a/app/code/core/Mage/Newsletter/Model/Template/Filter.php b/app/code/core/Mage/Newsletter/Model/Template/Filter.php index 21bdab61b8..214f0a7de0 100644 --- a/app/code/core/Mage/Newsletter/Model/Template/Filter.php +++ b/app/code/core/Mage/Newsletter/Model/Template/Filter.php @@ -44,7 +44,7 @@ public function widgetDirective($construction) if (!isset($this->_templateVars['subscriber'])) { return $construction[0]; } - + $construction[2] .= sprintf(' store_id ="%s"', $this->getStoreId()); return parent::widgetDirective($construction); } } diff --git a/app/code/core/Mage/Newsletter/controllers/SubscriberController.php b/app/code/core/Mage/Newsletter/controllers/SubscriberController.php index d13c999f0a..5dca26f1b5 100644 --- a/app/code/core/Mage/Newsletter/controllers/SubscriberController.php +++ b/app/code/core/Mage/Newsletter/controllers/SubscriberController.php @@ -50,7 +50,7 @@ public function newAction() if (Mage::getStoreConfig(Mage_Newsletter_Model_Subscriber::XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG) != 1 && !$customerSession->isLoggedIn()) { - Mage::throwException($this->__('Sorry, but administrator denied subscription for guests. Please register.', Mage::getUrl('customer/account/create/'))); + Mage::throwException($this->__('Sorry, but administrator denied subscription for guests. Please register.', Mage::helper('customer')->getRegisterUrl())); } $ownerId = Mage::getModel('customer/customer') @@ -58,7 +58,7 @@ public function newAction() ->loadByEmail($email) ->getId(); if ($ownerId !== null && $ownerId != $customerSession->getId()) { - Mage::throwException($this->__('Sorry, but your can not subscribe email adress assigned to another user.')); + Mage::throwException($this->__('This email address is already assigned to another user.')); } $status = Mage::getModel('newsletter/subscriber')->subscribe($email); diff --git a/app/code/core/Mage/Newsletter/etc/config.xml b/app/code/core/Mage/Newsletter/etc/config.xml index 244eee1b03..ff38636419 100644 --- a/app/code/core/Mage/Newsletter/etc/config.xml +++ b/app/code/core/Mage/Newsletter/etc/config.xml @@ -28,7 +28,7 @@ - 0.8.2 + 0.8.3 diff --git a/app/code/core/Mage/Newsletter/sql/newsletter_setup/mysql4-upgrade-0.8.2-0.8.3.php b/app/code/core/Mage/Newsletter/sql/newsletter_setup/mysql4-upgrade-0.8.2-0.8.3.php new file mode 100644 index 0000000000..06dec2d1a5 --- /dev/null +++ b/app/code/core/Mage/Newsletter/sql/newsletter_setup/mysql4-upgrade-0.8.2-0.8.3.php @@ -0,0 +1,88 @@ +getTable('newsletter_queue'); +$templateTable = $installer->getTable('newsletter_template'); +$conn = $installer->getConnection(); + + +$conn->addColumn($queueTable, 'newsletter_type', "int(3) default NULL AFTER `template_id`"); +$conn->addColumn($queueTable, 'newsletter_text', "text AFTER `newsletter_type`"); +$conn->addColumn($queueTable, 'newsletter_styles', "text AFTER `newsletter_text`"); +$conn->addColumn($queueTable, 'newsletter_subject', "varchar(200) default NULL AFTER `newsletter_styles`"); +$conn->addColumn($queueTable, 'newsletter_sender_name', "varchar(200) default NULL AFTER `newsletter_subject`"); +$conn->addColumn($queueTable, 'newsletter_sender_email', + "varchar(200) character set latin1 collate latin1_general_ci default NULL AFTER `newsletter_sender_name`"); + +$conn->modifyColumn($templateTable, 'template_text_preprocessed', "text comment 'deprecated since 1.4.0.1'"); + +$conn->beginTransaction(); + +try { + $select = $conn->select() + ->from(array('main_table' => $queueTable), array('main_table.queue_id', 'main_table.template_id')) + ->joinLeft( + $templateTable, + "$templateTable.template_id = main_table.template_id", + array( + 'template_type', + 'template_text', + 'template_styles', + 'template_subject', + 'template_sender_name', + 'template_sender_email' + ) + ); + $rows = $conn->fetchAll($select); + + if ($rows) { + foreach($rows as $row) { + $whereBind = $conn + ->quoteInto('queue_id=?', $row['queue_id']); + + $conn + ->update( + $queueTable, + array( + 'newsletter_type' => $row['template_type'], + 'newsletter_text' => $row['template_text'], + 'newsletter_styles' => $row['template_styles'], + 'newsletter_subject' => $row['template_subject'], + 'newsletter_sender_name' => $row['template_sender_name'], + 'newsletter_sender_email' => $row['template_sender_email'] + ), + $whereBind + ); + } + } + + $conn->commit(); +} catch (Exception $e) { + $conn->rollback(); + throw $e; +} diff --git a/app/code/core/Mage/Page/Block/Html/Head.php b/app/code/core/Mage/Page/Block/Html/Head.php index c740aa1d02..3a0c7371c5 100644 --- a/app/code/core/Mage/Page/Block/Html/Head.php +++ b/app/code/core/Mage/Page/Block/Html/Head.php @@ -466,4 +466,37 @@ public function getIncludes() } return $this->_data['includes']; } + + /** + * Getter for path to Favicon + * + * @return string + */ + public function getFaviconFile() + { + if (empty($this->_data['favicon_file'])) { + $this->_data['favicon_file'] = $this->_getFaviconFile(); + } + return $this->_data['favicon_file']; + } + + /** + * Retrieve path to Favicon + * + * @return string + */ + protected function _getFaviconFile() + { + $folderName = Mage_Adminhtml_Model_System_Config_Backend_Image_Favicon::UPLOAD_DIR; + $storeConfig = Mage::getStoreConfig('design/head/shortcut_icon'); + $faviconFile = Mage::getBaseUrl('media') . $folderName . '/' . $storeConfig; + $absolutePath = Mage::getBaseDir('media') . '/' . $folderName . '/' . $storeConfig; + + if(!is_null($storeConfig) && is_file($absolutePath)) { + $url = $faviconFile; + } else { + $url = $this->getSkinUrl('favicon.ico'); + } + return $url; + } } diff --git a/app/code/core/Mage/Page/Block/Html/Welcome.php b/app/code/core/Mage/Page/Block/Html/Welcome.php new file mode 100644 index 0000000000..0c779bf5f4 --- /dev/null +++ b/app/code/core/Mage/Page/Block/Html/Welcome.php @@ -0,0 +1,45 @@ + + */ +class Mage_Page_Block_Html_Welcome extends Mage_Core_Block_Template +{ + /** + * Get block messsage + * + * @return string + */ + protected function _toHtml() + { + return Mage::app()->getLayout()->getBlock('header')->getWelcome(); + } +} diff --git a/app/code/core/Mage/Page/Block/Template/Links.php b/app/code/core/Mage/Page/Block/Template/Links.php index c0a808a4b7..d582aa04c9 100644 --- a/app/code/core/Mage/Page/Block/Template/Links.php +++ b/app/code/core/Mage/Page/Block/Template/Links.php @@ -92,23 +92,27 @@ public function addLink($label, $url='', $title='', $prepare=false, $urlParams=a 'after_text' => $afterText, )); + $this->_links[$this->_getNewPosition($position)] = $link; if (intval($position) > 0) { - while (isset($this->_links[$position])) { - $position++; - } - $this->_links[$position] = $link; - ksort($this->_links); - } else { - $position = 0; - foreach ($this->_links as $k=>$v) { - $position = $k; - } - $this->_links[$position+10] = $link; + ksort($this->_links); } return $this; } + /** + * Add block to link list + * + * @param string $blockName + * @return Mage_Page_Block_Template_Links + */ + public function addLinkBlock($blockName) + { + $block = $this->getLayout()->getBlock($blockName); + $this->_links[$this->_getNewPosition((int)$block->getPosition())] = $block; + return $this; + } + /** * Removes link by url * @@ -126,6 +130,28 @@ public function removeLinkByUrl($url) return $this; } + /** + * Get cache key informative items + * Provide string array key to share specific info item with FPC placeholder + * + * @return array + */ + public function getCacheKeyInfo() + { + $links = array(); + if (!empty($this->_links)) { + foreach ($this->_links as $position => $link) { + if ($link instanceof Varien_Object) { + $links[$position] = $link->getData(); + } + } + } + return parent::getCacheKeyInfo() + array( + 'links' => base64_encode(serialize($links)), + 'name' => $this->getNameInLayout() + ); + } + /** * Prepare tag attributes * @@ -162,4 +188,26 @@ protected function _beforeToHtml() return parent::_beforeToHtml(); } + /** + * Return new link position in list + * + * @param int $position + * @return int + */ + protected function _getNewPosition($position = 0) + { + if (intval($position) > 0) { + while (isset($this->_links[$position])) { + $position++; + } + } else { + $position = 0; + foreach ($this->_links as $k=>$v) { + $position = $k; + } + $position += 10; + } + return $position; + } + } diff --git a/app/code/core/Mage/Page/Block/Template/Links/Block.php b/app/code/core/Mage/Page/Block/Template/Links/Block.php new file mode 100644 index 0000000000..bdc997f85c --- /dev/null +++ b/app/code/core/Mage/Page/Block/Template/Links/Block.php @@ -0,0 +1,201 @@ + + */ +class Mage_Page_Block_Template_Links_Block extends Mage_Core_Block_Template +{ + + /** + * First link flag + * + * @var bool + */ + protected $_isFirst = false; + + /** + * Last link flag + * + * @var bool + */ + protected $_isLast = false; + + /** + * Link label + * + * @var string + */ + protected $_label = null; + + /** + * Link url + * + * @var string + */ + protected $_url = null; + + /** + * Link title + * + * @var string + */ + protected $_title = null; + + /** + * Li elemnt params + * + * @var string + */ + protected $_liPparams = null; + + /** + * A elemnt params + * + * @var string + */ + protected $_aPparams = null; + + /** + * Message before link text + * + * @var string + */ + protected $_beforeText = null; + + /** + * Message after link text + * + * @var string + */ + protected $_afterText = null; + + /** + * Position in link list + * @var int + */ + protected $_position = 0; + + /** + * Set default template + * + */ + protected function _construct() + { + $this->setTemplate('page/template/linksblock.phtml'); + } + + + /** + * Return link position in link list + * + * @return in + */ + public function getPosition() + { + return $this->_position; + } + + /** + * Return first position flag + * + * @return bool + */ + public function getIsFirst() + { + return $this->_isFirst; + } + + /** + * Set first list flag + * + * @param bool $value + * return Mage_Page_Block_Template_Links_Block + */ + public function setIsFirst($value) + { + $this->_isFirst = (bool)$value; + return $this; + } + + /** + * Return last position flag + * + * @return bool + */ + public function getIsLast() + { + return $this->_isLast; + } + + /** + * Set last list flag + * + * @param bool $value + * return Mage_Page_Block_Template_Links_Block + */ + public function setIsLast($value) + { + $this->_isLast = (bool)$value; + return $this; + } + + /** + * Return link label + * + * @return string + */ + public function getLabel() + { + return $this->_label; + } + + /** + * Return link title + * + * @return string + */ + public function getTitle() + { + return $this->_title; + } + + /** + * Return link url + * + * @return string + */ + public function getLinkUrl() + { + return $this->_url; + } + +} diff --git a/app/code/core/Mage/Page/Helper/Layout.php b/app/code/core/Mage/Page/Helper/Layout.php index 303934e5c8..2d6cd8a074 100644 --- a/app/code/core/Mage/Page/Helper/Layout.php +++ b/app/code/core/Mage/Page/Helper/Layout.php @@ -91,6 +91,11 @@ public function applyTemplate($pageLayout = null) */ public function getCurrentPageLayout() { + if ($this->getLayout()->getBlock('root') && + $this->getLayout()->getBlock('root')->getLayoutCode()) { + return $this->_getConfig()->getPageLayout($this->getLayout()->getBlock('root')->getLayoutCode()); + } + // All loaded handles $handles = $this->getLayout()->getUpdate()->getHandles(); // Handles used in page layouts diff --git a/app/code/core/Mage/Page/etc/config.xml b/app/code/core/Mage/Page/etc/config.xml index ed5a9c1659..63a410cb69 100644 --- a/app/code/core/Mage/Page/etc/config.xml +++ b/app/code/core/Mage/Page/etc/config.xml @@ -46,7 +46,7 @@ - + page_empty diff --git a/app/code/core/Mage/Page/etc/system.xml b/app/code/core/Mage/Page/etc/system.xml index 508371405c..cbb7e147de 100644 --- a/app/code/core/Mage/Page/etc/system.xml +++ b/app/code/core/Mage/Page/etc/system.xml @@ -37,6 +37,17 @@ 1 1 + + + Allowed file types: ICO, PNG, GIF, JPEG, APNG, SVG. Not all browsers support all these formats! + image + adminhtml/system_config_backend_image_favicon + favicon + 5 + 1 + 1 + 1 + text diff --git a/app/code/core/Mage/Paygate/Model/Authorizenet.php b/app/code/core/Mage/Paygate/Model/Authorizenet.php index 54ca9db645..00a98b9961 100644 --- a/app/code/core/Mage/Paygate/Model/Authorizenet.php +++ b/app/code/core/Mage/Paygate/Model/Authorizenet.php @@ -64,7 +64,8 @@ class Mage_Paygate_Model_Authorizenet extends Mage_Payment_Model_Method_Cc protected $_canAuthorize = true; protected $_canCapture = true; protected $_canCapturePartial = false; - protected $_canRefund = false; + protected $_canRefund = true; + protected $_canRefundInvoicePartial = true; protected $_canVoid = true; protected $_canUseInternal = true; protected $_canUseCheckout = true; diff --git a/app/code/core/Mage/Payment/Block/Form/Container.php b/app/code/core/Mage/Payment/Block/Form/Container.php index b1b7f745cf..8520648fd8 100644 --- a/app/code/core/Mage/Payment/Block/Form/Container.php +++ b/app/code/core/Mage/Payment/Block/Form/Container.php @@ -113,10 +113,15 @@ public function getMethods() { $methods = $this->getData('methods'); if (is_null($methods)) { - $store = $this->getQuote() ? $this->getQuote()->getStoreId() : null; - $methods = $this->helper('payment')->getStoreMethods($store, $this->getQuote()); + $quote = $this->getQuote(); + $store = $quote ? $quote->getStoreId() : null; + $methods = $this->helper('payment')->getStoreMethods($store, $quote); + $total = $quote->getBaseGrandTotal(); foreach ($methods as $key => $method) { - if ($this->_canUseMethod($method)) { + if ($this->_canUseMethod($method) + && ($total != 0 + || $method->getCode() == 'free' + || ($quote->hasRecurringItems() && $method->canManageRecurringProfiles()))) { $this->_assignMethod($method); } else { diff --git a/app/code/core/Mage/Payment/Block/Info/Cc.php b/app/code/core/Mage/Payment/Block/Info/Cc.php index 6da238ba04..6435281b79 100644 --- a/app/code/core/Mage/Payment/Block/Info/Cc.php +++ b/app/code/core/Mage/Payment/Block/Info/Cc.php @@ -90,12 +90,14 @@ protected function _prepareSpecificInformation($transport = null) if ($this->getInfo()->getCcLast4()) { $data[Mage::helper('payment')->__('Credit Card Number')] = sprintf('xxxx-%s', $this->getInfo()->getCcLast4()); } - if ($ccSsIssue = $this->getInfo()->getCcSsIssue()) { - $data[Mage::helper('payment')->__('Switch/Solo Issue Number')] = $ccSsIssue; - } if (!$this->getIsSecureMode()) { - if ($year = $this->getInfo()->getCcSsStartYear() && $month = $this->getInfo()->getCcStartMonth()) { - $data[Mage::helper('payment')->__('Switch/Solo Start Date')] = $this->_formatCardDate($year, $month); + if ($ccSsIssue = $this->getInfo()->getCcSsIssue()) { + $data[Mage::helper('payment')->__('Switch/Solo/Maestro Issue Number')] = $ccSsIssue; + } + $year = $this->getInfo()->getCcSsStartYear(); + $month = $this->getInfo()->getCcSsStartMonth(); + if ($year && $month) { + $data[Mage::helper('payment')->__('Switch/Solo/Maestro Start Date')] = $this->_formatCardDate($year, $month); } } return $transport->setData(array_merge($data, $transport->getData())); diff --git a/app/code/core/Mage/Payment/Model/Billing/Agreement.php b/app/code/core/Mage/Payment/Model/Billing/Agreement.php deleted file mode 100644 index e0783b1a6f..0000000000 --- a/app/code/core/Mage/Payment/Model/Billing/Agreement.php +++ /dev/null @@ -1,110 +0,0 @@ - - */ - -abstract class Mage_Payment_Model_Billing_Agreement extends Mage_Core_Model_Abstract -{ - /** - * Payment method instance - * - * @var Mage_Payment_Model_Method_Abstract - */ - protected $_paymentMethodInstance = null; - - /** - * Init billing agreement - * - */ - abstract public function initToken(); - - /** - * Verify billing agreement details - * - */ - abstract public function verifyToken(); - - /** - * Create billing agreement - * - * @param Mage_Customer_Model_Customer $customer - */ - abstract public function place(Mage_Customer_Model_Customer $customer); - - /** - * Cancel billing agreement - * - */ - abstract public function cancel(); - - /** - * Retreive payment method instance - * - * @throws Mage_Core_Exception - * @return Mage_Payment_Model_Method_Abstract - */ - public function getPaymentMethodInstance() - { - if (is_null($this->_paymentMethodInstance)) { - $this->_paymentMethodInstance = Mage::helper('payment')->getMethodInstance($this->getMethodCode()); - } - return $this->_paymentMethodInstance; - } - - /** - * Validate data before save - * - * @return Mage_Payment_Model_Billing_Agreement - */ - public function validate() - { - if (is_null($this->_paymentMethodInstance) - || !$this->_paymentMethodInstance->getCode() - || !$this->getCustomerId() - || !$this->getReferenceId() - || !$this->getStatus()) { - throw new Mage_Core_Exception('Not enough data to save billing agreement instance.'); - } - return $this; - } - - /** - * Before save - * - * @return Mage_Core_Model_Abstract - */ - protected function _beforeSave() - { - $this->validate(); - return parent::_beforeSave(); - } -} diff --git a/app/code/core/Mage/Payment/Model/Billing/AgreementAbstract.php b/app/code/core/Mage/Payment/Model/Billing/AgreementAbstract.php index a262d73084..eda3d72162 100644 --- a/app/code/core/Mage/Payment/Model/Billing/AgreementAbstract.php +++ b/app/code/core/Mage/Payment/Model/Billing/AgreementAbstract.php @@ -78,8 +78,8 @@ public function getPaymentMethodInstance() { if (is_null($this->_paymentMethodInstance)) { $this->_paymentMethodInstance = Mage::helper('payment')->getMethodInstance($this->getMethodCode()); - $this->_paymentMethodInstance->setStore($this->getStoreId()); } + $this->_paymentMethodInstance->setStore($this->getStoreId()); return $this->_paymentMethodInstance; } @@ -91,7 +91,7 @@ public function getPaymentMethodInstance() public function isValid() { $this->_errors = array(); - if (is_null($this->_paymentMethodInstance) || !$this->_paymentMethodInstance->getCode()) { + if (is_null($this->getPaymentMethodInstance()) || !$this->getPaymentMethodInstance()->getCode()) { $this->_errors[] = Mage::helper('payment')->__('Payment method code is not set.'); } if (!$this->getReferenceId()) { diff --git a/app/code/core/Mage/Payment/Model/Config.php b/app/code/core/Mage/Payment/Model/Config.php index 5d72a54a9d..7029d57cf3 100644 --- a/app/code/core/Mage/Payment/Model/Config.php +++ b/app/code/core/Mage/Payment/Model/Config.php @@ -66,7 +66,10 @@ public function getAllMethods($store=null) $methods = array(); $config = Mage::getStoreConfig('payment', $store); foreach ($config as $code => $methodConfig) { - $methods[$code] = $this->_getMethod($code, $methodConfig); + $data = $this->_getMethod($code, $methodConfig); + if (false !== $data) { + $methods[$code] = $data; + } } return $methods; } @@ -76,7 +79,16 @@ protected function _getMethod($code, $config, $store=null) if (isset(self::$_methods[$code])) { return self::$_methods[$code]; } + if (empty($config['model'])) { + return false; + } $modelName = $config['model']; + + $className = Mage::getConfig()->getModelClassName($modelName); + if (!mageFindClassFile($className)) { + return false; + } + $method = Mage::getModel($modelName); $method->setId($code)->setStore($store); self::$_methods[$code] = $method; diff --git a/app/code/core/Mage/Payment/Model/Method/Cc.php b/app/code/core/Mage/Payment/Model/Method/Cc.php index 8787c4ffd8..7049299bdb 100644 --- a/app/code/core/Mage/Payment/Model/Method/Cc.php +++ b/app/code/core/Mage/Payment/Model/Method/Cc.php @@ -99,8 +99,6 @@ public function validate() $ccType = ''; - - if (in_array($info->getCcType(), $availableTypes)){ if ($this->validateCcNum($ccNumber) // Other credit card type number validation @@ -109,10 +107,9 @@ public function validate() $ccType = 'OT'; $ccTypeRegExpList = array( //Solo, Switch or Maestro. International safe + //'SS' => '/^((6759[0-9]{12})|(6334|6767[0-9]{12})|(6334|6767[0-9]{14,15})|(5018|5020|5038|6304|6759|6761|6763[0-9]{12,19})|(49[013][1356][0-9]{12})|(633[34][0-9]{12})|(633110[0-9]{10})|(564182[0-9]{10}))([0-9]{2,3})?$/', // Maestro / Solo 'SO' => '/(^(6334)[5-9](\d{11}$|\d{13,14}$))|(^(6767)(\d{12}$|\d{14,15}$))/', // Solo only 'SM' => '/(^(5[0678])\d{11,18}$)|(^(6[^05])\d{11,18}$)|(^(601)[^1]\d{9,16}$)|(^(6011)\d{9,11}$)|(^(6011)\d{13,16}$)|(^(65)\d{11,13}$)|(^(65)\d{15,18}$)|(^(49030)[2-9](\d{10}$|\d{12,13}$))|(^(49033)[5-9](\d{10}$|\d{12,13}$))|(^(49110)[1-2](\d{10}$|\d{12,13}$))|(^(49117)[4-9](\d{10}$|\d{12,13}$))|(^(49118)[0-2](\d{10}$|\d{12,13}$))|(^(4936)(\d{12}$|\d{14,15}$))/', - - 'SS' => '/^((6759[0-9]{12})|(6334|6767[0-9]{12})|(6334|6767[0-9]{14,15})|(5018|5020|5038|6304|6759|6761|6763[0-9]{12,19})|(49[013][1356][0-9]{12})|(633[34][0-9]{12})|(633110[0-9]{10})|(564182[0-9]{10}))([0-9]{2,3})?$/', // Maestro / Solo 'VI' => '/^4[0-9]{12}([0-9]{3})?$/', // Visa 'MC' => '/^5[1-5][0-9]{14}$/', // Master Card 'AE' => '/^3[47][0-9]{13}$/', // American Express diff --git a/app/code/core/Mage/Payment/Model/Method/Free.php b/app/code/core/Mage/Payment/Model/Method/Free.php index 1e4b00a50c..fb7c7e1f7e 100644 --- a/app/code/core/Mage/Payment/Model/Method/Free.php +++ b/app/code/core/Mage/Payment/Model/Method/Free.php @@ -34,6 +34,14 @@ */ class Mage_Payment_Model_Method_Free extends Mage_Payment_Model_Method_Abstract { + + /** + * Payment Method features + * @var bool + */ + protected $_canAuthorize = true; + protected $_canCapture = true; + /** * Payment code name * @@ -52,4 +60,17 @@ public function isAvailable($quote = null) return parent::isAvailable($quote) && (!empty($quote)) && (Mage::app()->getStore()->roundPrice($quote->getGrandTotal()) == 0); } + + /** + * Get config peyment action + * + * @return string + */ + public function getConfigPaymentAction() + { + if ('pending' == $this->getConfigData('order_status')) { + return Mage_Payment_Model_Method_Abstract::ACTION_AUTHORIZE; + } + return parent::getConfigPaymentAction(); + } } diff --git a/app/code/core/Mage/Payment/Model/Recurring/Profile.php b/app/code/core/Mage/Payment/Model/Recurring/Profile.php index ebe989fbbf..a7b8d34c24 100644 --- a/app/code/core/Mage/Payment/Model/Recurring/Profile.php +++ b/app/code/core/Mage/Payment/Model/Recurring/Profile.php @@ -38,6 +38,17 @@ class Mage_Payment_Model_Recurring_Profile extends Mage_Core_Model_Abstract const BUY_REQUEST_START_DATETIME = 'recurring_profile_start_datetime'; const PRODUCT_OPTIONS_KEY = 'recurring_profile_options'; + /** + * Period units + * + * @var string + */ + const PERIOD_UNIT_DAY = 'day'; + const PERIOD_UNIT_WEEK = 'week'; + const PERIOD_UNIT_SEMI_MONTH = 'semi_month'; + const PERIOD_UNIT_MONTH = 'month'; + const PERIOD_UNIT_YEAR = 'year'; + /** * Errors collected during validation * @@ -93,17 +104,27 @@ public function isValid() $this->_errors['schedule_description'][] = Mage::helper('payment')->__('Schedule description must be not empty.'); } - // period unit and frequency, trial period unit and trial frequency + // period unit and frequency if (!$this->getPeriodUnit() || !in_array($this->getPeriodUnit(), $this->getAllPeriodUnits(false), true)) { $this->_errors['period_unit'][] = Mage::helper('payment')->__('Billing period unit is not defined or wrong.'); - } elseif ($this->getPeriodFrequency()) { - $this->_validatePeriodFrequency('period_unit', 'period_frequency'); } + if ($this->getPeriodFrequency() && !$this->_validatePeriodFrequency('period_unit', 'period_frequency')) { + $this->_errors['period_frequency'][] = Mage::helper('payment')->__('Period frequency is wrong.');; + } + + // trial period unit, trial frequency, trial period max cycles, trial billing amount if ($this->getTrialPeriodUnit()) { if (!in_array($this->getTrialPeriodUnit(), $this->getAllPeriodUnits(false), true)) { $this->_errors['trial_period_unit'][] = Mage::helper('payment')->__('Trial billing period unit is wrong.'); - } elseif ($this->getTrialPeriodFrequency()) { - $this->_validatePeriodFrequency('trial_period_unit', 'trial_period_frequency'); + } + if (!$this->getTrialPeriodFrequency() || !$this->_validatePeriodFrequency('trial_period_unit', 'trial_period_frequency')) { + $this->_errors['trial_period_frequency'][] = Mage::helper('payment')->__('Trial period frequency is wrong.'); + } + if (!$this->getTrialPeriodMaxCycles()) { + $this->_errors['trial_period_max_cycles'][] = Mage::helper('payment')->__('Trial period max cycles is wrong.'); + } + if (!$this->getTrialBillingAmount()) { + $this->_errors['trial_billing_amount'][] = Mage::helper('payment')->__('Trial billing amount is wrong.'); } } @@ -289,7 +310,7 @@ public function exportStartDatetime($asString = true) if (!$datetime || !$this->_locale || !$this->_store) { return; } - $date = $this->_locale->storeDate($this->_store, $datetime, true); + $date = $this->_locale->storeDate($this->_store, strtotime($datetime), true); if ($asString) { return $date->toString($this->_locale->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT)); } @@ -328,7 +349,14 @@ public function setStore(Mage_Core_Model_Store $store) */ public function getAllPeriodUnits($withLabels = true) { - $units = array('day', 'week', 'semi_month', 'month', 'year'); + $units = array( + self::PERIOD_UNIT_DAY, + self::PERIOD_UNIT_WEEK, + self::PERIOD_UNIT_SEMI_MONTH, + self::PERIOD_UNIT_MONTH, + self::PERIOD_UNIT_YEAR + ); + if ($withLabels) { $result = array(); foreach ($units as $unit) { @@ -347,11 +375,11 @@ public function getAllPeriodUnits($withLabels = true) public function getPeriodUnitLabel($unit) { switch ($unit) { - case 'day': return Mage::helper('payment')->__('Day'); - case 'week': return Mage::helper('payment')->__('Week'); - case 'semi_month': return Mage::helper('payment')->__('Two Weeks'); - case 'month': return Mage::helper('payment')->__('Month'); - case 'year': return Mage::helper('payment')->__('Year'); + case self::PERIOD_UNIT_DAY: return Mage::helper('payment')->__('Day'); + case self::PERIOD_UNIT_WEEK: return Mage::helper('payment')->__('Week'); + case self::PERIOD_UNIT_SEMI_MONTH: return Mage::helper('payment')->__('Two Weeks'); + case self::PERIOD_UNIT_MONTH: return Mage::helper('payment')->__('Month'); + case self::PERIOD_UNIT_YEAR: return Mage::helper('payment')->__('Year'); } return $unit; } @@ -546,13 +574,14 @@ protected function getMethodInstance() * * @param string $unitKey * @param string $frequencyKey + * @return bool */ protected function _validatePeriodFrequency($unitKey, $frequencyKey) { -// TODO: implement - // check accordance of the unit and frequency - // $this->_errors - // if set, invoke payment method instance? + if ($this->getData($unitKey) == self::PERIOD_UNIT_SEMI_MONTH && $this->getData($frequencyKey) != 1) { + return false; + } + return true; } /** @@ -602,7 +631,7 @@ protected function _renderSchedule($periodKey, $frequencyKey, $cyclesKey) if (!$period || !$frequency) { return $result; } - if ('semi_month' == $period) { + if (self::PERIOD_UNIT_SEMI_MONTH == $period) { $frequency = ''; } $result[] = Mage::helper('payment')->__('%s %s cycle.', $frequency, $this->getPeriodUnitLabel($period)); diff --git a/app/code/core/Mage/Payment/etc/config.xml b/app/code/core/Mage/Payment/etc/config.xml index 0c5014e4b6..ec3ffc1998 100644 --- a/app/code/core/Mage/Payment/etc/config.xml +++ b/app/code/core/Mage/Payment/etc/config.xml @@ -77,11 +77,16 @@ Discover 30 - - SS - Maestro/Solo + + SM + Maestro/Switch 40 - + + + SO + Solo + 45 + JCB JCB diff --git a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/ApiWizard.php b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/ApiWizard.php index d96889cf7c..3ab93f8c85 100644 --- a/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/ApiWizard.php +++ b/app/code/core/Mage/Paypal/Block/Adminhtml/System/Config/ApiWizard.php @@ -66,6 +66,9 @@ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) 'button_label' => Mage::helper('paypal')->__($originalData['button_label']), 'button_url' => $originalData['button_url'], 'html_id' => $element->getHtmlId(), + 'sandbox_button_label' => Mage::helper('paypal')->__($originalData['sandbox_button_label']), + 'sandbox_button_url' => $originalData['sandbox_button_url'], + 'sandbox_html_id' => 'sandbox_' . $element->getHtmlId(), )); return $this->_toHtml(); } diff --git a/app/code/core/Mage/Paypal/Block/Express/Shortcut.php b/app/code/core/Mage/Paypal/Block/Express/Shortcut.php index ab9515b351..8ccf8baf9d 100644 --- a/app/code/core/Mage/Paypal/Block/Express/Shortcut.php +++ b/app/code/core/Mage/Paypal/Block/Express/Shortcut.php @@ -72,8 +72,9 @@ protected function _beforeToHtml() return $result; } - // validate minimum quote amount - if (null !== $quote && !$quote->validateMinimumAmount()) { + // validate minimum quote amount and validate quote for zero grandtotal + if (null !== $quote && (!$quote->validateMinimumAmount() + || (!$quote->getGrandTotal() && !$quote->hasNominalItems()))) { $this->_shouldRender = false; return $result; } diff --git a/app/code/core/Mage/Paypal/Controller/Express/Abstract.php b/app/code/core/Mage/Paypal/Controller/Express/Abstract.php index ae23c9501d..1f71a0d617 100644 --- a/app/code/core/Mage/Paypal/Controller/Express/Abstract.php +++ b/app/code/core/Mage/Paypal/Controller/Express/Abstract.php @@ -63,11 +63,10 @@ public function startAction() $customer = Mage::getSingleton('customer/session')->getCustomer(); if ($customer && $customer->getId()) { - $this->_checkout->setCustomer($customer); + $this->_checkout->setCustomerWithAddressChange($customer, null, $this->_getQuote()->getShippingAddress()); } // billing agreement - $customerId = Mage::getSingleton('customer/session')->getCustomerId(); $isBARequested = (bool)$this->getRequest() ->getParam(Mage_Paypal_Model_Express_Checkout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT); if ($customer && $customer->getId()) { @@ -75,8 +74,10 @@ public function startAction() } // giropay - $this->_checkout->prepareGiropayUrls(Mage::getUrl('checkout/onepage/success'), - Mage::getUrl('paypal/express/cancel'), Mage::getUrl('checkout/onepage/success') + $this->_checkout->prepareGiropayUrls( + Mage::getUrl('checkout/onepage/success'), + Mage::getUrl('paypal/express/cancel'), + Mage::getUrl('checkout/onepage/success') ); $token = $this->_checkout->start(Mage::getUrl('*/*/return'), Mage::getUrl('*/*/cancel')); @@ -85,14 +86,13 @@ public function startAction() $this->getResponse()->setRedirect($url); return; } - } - catch (Mage_Core_Exception $e) { + } catch (Mage_Core_Exception $e) { $this->_getCheckoutSession()->addError($e->getMessage()); - } - catch (Exception $e) { + } catch (Exception $e) { $this->_getCheckoutSession()->addError($this->__('Unable to start Express Checkout.')); Mage::logException($e); } + $this->_redirect('checkout/cart'); } @@ -119,19 +119,19 @@ public function cancelAction() { try { $this->_initToken(false); + // TODO verify if this logic of order cancelation is deprecated // if there is an order - cancel it - if ($orderId = $this->_getCheckoutSession()->getLastOrderId()) { - $order = Mage::getModel('sales/order')->load($orderId); - if ($order->getId()) { - $order->cancel()->save(); - $this->_getCheckoutSession() - ->unsLastQuoteId() - ->unsLastSuccessQuoteId() - ->unsLastOrderId() - ->unsLastRealOrderId() - ->addSuccess($this->__('Express Checkout and Order have been canceled.')) - ; - } + $orderId = $this->_getCheckoutSession()->getLastOrderId(); + $order = ($orderId) ? Mage::getModel('sales/order')->load($orderId) : false; + if ($order && $order->getId() && $order->getQuoteId() == $this->_getCheckoutSession()->getQuoteId()) { + $order->cancel()->save(); + $this->_getCheckoutSession() + ->unsLastQuoteId() + ->unsLastSuccessQuoteId() + ->unsLastOrderId() + ->unsLastRealOrderId() + ->addSuccess($this->__('Express Checkout and Order have been canceled.')) + ; } else { $this->_getCheckoutSession()->addSuccess($this->__('Express Checkout has been canceled.')); } @@ -141,6 +141,7 @@ public function cancelAction() $this->_getCheckoutSession()->addError($this->__('Unable to cancel Express Checkout.')); Mage::logException($e); } + $this->_redirect('checkout/cart'); } @@ -304,7 +305,7 @@ public function placeOrderAction() private function _initCheckout() { $quote = $this->_getQuote(); - if (!$quote->hasItems()) { + if (!$quote->hasItems() || $quote->getHasError()) { $this->getResponse()->setHeader('HTTP/1.1','403 Forbidden'); Mage::throwException(Mage::helper('paypal')->__('Unable to initialize Express Checkout.')); } diff --git a/app/code/core/Mage/Paypal/Helper/Data.php b/app/code/core/Mage/Paypal/Helper/Data.php index 38939e384f..727fcd040c 100644 --- a/app/code/core/Mage/Paypal/Helper/Data.php +++ b/app/code/core/Mage/Paypal/Helper/Data.php @@ -36,115 +36,6 @@ class Mage_Paypal_Helper_Data extends Mage_Core_Helper_Abstract */ protected static $_shouldAskToCreateBillingAgreement = null; - /** - * Get line items and totals from sales quote or order - * - * PayPal calculates grand total by this formula: - * sum(item_base_price * qty) + subtotal + shipping + shipping_discount - * where subtotal doesn't include anything, shipping_discount is negative - * the items discount should go as separate cart line item with negative amount - * the shipping_discount is outlined in PayPal API docs, but ignored for some reason. Hence commented out. - * - * @param Mage_Sales_Model_Order $salesEntity - * @return array (array of $items, array of totals, $discountTotal, $shippingTotal) - */ - public function prepareLineItems(Mage_Core_Model_Abstract $salesEntity, $discountTotalAsItem = true, $shippingTotalAsItem = false) - { - $items = array(); - foreach ($salesEntity->getAllItems() as $item) { - if (!$item->getParentItem()) { - $items[] = new Varien_Object($this->_prepareLineItemFields($salesEntity, $item)); - } - } - $additionalItems = new Varien_Object(array('items'=>array())); - Mage::dispatchEvent('paypal_prepare_line_items', array('sales_entity'=>$salesEntity, 'additional'=>$additionalItems)); - $additionalAmount = 0; - $discountAmount = 0; // this amount always includes the shipping discount - foreach ($additionalItems->getItems() as $item) { - if ($item['amount'] > 0) { - $additionalAmount += $item['amount']; - $items[] = $item; - } else { - $discountAmount += abs($item['amount']); - } - } - $shippingDescription = ''; - if ($salesEntity instanceof Mage_Sales_Model_Order) { - $discountAmount += abs($salesEntity->getBaseDiscountAmount()); - $shippingDescription = $salesEntity->getShippingDescription(); - $totals = array( - 'subtotal' => $salesEntity->getBaseSubtotal() - $discountAmount, - 'tax' => $salesEntity->getBaseTaxAmount(), - 'shipping' => $salesEntity->getBaseShippingAmount(), - 'discount' => $discountAmount, -// 'shipping_discount' => -1 * abs($salesEntity->getBaseShippingDiscountAmount()), - ); - } else { - $address = $salesEntity->getIsVirtual() ? $salesEntity->getBillingAddress() : $salesEntity->getShippingAddress(); - $discountAmount += abs($address->getBaseDiscountAmount()); - $shippingDescription = $address->getShippingDescription(); - $totals = array ( - 'subtotal' => $salesEntity->getBaseSubtotal() - $discountAmount, - 'tax' => $address->getBaseTaxAmount(), - 'shipping' => $address->getBaseShippingAmount(), - 'discount' => $discountAmount, -// 'shipping_discount' => -1 * abs($address->getBaseShippingDiscountAmount()), - ); - } - - // discount total as line item (negative) - if ($discountTotalAsItem && $discountAmount) { - $items[] = new Varien_Object(array( - 'name' => Mage::helper('paypal')->__('Discount'), - 'qty' => 1, - 'amount' => -1.00 * $discountAmount, - )); - } - // shipping total as line item - if ($shippingTotalAsItem && (!$salesEntity->getIsVirtual()) && (float)$totals['shipping']) { - $items[] = new Varien_Object(array( - 'id' => Mage::helper('paypal')->__('Shipping'), - 'name' => $shippingDescription, - 'qty' => 1, - 'amount' => (float)$totals['shipping'], - )); - } - - $hiddenTax = (float) $salesEntity->getBaseHiddenTaxAmount(); - if ($hiddenTax) { - $items[] = new Varien_Object(array( - 'name' => Mage::helper('paypal')->__('Discount Tax'), - 'qty' => 1, - 'amount' => (float)$hiddenTax, - )); - } - - return array($items, $totals, $discountAmount, $totals['shipping']); - } - - /** - * Check whether cart line items are eligible for exporting to PayPal API - * - * Requires data returned by self::prepareLineItems() - * - * @param array $items - * @param array $totals - * @param float $referenceAmount - * @return bool - */ - public function areCartLineItemsValid($items, $totals, $referenceAmount) - { - $sum = 0; - foreach ($items as $i) { - $sum = $sum + $i['qty'] * $i['amount']; - } - /** - * numbers are intentionally converted to strings because of possible comparison error - * see http://php.net/float - */ - return sprintf('%.4F', ($sum + $totals['shipping'] + $totals['tax'])) == sprintf('%.4F', $referenceAmount); - } - /** * Check whether customer should be asked confirmation whether to sign a billing agreement * @@ -164,44 +55,4 @@ public function shouldAskToCreateBillingAgreement(Mage_Paypal_Model_Config $conf } return self::$_shouldAskToCreateBillingAgreement; } - - /** - * @deprecated after 1.4.0.1 - */ - public function doLineItemsMatchAmount(Mage_Core_Model_Abstract $salesEntity, $orderAmount) - { - return false; - } - - /** - * Get one line item key-value array - * - * @param Mage_Core_Model_Abstract $salesEntity - * @param Varien_Object $item - * @return array - */ - protected function _prepareLineItemFields(Mage_Core_Model_Abstract $salesEntity, Varien_Object $item) - { - if ($salesEntity instanceof Mage_Sales_Model_Order) { - $qty = $item->getQtyOrdered(); - $amount = $item->getBasePrice(); - // TODO: nominal item for order - } else { - $qty = $item->getTotalQty(); - $amount = $item->isNominal() ? 0 : $item->getBaseCalculationPrice(); - } - // workaround in case if item subtotal precision is not compatible with PayPal (.2) - $subAggregatedLabel = ''; - if ((float)$amount - round((float)$amount, 2)) { - $amount = $amount * $qty; - $subAggregatedLabel = ' x' . $qty; - $qty = 1; - } - return array( - 'id' => $item->getSku(), - 'name' => $item->getName() . $subAggregatedLabel, - 'qty' => $qty, - 'amount' => (float)$amount, - ); - } } diff --git a/app/code/core/Mage/Paypal/Model/Api/Abstract.php b/app/code/core/Mage/Paypal/Model/Api/Abstract.php index 977d89e5b1..0f56f1d39b 100644 --- a/app/code/core/Mage/Paypal/Model/Api/Abstract.php +++ b/app/code/core/Mage/Paypal/Model/Api/Abstract.php @@ -61,9 +61,16 @@ abstract class Mage_Paypal_Model_Api_Abstract extends Varien_Object * Line items export to request mapping settings * @var array */ - protected $_lineItemExportTotals = array(); protected $_lineItemExportItemsFormat = array(); protected $_lineItemExportItemsFilters = array(); + protected $_lineItemTotalExportMap = array(); + + /** + * PayPal shopping cart instance + * + * @var Mage_Paypal_Model_Cart + */ + protected $_cart = null; /** * Shipping options export to request mapping settings @@ -258,6 +265,18 @@ public function export($from, array $publicMap = array()) return $this; } + /** + * Set PayPal cart instance + * + * @param Mage_Paypal_Model_Cart $cart + * @return Mage_Paypal_Model_Api_Abstract + */ + public function setPaypalCart(Mage_Paypal_Model_Cart $cart) + { + $this->_cart = $cart; + return $this; + } + /** * Config instance setter * @param Mage_Paypal_Model_Config $config @@ -352,18 +371,37 @@ protected function _importFromResponse(array $privateResponseMap, array $respons /** * Prepare line items request * + * Returns true if there were line items added + * * @param array &$request * @param int $i + * @return true|bool */ protected function _exportLineItems(array &$request, $i = 0) { - $items = $this->getLineItems(); - if (empty($items)) { + if (!$this->_cart) { + return; + } + + // always add cart totals, even if line items are not requested + if ($this->_lineItemTotalExportMap) { + foreach ($this->_cart->getTotals() as $key => $total) { + if (isset($this->_lineItemTotalExportMap[$key])) { // !empty($total) + $privateKey = $this->_lineItemTotalExportMap[$key]; + $request[$privateKey] = $this->_filterAmount($total); + } + } + } + + // add cart line items + $items = $this->_cart->getItems(); + if (empty($items) || !$this->getIsLineItemsEnabled()) { return; } - // line items + $result = null; foreach ($items as $item) { foreach ($this->_lineItemExportItemsFormat as $publicKey => $privateFormat) { + $result = true; $value = $item->getDataUsingMethod($publicKey); if (isset($this->_lineItemExportItemsFilters[$publicKey])) { $callback = $this->_lineItemExportItemsFilters[$publicKey]; @@ -376,19 +414,7 @@ protected function _exportLineItems(array &$request, $i = 0) } $i++; } - // line item totals - $lineItemTotals = $this->getLineItemTotals(); - if ($lineItemTotals) { - $request = Varien_Object_Mapper::accumulateByMap($lineItemTotals, $request, $this->_lineItemExportTotals); - foreach ($this->_lineItemExportTotals as $privateKey) { - if (array_key_exists($privateKey, $request)) { - $request[$privateKey] = $this->_filterAmount($request[$privateKey]); - } else { - Mage::logException(new Exception(sprintf('Missing index "%s" for line item totals.', $privateKey))); - Mage::throwException(Mage::helper('paypal')->__('Unable to calculate cart line item totals.')); - } - } - } + return $result; } /** diff --git a/app/code/core/Mage/Paypal/Model/Api/Nvp.php b/app/code/core/Mage/Paypal/Model/Api/Nvp.php index fbb66eaff6..09ef1d7c9d 100644 --- a/app/code/core/Mage/Paypal/Model/Api/Nvp.php +++ b/app/code/core/Mage/Paypal/Model/Api/Nvp.php @@ -104,6 +104,7 @@ class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract 'REFUNDTRANSACTIONID' => 'refund_transaction_id', 'COMPLETETYPE' => 'complete_type', 'AMT' => 'amount', + 'ITEMAMT' => 'subtotal_amount', 'GROSSREFUNDAMT' => 'refunded_amount', // possible mistake, check with API reference // payment/billing info @@ -186,6 +187,7 @@ class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract */ protected $_exportToRequestFilters = array( 'AMT' => '_filterAmount', + 'ITEMAMT' => '_filterAmount', 'TRIALAMT' => '_filterAmount', 'SHIPPINGAMT' => '_filterAmount', 'TAXAMT' => '_filterAmount', @@ -220,7 +222,7 @@ class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract 'PAYMENTACTION', 'AMT', 'CURRENCYCODE', 'RETURNURL', 'CANCELURL', 'INVNUM', 'SOLUTIONTYPE', 'NOSHIPPING', 'GIROPAYCANCELURL', 'GIROPAYSUCCESSURL', 'BANKTXNPENDINGURL', 'PAGESTYLE', 'HDRIMG', 'HDRBORDERCOLOR', 'HDRBACKCOLOR', 'PAYFLOWCOLOR', 'LOCALECODE', - 'BILLINGTYPE', 'SUBJECT', + 'BILLINGTYPE', 'SUBJECT', 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT', ); protected $_setExpressCheckoutResponse = array('TOKEN'); @@ -236,7 +238,7 @@ class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract */ protected $_doExpressCheckoutPaymentRequest = array( 'TOKEN', 'PAYERID', 'PAYMENTACTION', 'AMT', 'CURRENCYCODE', 'IPADDRESS', 'BUTTONSOURCE', 'NOTIFYURL', - 'RETURNFMFDETAILS', 'SUBJECT', + 'RETURNFMFDETAILS', 'SUBJECT', 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT', ); protected $_doExpressCheckoutPaymentResponse = array( 'TRANSACTIONID', 'AMT', 'PAYMENTSTATUS', 'PENDINGREASON', 'REDIRECTREQUIRED', 'SUCCESSPAGEREDIRECTREQUESTED', @@ -248,7 +250,7 @@ class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract */ protected $_doDirectPaymentRequest = array( 'PAYMENTACTION', 'IPADDRESS', 'RETURNFMFDETAILS', - 'AMT', 'CURRENCYCODE', 'INVNUM', 'NOTIFYURL', 'EMAIL', //, 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT', + 'AMT', 'CURRENCYCODE', 'INVNUM', 'NOTIFYURL', 'EMAIL', 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT', 'CREDITCARDTYPE', 'ACCT', 'EXPDATE', 'CVV2', 'STARTDATE', 'ISSUENUMBER', 'AUTHSTATUS3DS', 'MPIVENDOR3DS', 'CAVV', 'ECI3DS', 'XID', ); @@ -401,11 +403,10 @@ class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract * Line items export mapping settings * @var array */ - protected $_lineItemExportTotals = array( - 'subtotal' => 'ITEMAMT', - 'shipping' => 'SHIPPINGAMT', - 'tax' => 'TAXAMT', - // 'shipping_discount' => 'SHIPPINGDISCOUNT', // currently ignored by API for some reason + protected $_lineItemTotalExportMap = array( + Mage_Paypal_Model_Cart::TOTAL_SUBTOTAL => 'ITEMAMT', + Mage_Paypal_Model_Cart::TOTAL_TAX => 'TAXAMT', + Mage_Paypal_Model_Cart::TOTAL_SHIPPING => 'SHIPPINGAMT', ); protected $_lineItemExportItemsFormat = array( 'id' => 'L_NUMBER%d', @@ -462,7 +463,7 @@ class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract * * @var array */ - protected $_doReferenceTransactionRequest = array('REFERENCEID', 'PAYMENTACTION', 'AMT'); + protected $_doReferenceTransactionRequest = array('REFERENCEID', 'PAYMENTACTION', 'AMT', 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT',); protected $_doReferenceTransactionResponse = array('BILLINGAGREEMENTID', 'TRANSACTIONID'); /** @@ -544,10 +545,9 @@ public function callSetExpressCheckout() $this->_exportLineItems($request); // import/suppress shipping address, if any - $address = $this->getAddress(); $options = $this->getShippingOptions(); - if ($address) { - $request = $this->_importAddress($address, $request); + if ($this->getAddress()) { + $request = $this->_importAddresses($request); $request['ADDROVERRIDE'] = 1; } elseif ($options && (count($options) < 10)) { // doesn't support more than 10 shipping options $request['CALLBACK'] = $this->getShippingOptionsCallbackUrl(); @@ -604,8 +604,8 @@ public function callDoDirectPayment() { $request = $this->_exportToRequest($this->_doDirectPaymentRequest); $this->_exportLineItems($request); - if ($address = $this->getAddress()) { - $request = $this->_importAddress($address, $request); + if ($this->getAddress()) { + $request = $this->_importAddresses($request); } $response = $this->call(self::DO_DIRECT_PAYMENT, $request); $this->_importFromResponse($this->_doDirectPaymentResponse, $response); @@ -792,25 +792,11 @@ public function callManageRecurringPaymentsProfileStatus() try { $response = $this->call('ManageRecurringPaymentsProfileStatus', $request); } catch (Mage_Core_Exception $e) { - // trying to cancel already canceled - if (in_array(11556, $this->_callErrors)) { - if ('Cancel' === $request['ACTION'] && $this->getIsAlreadyCanceled()) { - return; - } - } - // trying to suspend already suspended + - // trying to suspend already canceled - elseif (in_array(11557, $this->_callErrors)) { - if ('Suspend' === $request['ACTION'] && $this->getIsAlreadySuspended()) { - return; - } - } - // trying to activate already active + - // trying to activate already canceled - elseif (in_array(11558, $this->_callErrors)) { - if ('Reactivate' === $request['ACTION'] && $this->getIsAlreadyActive()) { - return; - } + if ((in_array(11556, $this->_callErrors) && 'Cancel' === $request['ACTION']) + || (in_array(11557, $this->_callErrors) && 'Suspend' === $request['ACTION']) + || (in_array(11558, $this->_callErrors) && 'Reactivate' === $request['ACTION']) + ) { + Mage::throwException(Mage::helper('paypal')->__('Unable to change status. Current status is not correspond to real status.')); } throw $e; } @@ -1020,6 +1006,22 @@ protected function _deformatNVP($nvpstr) return $nvpArray; } + /** + * NVP doesn't support passing discount total as a separate amount - add it as a line item + * + * @param array $request + * @param int $i + * @return true|null + */ + protected function _exportLineItems(array &$request, $i = 0) + { + if (!$this->_cart) { + return; + } + $this->_cart->isDiscountAsItem(true); + return parent::_exportLineItems($request, $i); + } + /** * Create billing and shipping addresses basing on response data * @param array $data @@ -1074,28 +1076,60 @@ protected function _applyStreetAndRegionWorkarounds(Varien_Object $address) } } + /** + * Adopt specified request array to be compatible with Paypal + * Puerto Rico should be as state of USA and not as a country + * + * @param array $request + */ + protected function _applyCountryWorkarounds(&$request) + { + if (isset($request['SHIPTOCOUNTRYCODE']) && $request['SHIPTOCOUNTRYCODE'] == 'PR') { + $request['SHIPTOCOUNTRYCODE'] = 'US'; + $request['SHIPTOSTATE'] = 'PR'; + } + } + /** * Prepare request data basing on provided address * + * @deprecated after 1.4.2.0-beta1, use _importAddresses() instead + * * @param Varien_Object $address * @param array $to * @return array */ protected function _importAddress(Varien_Object $address, array $to) { - $to = Varien_Object_Mapper::accumulateByMap($address, $to, array_flip($this->_billingAddressMap)); - if ($regionCode = $this->_lookupRegionCodeFromAddress($address)) { + $this->setAddress($address); + return $this->_importAddresses($to); + } + + /** + * Prepare request data basing on provided addresses + * + * @param array $to + * @return array + */ + protected function _importAddresses(array $to) + { + $billingAddress = ($this->getBillingAddress()) ? $this->getBillingAddress() : $this->getAddress(); + $shippingAddress = $this->getAddress(); + + $to = Varien_Object_Mapper::accumulateByMap($billingAddress, $to, array_flip($this->_billingAddressMap)); + if ($regionCode = $this->_lookupRegionCodeFromAddress($billingAddress)) { $to['STATE'] = $regionCode; } if (!$this->getSuppressShipping()) { - $to = Varien_Object_Mapper::accumulateByMap($address, $to, array_flip($this->_shippingAddressMap)); - if ($regionCode = $this->_lookupRegionCodeFromAddress($address)) { + $to = Varien_Object_Mapper::accumulateByMap($shippingAddress, $to, array_flip($this->_shippingAddressMap)); + if ($regionCode = $this->_lookupRegionCodeFromAddress($shippingAddress)) { $to['SHIPTOSTATE'] = $regionCode; } - $this->_importStreetFromAddress($address, $to, 'SHIPTOSTREET', 'SHIPTOSTREET2'); - $this->_importStreetFromAddress($address, $to, 'STREET', 'STREET2'); - $to['SHIPTONAME'] = $address->getName(); + $this->_importStreetFromAddress($shippingAddress, $to, 'SHIPTOSTREET', 'SHIPTOSTREET2'); + $this->_importStreetFromAddress($billingAddress, $to, 'STREET', 'STREET2'); + $to['SHIPTONAME'] = $shippingAddress->getName(); } + $this->_applyCountryWorkarounds($to); return $to; } diff --git a/app/code/core/Mage/Paypal/Model/Api/Standard.php b/app/code/core/Mage/Paypal/Model/Api/Standard.php index 53923a2d75..aa0d17e2d2 100644 --- a/app/code/core/Mage/Paypal/Model/Api/Standard.php +++ b/app/code/core/Mage/Paypal/Model/Api/Standard.php @@ -46,8 +46,8 @@ class Mage_Paypal_Model_Api_Standard extends Mage_Paypal_Model_Api_Abstract 'currency_code' => 'currency_code', 'amount' => 'amount', 'shipping' => 'shipping_amount', - 'tax_cart' => 'tax_amount', - 'discount_amount_cart' => 'discount_amount', + 'tax' => 'tax_amount', + 'discount_amount' => 'discount_amount', // misc 'item_name' => 'cart_summary', // page design settings @@ -60,7 +60,9 @@ class Mage_Paypal_Model_Api_Standard extends Mage_Paypal_Model_Api_Abstract ); protected $_exportToRequestFilters = array( 'amount' => '_filterAmount', - 'shipping' => '_filterAmount' + 'shipping' => '_filterAmount', + 'tax' => '_filterAmount', + 'discount_amount' => '_filterAmount', ); /** @@ -69,16 +71,9 @@ class Mage_Paypal_Model_Api_Standard extends Mage_Paypal_Model_Api_Abstract */ protected $_commonRequestFields = array( 'business', 'invoice', 'currency_code', 'paymentaction', 'return', 'cancel_return', 'notify_url', 'bn', - 'page_style', 'cpp_header_image', 'cpp_headerback_color', 'cpp_headerborder_color', 'cpp_payflow_color' + 'page_style', 'cpp_header_image', 'cpp_headerback_color', 'cpp_headerborder_color', 'cpp_payflow_color', + 'amount', 'shipping', 'tax', 'discount_amount', 'item_name', ); - protected $_aggregatedOrderFields = array('item_name', 'amount', 'shipping'); - - /** - * @deprecated after 1.4.1.0 - * - * @var array - */ - protected $_obscureDebugFor = array('business'); /** * Fields that should be replaced in debug with '***' @@ -91,9 +86,11 @@ class Mage_Paypal_Model_Api_Standard extends Mage_Paypal_Model_Api_Abstract * Line items export mapping settings * @var array */ - protected $_lineItemExportTotals = array( - 'tax' => 'tax_cart', - 'discount' => 'discount_amount_cart', + protected $_lineItemTotalExportMap = array( + Mage_Paypal_Model_Cart::TOTAL_SUBTOTAL => 'amount', + Mage_Paypal_Model_Cart::TOTAL_DISCOUNT => 'discount_amount', + Mage_Paypal_Model_Cart::TOTAL_TAX => 'tax', + Mage_Paypal_Model_Cart::TOTAL_SHIPPING => 'shipping', ); protected $_lineItemExportItemsFormat = array( 'id' => 'item_number_%d', @@ -131,22 +128,26 @@ public function getStandardCheckoutRequest() { $request = $this->_exportToRequest($this->_commonRequestFields); $request['charset'] = 'utf-8'; - // cart line items - if ($this->getLineItems()) { - $this->_exportLineItems($request, 1); + + $isLineItems = $this->_exportLineItems($request); + if ($isLineItems) { $request = array_merge($request, array( 'cmd' => '_cart', 'upload' => 1, )); - } - // aggregated order - else { - $request = $this->_exportToRequest($this->_aggregatedOrderFields, $request); + if (isset($request['tax'])) { + $request['tax_cart'] = $request['tax']; + } + if (isset($request['discount_amount'])) { + $request['discount_amount_cart'] = $request['discount_amount']; + } + } else { $request = array_merge($request, array( 'cmd' => '_ext-enter', 'redirect_cmd' => '_xclick', )); } + // payer address $this->_importAddress($request); $this->_debug(array('request' => $request)); // TODO: this is not supposed to be called in getter @@ -181,6 +182,26 @@ public function debugRequest($request) return; } + /** + * Add shipping total as a line item. + * For some reason PayPal ignores shipping total variables exactly when line items is enabled + * Note that $i = 1 + * + * @param array $request + * @param int $i + * @return true|null + */ + protected function _exportLineItems(array &$request, $i = 1) + { + if (!$this->_cart) { + return; + } + if ($this->getIsLineItemsEnabled()) { + $this->_cart->isShippingAsItem(true); + } + return parent::_exportLineItems($request, $i); + } + /** * Import address object, if set, to the request * @@ -195,11 +216,38 @@ protected function _importAddress(&$request) } return; } + $request = Varien_Object_Mapper::accumulateByMap($address, $request, array_flip($this->_addressMap)); - if ($regionCode = $this->_lookupRegionCodeFromAddress($address)) { + + // Address may come without email info (user is not always required to enter it), so add email from order + if (!$request['email']) { + $order = $this->getOrder(); + if ($order) { + $request['email'] = $order->getCustomerEmail(); + } + } + + $regionCode = $this->_lookupRegionCodeFromAddress($address); + if ($regionCode) { $request['state'] = $regionCode; } $this->_importStreetFromAddress($address, $request, 'address1', 'address2'); + $this->_applyCountryWorkarounds($request); + $request['address_override'] = 1; } + + /** + * Adopt specified request array to be compatible with Paypal + * Puerto Rico should be as state of USA and not as a country + * + * @param array $request + */ + protected function _applyCountryWorkarounds(&$request) + { + if (isset($request['country']) && $request['country'] == 'PR') { + $request['country'] = 'US'; + $request['state'] = 'PR'; + } + } } diff --git a/app/code/core/Mage/Paypal/Model/Cart.php b/app/code/core/Mage/Paypal/Model/Cart.php new file mode 100644 index 0000000000..259b1f3e6d --- /dev/null +++ b/app/code/core/Mage/Paypal/Model/Cart.php @@ -0,0 +1,467 @@ +_salesEntity = $salesEntity; + } else { + throw new Exception('Invalid sales entity provided.'); + } + } + + /** + * Getter for the current sales entity + * + * @return Mage_Sales_Model_Order + * @return Mage_Sales_Model_Quote + */ + public function getSalesEntity() + { + return $this->_salesEntity; + } + + /** + * Render and get line items + * By default returns false if the items are invalid + * + * @param bool $bypassValidation + * @return array|false + */ + public function getItems($bypassValidation = false) + { + $this->_render(); + if (!$bypassValidation && !$this->_areItemsValid) { + return false; + } + return $this->_items; + } + + /** + * Render and get totals + * If the totals are invalid for any reason, they will be merged into one amount (subtotal is utilized for it) + * An option to substract discount from the subtotal is available + * + * @param bool $mergeDiscount + * @return array + */ + public function getTotals($mergeDiscount = false) + { + $this->_render(); + + // cut down totals to one total if they are invalid + if (!$this->_areTotalsValid) { + $totals = array(self::TOTAL_SUBTOTAL => + $this->_totals[self::TOTAL_SUBTOTAL] + $this->_totals[self::TOTAL_TAX] + ); + if (!$this->_isShippingAsItem) { + $totals[self::TOTAL_SUBTOTAL] += $this->_totals[self::TOTAL_SHIPPING]; + } + if (!$this->_isDiscountAsItem) { + $totals[self::TOTAL_SUBTOTAL] -= $this->_totals[self::TOTAL_DISCOUNT]; + } + return $totals; + } elseif ($mergeDiscount) { + $totals = $this->_totals; + unset($totals[self::TOTAL_DISCOUNT]); + if (!$this->_isDiscountAsItem) { + $totals[self::TOTAL_SUBTOTAL] -= $this->_totals[self::TOTAL_DISCOUNT]; + } + return $totals; + } + return $this->_totals; + } + + /** + * Add a line item + * + * @param string $name + * @param numeric $qty + * @param float $amount + * @param string $identifier + * @return Varien_Object + */ + public function addItem($name, $qty, $amount, $identifier = null) + { + $this->_shouldRender = true; + $item = new Varien_Object(array( + 'name' => $name, + 'qty' => $qty, + 'amount' => (float)$amount, + )); + if ($identifier) { + $item->setData('id', $identifier); + } + $this->_items[] = $item; + return $item; + } + + /** + * Compound the specified amount with the specified total + * + * @param string $code + * @param float $amount + * @param string $lineItemDescription + * @return Mage_Paypal_Model_Cart + */ + public function updateTotal($code, $amount, $lineItemDescription = null) + { + $this->_shouldRender = true; + if (isset($this->_totals[$code])) { + $this->_totals[$code] += $amount; + if ($lineItemDescription) { + $this->_totalLineItemDescriptions[$code][] = $lineItemDescription; + } + } + return $this; + } + + /** + * Get/Set whether to render the discount total as a line item + * + * @param $setValue + * @return bool|Mage_Paypal_Model_Cart + */ + public function isDiscountAsItem($setValue = null) + { + return $this->_totalAsItem('_isDiscountAsItem', $setValue); + } + + /** + * Get/Set whether to render the discount total as a line item + * + * @param $setValue + * @return bool|Mage_Paypal_Model_Cart + */ + public function isShippingAsItem($setValue = null) + { + return $this->_totalAsItem('_isShippingAsItem', $setValue); + } + + /** + * (re)Render all items and totals + */ + protected function _render() + { + if (!$this->_shouldRender) { + return; + } + + // regular items from the sales entity + $this->_items = array(); + foreach ($this->_salesEntity->getAllItems() as $item) { + if (!$item->getParentItem()) { + $this->_addRegularItem($item); + } + } + end($this->_items); + $lastRegularItemKey = key($this->_items); + + // regular totals + $shippingDescription = ''; + if ($this->_salesEntity instanceof Mage_Sales_Model_Order) { + $shippingDescription = $this->_salesEntity->getShippingDescription(); + $this->_totals = array( + self::TOTAL_SUBTOTAL => $this->_salesEntity->getBaseSubtotal(), + self::TOTAL_TAX => $this->_salesEntity->getBaseTaxAmount(), + self::TOTAL_SHIPPING => $this->_salesEntity->getBaseShippingAmount(), + self::TOTAL_DISCOUNT => abs($this->_salesEntity->getBaseDiscountAmount()), + ); + $this->_applyHiddenTaxWorkaround($this->_salesEntity); + } else { + $address = $this->_salesEntity->getIsVirtual() ? + $this->_salesEntity->getBillingAddress() : $this->_salesEntity->getShippingAddress(); + $shippingDescription = $address->getShippingDescription(); + $this->_totals = array ( + self::TOTAL_SUBTOTAL => $this->_salesEntity->getBaseSubtotal(), + self::TOTAL_TAX => $address->getBaseTaxAmount(), + self::TOTAL_SHIPPING => $address->getBaseShippingAmount(), + self::TOTAL_DISCOUNT => abs($address->getBaseDiscountAmount()), + ); + $this->_applyHiddenTaxWorkaround($address); + } + $originalDiscount = $this->_totals[self::TOTAL_DISCOUNT]; + + // arbitrary items, total modifications + Mage::dispatchEvent('paypal_prepare_line_items', array('paypal_cart' => $this)); + + // distinguish original discount among the others + if ($originalDiscount > 0.0001 && isset($this->_totalLineItemDescriptions[self::TOTAL_DISCOUNT])) { + $this->_totalLineItemDescriptions[self::TOTAL_DISCOUNT][] = Mage::helper('sales')->__('Discount (%s)', Mage::app()->getStore()->convertPrice($originalDiscount, true, false)); + } + + // discount, shipping as items + if ($this->_isDiscountAsItem && $this->_totals[self::TOTAL_DISCOUNT]) { + $this->addItem(Mage::helper('paypal')->__('Discount'), 1, -1.00 * $this->_totals[self::TOTAL_DISCOUNT], + $this->_renderTotalLineItemDescriptions(self::TOTAL_DISCOUNT) + ); + } + if ($this->_isShippingAsItem && (float)$this->_totals[self::TOTAL_SHIPPING]) { + $this->addItem(Mage::helper('paypal')->__('Shipping'), 1, (float)$this->_totals[self::TOTAL_SHIPPING], + $this->_renderTotalLineItemDescriptions(self::TOTAL_SHIPPING, $shippingDescription) + ); + } + + // compound non-regular items into subtotal + foreach ($this->_items as $key => $item) { + if ($key > $lastRegularItemKey && $item->getAmount() != 0) { + $this->_totals[self::TOTAL_SUBTOTAL] += $item->getAmount(); + } + } + + $this->_validate(); + $this->_shouldRender = false; + } + + /** + * Merge multiple descriptions by a total code into a string + * + * @param string $code + * @param string $prepend + * @param string $append + * @param string $glue + * @return string + */ + protected function _renderTotalLineItemDescriptions($code, $prepend = '', $append = '', $glue = '; ') + { + $result = array(); + if ($prepend) { + $result[] = $prepend; + } + if (isset($this->_totalLineItemDescriptions[$code])) { + $result = array_merge($this->_totalLineItemDescriptions[$code]); + } + if ($append) { + $result[] = $append; + } + return implode($glue, $result); + } + + /** + * Check the line items and totals according to PayPal business logic limitations + */ + protected function _validate() + { + $this->_areItemsValid = false; + $this->_areTotalsValid = false; + + $referenceAmount = $this->_salesEntity->getBaseGrandTotal(); + + $itemsSubtotal = 0; + foreach ($this->_items as $i) { + $itemsSubtotal = $itemsSubtotal + $i['qty'] * $i['amount']; + } + $sum = $itemsSubtotal + $this->_totals[self::TOTAL_TAX]; + if (!$this->_isShippingAsItem) { + $sum += $this->_totals[self::TOTAL_SHIPPING]; + } + if (!$this->_isDiscountAsItem) { + $sum -= $this->_totals[self::TOTAL_DISCOUNT]; + } + /** + * numbers are intentionally converted to strings because of possible comparison error + * see http://php.net/float + */ + // match sum of all the items and totals to the reference amount + if (sprintf('%.4F', $sum) == sprintf('%.4F', $referenceAmount)) { + $this->_areItemsValid = true; + } + + // PayPal requires to have discount less than items subtotal + if (!$this->_isDiscountAsItem) { + $this->_areTotalsValid = round($this->_totals[self::TOTAL_DISCOUNT], 4) < round($itemsSubtotal, 4); + } else { + $this->_areTotalsValid = $itemsSubtotal > 0.00001; + } + + $this->_areItemsValid = $this->_areItemsValid && $this->_areTotalsValid; + } + + /** + * Add a usual line item with amount and qty + * + * @param Varien_Object $salesItem + * @return Varien_Object + */ + protected function _addRegularItem(Varien_Object $salesItem) + { + if ($this->_salesEntity instanceof Mage_Sales_Model_Order) { + $qty = $salesItem->getQtyOrdered(); + $amount = $salesItem->getBasePrice(); + // TODO: nominal item for order + } else { + $qty = $salesItem->getTotalQty(); + $amount = $salesItem->isNominal() ? 0 : $salesItem->getBaseCalculationPrice(); + } + // workaround in case if item subtotal precision is not compatible with PayPal (.2) + $subAggregatedLabel = ''; + if ((float)$amount - round((float)$amount, 2)) { + $amount = $amount * $qty; + $subAggregatedLabel = ' x' . $qty; + $qty = 1; + } + return $this->addItem($salesItem->getName() . $subAggregatedLabel, $qty, (float)$amount, $salesItem->getSku()); + } + + /** + * Get/Set for the specified variable. + * If the value changes, the re-rendering is commenced + * + * @param string $var + * @param $setValue + * @return bool|Mage_Paypal_Model_Cart + */ + private function _totalAsItem($var, $setValue = null) + { + if (null !== $setValue) { + if ($setValue != $this->$var) { + $this->_shouldRender = true; + } + $this->$var = $setValue; + return $this; + } + return $this->$var; + } + + /** + * Add "hidden" discount and shipping tax + * + * Go ahead, try to understand ]:-> + * + * Tax settings for getting "discount tax": + * - Catalog Prices = Including Tax + * - Apply Customer Tax = After Discount + * - Apply Discount on Prices = Including Tax + * + * Test case for getting "hidden shipping tax": + * - Make sure shipping is taxable (set shipping tax class) + * - Catalog Prices = Including Tax + * - Shipping Prices = Including Tax + * - Apply Customer Tax = After Discount + * - Create a shopping cart price rule with % discount applied to the Shipping Amount + * - run shopping cart and estimate shipping + * - go to PayPal + * + * @param Mage_Core_Model_Abstract $salesEntity + */ + private function _applyHiddenTaxWorkaround($salesEntity) + { + $this->_totals[self::TOTAL_TAX] += (float)$salesEntity->getBaseHiddenTaxAmount(); + $this->_totals[self::TOTAL_TAX] += (float)$salesEntity->getBaseShippingHiddenTaxAmount(); + } +} diff --git a/app/code/core/Mage/Paypal/Model/Config.php b/app/code/core/Mage/Paypal/Model/Config.php index d52f222f4e..e0fe325624 100644 --- a/app/code/core/Mage/Paypal/Model/Config.php +++ b/app/code/core/Mage/Paypal/Model/Config.php @@ -323,7 +323,9 @@ public function isMethodAvailable($methodCode = null) break; case self::METHOD_WPP_EXPRESS: // check for direct payments dependence - if ($this->isMethodActive(self::METHOD_WPP_DIRECT)) { + if ($this->isMethodActive(self::METHOD_WPP_PE_DIRECT)) { + $result = false; + } elseif ($this->isMethodActive(self::METHOD_WPP_DIRECT)) { $result = true; } break; @@ -900,7 +902,7 @@ public function getWpsPaymentDeliveryMethods() */ public function getWppCcTypesAsOptionArray() { - $model = Mage::getModel('payment/source_cctype')->setAllowedTypes(array('AE', 'VI', 'MC', 'SS', 'DI')); + $model = Mage::getModel('payment/source_cctype')->setAllowedTypes(array('AE', 'VI', 'MC', 'SM', 'SO', 'DI')); return $model->toOptionArray(); } diff --git a/app/code/core/Mage/Paypal/Model/Direct.php b/app/code/core/Mage/Paypal/Model/Direct.php index 5170183a00..c5a6344bcc 100644 --- a/app/code/core/Mage/Paypal/Model/Direct.php +++ b/app/code/core/Mage/Paypal/Model/Direct.php @@ -124,8 +124,9 @@ public function getAllowedCcTypes() { $ccTypes = explode(',', $this->_pro->getConfig()->cctypes); $country = $this->_pro->getConfig()->getMerchantCountry(); + if ($country == 'GB') { - $ccTypes = array_intersect(array('SS', 'MC', 'DI', 'VI'), $ccTypes); + $ccTypes = array_intersect(array('SM', 'SO', 'MC', 'DI', 'VI'), $ccTypes); } elseif ($country == 'CA') { $ccTypes = array_intersect(array('MC', 'VI'), $ccTypes); } @@ -324,20 +325,18 @@ protected function _placeOrder(Mage_Sales_Model_Order_Payment $payment, $amount) $this->getCentinelValidator()->exportCmpiData($api); } - // add shipping address + // add shipping and billing addresses if ($order->getIsVirtual()) { $api->setAddress($order->getBillingAddress())->setSuppressShipping(true); } else { $api->setAddress($order->getShippingAddress()); + $api->setBillingAddress($order->getBillingAddress()); } // add line items - if ($this->_pro->getConfig()->lineItemsEnabled) { - list($items, $totals) = Mage::helper('paypal')->prepareLineItems($order); - if (Mage::helper('paypal')->areCartLineItemsValid($items, $totals, $amount)) { - $api->setLineItems($items)->setLineItemTotals($totals); - } - } + $api->setPaypalCart(Mage::getModel('paypal/cart', array($order))) + ->setIsLineItemsEnabled($this->_pro->getConfig()->lineItemsEnabled) + ; // call api and import transaction and other payment information $api->callDoDirectPayment(); diff --git a/app/code/core/Mage/Paypal/Model/Express.php b/app/code/core/Mage/Paypal/Model/Express.php index b78311e9d3..4c00bef97d 100644 --- a/app/code/core/Mage/Paypal/Model/Express.php +++ b/app/code/core/Mage/Paypal/Model/Express.php @@ -319,7 +319,7 @@ public function updateRecurringProfile(Mage_Payment_Model_Recurring_Profile $pro */ public function updateRecurringProfileStatus(Mage_Payment_Model_Recurring_Profile $profile) { - return $this->_pro->updateRecurringProfile($profile); + return $this->_pro->updateRecurringProfileStatus($profile); } /** @@ -362,16 +362,10 @@ protected function _placeOrder(Mage_Sales_Model_Order_Payment $payment, $amount) ->setNotifyUrl(Mage::getUrl('paypal/ipn/')) ->setInvNum($order->getIncrementId()) ->setCurrencyCode($order->getBaseCurrencyCode()) + ->setPaypalCart(Mage::getModel('paypal/cart', array($order))) + ->setIsLineItemsEnabled($this->_pro->getConfig()->lineItemsEnabled) ; - // add line items - if ($this->_pro->getConfig()->lineItemsEnabled) { - list($items, $totals) = Mage::helper('paypal')->prepareLineItems($order); - if (Mage::helper('paypal')->areCartLineItemsValid($items, $totals, $amount)) { - $api->setLineItems($items)->setLineItemTotals($totals); - } - } - // call api and get details from it $api->callDoExpressCheckoutPayment(); $this->_importToPayment($api, $payment); diff --git a/app/code/core/Mage/Paypal/Model/Express/Checkout.php b/app/code/core/Mage/Paypal/Model/Express/Checkout.php index 7bf370b5d2..c8b27f8deb 100644 --- a/app/code/core/Mage/Paypal/Model/Express/Checkout.php +++ b/app/code/core/Mage/Paypal/Model/Express/Checkout.php @@ -233,6 +233,21 @@ public function setCustomer($customer) return $this; } + /** + * Setter for customer with billing and shipping address changing ability + * + * @param Mage_Customer_Model_Customer $customer + * @param Mage_Sales_Model_Quote_Address $billingAddress + * @param Mage_Sales_Model_Quote_Address $shippingAddress + * @return Mage_Paypal_Model_Express_Checkout + */ + public function setCustomerWithAddressChange($customer, $billingAddress = null, $shippingAddress = null) + { + $this->_quote->assignCustomerWithAddressChange($customer, $billingAddress, $shippingAddress); + $this->_customerId = $customer->getId(); + return $this; + } + /** * Reserve order ID for specified quote and start checkout on PayPal * @return string @@ -240,6 +255,11 @@ public function setCustomer($customer) public function start($returnUrl, $cancelUrl) { $this->_quote->collectTotals(); + + if (!$this->_quote->getGrandTotal() && !$this->_quote->hasNominalItems()) { + Mage::throwException(Mage::helper('paypal')->__('PayPal does not support processing orders with zero amount. To complete your purchase, proceed to the standard checkout process.')); + } + $this->_quote->reserveOrderId()->save(); // prepare API $this->_getApi(); @@ -277,16 +297,16 @@ public function start($returnUrl, $cancelUrl) ); $this->_quote->getPayment()->save(); } + // add line items - if ($this->_config->lineItemsEnabled) { - list($items, $totals) = Mage::helper('paypal')->prepareLineItems($this->_quote); - if (Mage::helper('paypal')->areCartLineItemsValid($items, $totals, $this->_quote->getBaseGrandTotal())) { - $this->_api->setLineItems($items)->setLineItemTotals($totals); - } + $paypalCart = Mage::getModel('paypal/cart', array($this->_quote)); + $this->_api->setPaypalCart($paypalCart) + ->setIsLineItemsEnabled($this->_config->lineItemsEnabled) + ; - // add shipping options - if ($this->_config->transferShippingOptions - && !$this->_quote->getIsVirtual() && !$this->_quote->hasNominalItems()) { + // add shipping options if needed and line items are available + if ($this->_config->lineItemsEnabled && $this->_config->transferShippingOptions && $paypalCart->getItems()) { + if (!$this->_quote->getIsVirtual() && !$this->_quote->hasNominalItems()) { if ($options = $this->_prepareShippingOptions($address, true)) { $this->_api->setShippingOptionsCallbackUrl( Mage::getUrl('*/*/shippingOptionsCallback', array('quote_id' => $this->_quote->getId())) @@ -344,7 +364,7 @@ public function returnFromPaypal($token) foreach ($exportedShippingAddress->getExportedKeys() as $key) { $shippingAddress->setDataUsingMethod($key, $exportedShippingAddress->getData($key)); } - $shippingAddress->setCollectShippingRates(true)->collectShippingRates(); + $shippingAddress->setCollectShippingRates(true); } // import shipping method @@ -416,7 +436,7 @@ public function getShippingOptionsCallbackResponse(array $request) foreach ($address->getExportedKeys() as $key) { $quoteAddress->setDataUsingMethod($key, $address->getData($key)); } - $quoteAddress->setCollectShippingRates(true)->collectShippingRates(); + $quoteAddress->setCollectShippingRates(true)->collectTotals(); $options = $this->_prepareShippingOptions($quoteAddress, false); } $response = $this->_api->setShippingOptions($options)->formatShippingOptionsCallback(); @@ -604,7 +624,7 @@ protected function _prepareShippingOptions(Mage_Sales_Model_Quote_Address $addre foreach ($address->getGroupedAllShippingRates() as $group) { foreach ($group as $rate) { $amount = (float)$rate->getPrice(); - if (!$rate->getMethodTitle() || 0.00 == $amount) { + if ($rate->getErrorMessage()) { continue; } $isDefault = $address->getShippingMethod() === $rate->getCode(); diff --git a/app/code/core/Mage/Paypal/Model/Ipn.php b/app/code/core/Mage/Paypal/Model/Ipn.php index ae03803b1e..1907325b91 100644 --- a/app/code/core/Mage/Paypal/Model/Ipn.php +++ b/app/code/core/Mage/Paypal/Model/Ipn.php @@ -370,6 +370,9 @@ protected function _registerRecurringProfilePaymentCapture() */ protected function _registerPaymentCapture() { + if ($this->getRequestData('transaction_entity') == 'auth') { + return; + } $this->_importPaymentInformation(); $payment = $this->_order->getPayment(); $payment->setTransactionId($this->getRequestData('txn_id')) diff --git a/app/code/core/Mage/Paypal/Model/Method/Agreement.php b/app/code/core/Mage/Paypal/Model/Method/Agreement.php index dfe638b412..9ff5458380 100644 --- a/app/code/core/Mage/Paypal/Model/Method/Agreement.php +++ b/app/code/core/Mage/Paypal/Model/Method/Agreement.php @@ -301,15 +301,10 @@ protected function _placeOrder(Mage_Sales_Model_Order_Payment $payment, $amount) ->setReferenceId($billingAgreement->getReferenceId()) ->setPaymentAction($this->_pro->getConfig()->paymentAction) ->setAmount($amount) - ->setNotifyUrl(Mage::getUrl('paypal/ipn/')); - - // add line items - if ($this->_pro->getConfig()->lineItemsEnabled) { - list($items, $totals) = Mage::helper('paypal')->prepareLineItems($order); - if (Mage::helper('paypal')->areCartLineItemsValid($items, $totals, $amount)) { - $api->setLineItems($items)->setLineItemTotals($totals); - } - } + ->setNotifyUrl(Mage::getUrl('paypal/ipn/')) + ->setPaypalCart(Mage::getModel('paypal/cart', array($order))) + ->setIsLineItemsEnabled($this->_pro->getConfig()->lineItemsEnabled) + ; // call api and import transaction and other payment information $api->callDoReferenceTransaction(); @@ -322,6 +317,7 @@ protected function _placeOrder(Mage_Sales_Model_Order_Payment $payment, $amount) if ($api->getBillingAgreementId()) { $order->addRelatedObject($billingAgreement); + $billingAgreement->setIsObjectChanged(true); $billingAgreement->addOrderRelation($order->getId()); } diff --git a/app/code/core/Mage/Paypal/Model/Payflowpro.php b/app/code/core/Mage/Paypal/Model/Payflowpro.php index da45412704..61a9b5d71b 100644 --- a/app/code/core/Mage/Paypal/Model/Payflowpro.php +++ b/app/code/core/Mage/Paypal/Model/Payflowpro.php @@ -59,10 +59,12 @@ class Mage_Paypal_Model_Payflowpro extends Mage_Payment_Model_Method_Cc /** * Response codes */ - const RESPONSE_CODE_APPROVED = 0; - const RESPONSE_CODE_FRAUDSERVICE_FILTER = 126; - const RESPONSE_CODE_DECLINED = 12; - const RESPONSE_CODE_CAPTURE_ERROR = 111; + const RESPONSE_CODE_APPROVED = 0; + const RESPONSE_CODE_FRAUDSERVICE_FILTER = 126; + const RESPONSE_CODE_DECLINED = 12; + const RESPONSE_CODE_DECLINED_BY_FILTER = 125; + const RESPONSE_CODE_DECLINED_BY_MERCHANT = 128; + const RESPONSE_CODE_CAPTURE_ERROR = 111; /** * Payment method code @@ -83,6 +85,7 @@ class Mage_Paypal_Model_Payflowpro extends Mage_Payment_Model_Method_Cc protected $_canUseForMultishipping = true; protected $_canSaveCc = false; protected $_isProxy = false; + protected $_canFetchTransactionInfo = true; /** * Gateway request timeout @@ -255,6 +258,50 @@ public function refund(Varien_Object $payment, $amount) return $this; } + /** + * Fetch transaction details info + * + * @param Mage_Payment_Model_Info $payment + * @param string $transactionId + * @return array + */ + public function fetchTransactionInfo(Mage_Payment_Model_Info $payment, $transactionId) + { + $request = $this->_buildBasicRequest($payment); + $request->setTrxtype(self::TRXTYPE_DELAYED_INQUIRY); + $request->setOrigid($transactionId); + $response = $this->_postRequest($request); + + $this->_processErrors($response); + + if (!$this->_isTransactionUnderReview($response->getOrigresult())) { + $payment->setTransactionId($response->getOrigpnref()) + ->setIsTransactionClosed(0); + if ($response->getOrigresult() == self::RESPONSE_CODE_APPROVED) { + $payment->setIsTransactionApproved(true); + } else if ($response->getOrigresult() == self::RESPONSE_CODE_DECLINED_BY_MERCHANT) { + $payment->setIsTransactionDenied(true); + } + } + + $rawData = $response->getData(); + return ($rawData) ? $rawData : array(); + } + + /** + * Check whether the transaction is in payment review status + * + * @param string $statusCode + * @return bool + */ + protected static function _isTransactionUnderReview($status) + { + if (in_array($status, array(self::RESPONSE_CODE_APPROVED, self::RESPONSE_CODE_DECLINED_BY_MERCHANT))) { + return false; + } + return true; + } + /** * Getter for URL to perform Payflow requests, based on test mode by default * @@ -364,7 +411,7 @@ protected function _buildPlaceRequest(Varien_Object $payment, $amount) if (!empty($billing)) { $request->setFirstname($billing->getFirstname()) ->setLastname($billing->getLastname()) - ->setStreet($billing->getStreet(1)) + ->setStreet(implode(' ', $billing->getStreet())) ->setCity($billing->getCity()) ->setState($billing->getRegionCode()) ->setZip($billing->getPostcode()) @@ -373,9 +420,10 @@ protected function _buildPlaceRequest(Varien_Object $payment, $amount) } $shipping = $order->getShippingAddress(); if (!empty($shipping)) { + $this->_applyCountryWorkarounds($shipping); $request->setShiptofirstname($shipping->getFirstname()) ->setShiptolastname($shipping->getLastname()) - ->setShiptostreet($shipping->getStreet(1)) + ->setShiptostreet(implode(' ', $shipping->getStreet())) ->setShiptocity($shipping->getCity()) ->setShiptostate($shipping->getRegionCode()) ->setShiptozip($shipping->getPostcode()) @@ -427,4 +475,18 @@ protected function _processErrors(Varien_Object $response) Mage::throwException($response->getRespmsg()); } } + + /** + * Adopt specified address object to be compatible with Paypal + * Puerto Rico should be as state of USA and not as a country + * + * @param Varien_Object $address + */ + protected function _applyCountryWorkarounds(Varien_Object $address) + { + if ($address->getCountry() == 'PR') { + $address->setCountry('US'); + $address->setRegionCode('PR'); + } + } } diff --git a/app/code/core/Mage/Paypal/Model/Pro.php b/app/code/core/Mage/Paypal/Model/Pro.php index 0f96c0b179..ab0b760ca7 100644 --- a/app/code/core/Mage/Paypal/Model/Pro.php +++ b/app/code/core/Mage/Paypal/Model/Pro.php @@ -393,6 +393,16 @@ public function getRecurringProfileDetails($referenceId, Varien_Object $result) * @param Mage_Payment_Model_Recurring_Profile $profile */ public function updateRecurringProfile(Mage_Payment_Model_Recurring_Profile $profile) + { + + } + + /** + * Manage status + * + * @param Mage_Payment_Model_Recurring_Profile $profile + */ + public function updateRecurringProfileStatus(Mage_Payment_Model_Recurring_Profile $profile) { $api = $this->getApi(); $action = null; @@ -411,16 +421,6 @@ public function updateRecurringProfile(Mage_Payment_Model_Recurring_Profile $pro ; } - /** - * Manage status - * - * @param Mage_Payment_Model_Recurring_Profile $profile - */ - public function updateRecurringProfileStatus(Mage_Payment_Model_Recurring_Profile $profile) - { - - } - /** * Import capture results to payment * diff --git a/app/code/core/Mage/Paypal/Model/Report/Settlement.php b/app/code/core/Mage/Paypal/Model/Report/Settlement.php index c2c77c003f..a938598e4c 100644 --- a/app/code/core/Mage/Paypal/Model/Report/Settlement.php +++ b/app/code/core/Mage/Paypal/Model/Report/Settlement.php @@ -120,7 +120,7 @@ public function fetchAndSave($config) } $encoded = file_get_contents($localCsv); - $decoded = iconv(self::FILES_IN_CHARSET, self::FILES_OUT_CHARSET.'//IGNORE', $encoded); + $decoded = @iconv(self::FILES_IN_CHARSET, self::FILES_OUT_CHARSET.'//IGNORE', $encoded); file_put_contents($localCsv, $decoded); // Set last modified date, this value will be overwritten during parsing @@ -131,8 +131,11 @@ public function fetchAndSave($config) $this->setReportDate($this->_fileNameToDate($filename)) ->setFilename($filename) - ->parseCsv($localCsv) - ->save(); + ->parseCsv($localCsv); + + if ($this->getAccountId()) { + $this->save(); + } if ($this->_dataSaveAllowed) { $fetched += count($this->_rows); diff --git a/app/code/core/Mage/Paypal/Model/Standard.php b/app/code/core/Mage/Paypal/Model/Standard.php index cb5a77accd..4802a45a5b 100644 --- a/app/code/core/Mage/Paypal/Model/Standard.php +++ b/app/code/core/Mage/Paypal/Model/Standard.php @@ -123,6 +123,7 @@ public function getStandardCheckoutFormFields() $api->setOrderId($orderIncrementId) ->setCurrencyCode($order->getBaseCurrencyCode()) //->setPaymentAction() + ->setOrder($order) ->setNotifyUrl(Mage::getUrl('paypal/ipn/')) ->setReturnUrl(Mage::getUrl('paypal/standard/success')) ->setCancelUrl(Mage::getUrl('paypal/standard/cancel')); @@ -132,24 +133,16 @@ public function getStandardCheckoutFormFields() $address = $isOrderVirtual ? $order->getBillingAddress() : $order->getShippingAddress(); if ($isOrderVirtual) { $api->setNoShipping(true); - } - elseif ($address->getEmail()) { + } elseif ($address->validate()) { $api->setAddress($address); } - list($items, $totals, $discountAmount, $shippingAmount) = Mage::helper('paypal')->prepareLineItems($order, false, true); - // prepare line items if required in config - if ($this->_config->lineItemsEnabled) { - $api->setLineItems($items)->setLineItemTotals($totals)->setDiscountAmount($discountAmount); - } - // or values specific for aggregated order - else { - $grandTotal = $order->getBaseGrandTotal(); - if (!$isOrderVirtual) { - $api->setShippingAmount($shippingAmount); - $grandTotal -= $shippingAmount; - } - $api->setAmount($grandTotal)->setCartSummary($this->_getAggregatedCartSummary()); + // add cart totals and line items + $api->setPaypalCart(Mage::getModel('paypal/cart', array($order))) + ->setIsLineItemsEnabled($this->_config->lineItemsEnabled) + ; + if (!$this->_config->lineItemsEnabled) { + $api->setCartSummary($this->_getAggregatedCartSummary()); } $result = $api->getStandardCheckoutRequest(); diff --git a/app/code/core/Mage/Paypal/etc/system.xml b/app/code/core/Mage/Paypal/etc/system.xml index 677cbfe49e..a53ba3ba94 100644 --- a/app/code/core/Mage/Paypal/etc/system.xml +++ b/app/code/core/Mage/Paypal/etc/system.xml @@ -191,10 +191,12 @@ 1 1 - + Get Credentials from PayPal + Sandbox Credentials + paypal/adminhtml_system_config_apiWizard 20 1 @@ -560,7 +562,7 @@ - http://www.paypal.com/amexupdate.]]> + http://www.paypal.com/amexupdate.]]> payment/paypal_direct/cctypes multiselect paypal/config::getWppCcTypesAsOptionArray @@ -873,6 +875,7 @@ + payment/paypaluk_direct/cctypes multiselect paypal/config::getWppPeCcTypesAsOptionArray diff --git a/app/code/core/Mage/PaypalUk/Model/Api/Nvp.php b/app/code/core/Mage/PaypalUk/Model/Api/Nvp.php index e111572e22..3d8db9dcc8 100644 --- a/app/code/core/Mage/PaypalUk/Model/Api/Nvp.php +++ b/app/code/core/Mage/PaypalUk/Model/Api/Nvp.php @@ -122,7 +122,7 @@ class Mage_PaypalUk_Model_Api_Nvp extends Mage_Paypal_Model_Api_Nvp 'ACCT' => 'credit_card_number', 'EXPDATE' => 'credit_card_expiration_date', 'CVV2' => 'credit_card_cvv2', - 'CARDSTART' => 'maestro_solo_issue_date', // MMYYYY, always six chars, including leading zero + 'CARDSTART' => 'maestro_solo_issue_date', // MMYY, including leading zero 'CARDISSUE' => 'maestro_solo_issue_number', 'CVV2MATCH' => 'cvv2_check_result', // cardinal centinel @@ -264,7 +264,7 @@ class Mage_PaypalUk_Model_Api_Nvp extends Mage_Paypal_Model_Api_Nvp * Line items export mapping settings * @var array */ - protected $_lineItemExportTotals = array(); + protected $_lineItemTotalExportMap = array(); protected $_lineItemExportItemsFormat = array( 'name' => 'L_NAME%d', 'qty' => 'L_QTY%d', @@ -343,6 +343,19 @@ public function getTender() return self::TENDER_CC; } + /** + * Override transaction id getting to process payflow accounts not assigned to paypal side + * + * @return string + */ + public function getPaypalTransactionId() + { + if ($this->getData('paypal_transaction_id')) { + return $this->getData('paypal_transaction_id'); + } + return $this->getTransactionId(); + } + /** * Add method to request array * @@ -504,4 +517,18 @@ protected function _prepareExpressCheckoutCallRequest(&$requestFields) { return $requestFields; } + + /** + * Adopt specified request array to be compatible with Paypal + * Puerto Rico should be as state of USA and not as a country + * + * @param array $request + */ + protected function _applyCountryWorkarounds(&$request) + { + if (isset($request['SHIPTOCOUNTRY']) && $request['SHIPTOCOUNTRY'] == 'PR') { + $request['SHIPTOCOUNTRY'] = 'US'; + $request['SHIPTOSTATE'] = 'PR'; + } + } } diff --git a/app/code/core/Mage/ProductAlert/Block/Price.php b/app/code/core/Mage/ProductAlert/Block/Price.php index 801454ed70..c3f123ac2e 100644 --- a/app/code/core/Mage/ProductAlert/Block/Price.php +++ b/app/code/core/Mage/ProductAlert/Block/Price.php @@ -24,13 +24,9 @@ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ - /** - * ProductAlert price block - * - * @category Mage - * @package Mage_ProductAlert - * @author Magento Core Team + * @deprecated after 1.4.1.0 + * @see Mage_ProductAlert_Block_Product_View */ class Mage_ProductAlert_Block_Price extends Mage_Core_Block_Template { diff --git a/app/code/core/Mage/ProductAlert/Block/Product/View.php b/app/code/core/Mage/ProductAlert/Block/Product/View.php new file mode 100644 index 0000000000..9b867e1e81 --- /dev/null +++ b/app/code/core/Mage/ProductAlert/Block/Product/View.php @@ -0,0 +1,81 @@ +_product || $this->_product->isAvailable() + ) { + $this->setTemplate(''); + return; + } + $this->setSignupUrl(Mage::helper('productalert')->getSaveUrl('stock')); + } + + /** + * Check whether the price alert data can be shown and prepare related data + */ + public function preparePriceAlertData() + { + if (!Mage::getStoreConfigFlag(Mage_ProductAlert_Model_Observer::XML_PATH_PRICE_ALLOW) + || !$this->_product || false === $this->_product->getCanShowPrice() + ) { + $this->setTemplate(''); + return; + } + $this->setSignupUrl(Mage::helper('productalert')->getSaveUrl('price')); + } + + /** + * Get current product instance + * + * @return Mage_ProductAlert_Block_Product_View + */ + protected function _prepareLayout() + { + $product = Mage::registry('current_product'); + if ($product && $product->getId()) { + $this->_product = $product; + } + + return parent::_prepareLayout(); + } +} diff --git a/app/code/core/Mage/ProductAlert/Block/Stock.php b/app/code/core/Mage/ProductAlert/Block/Stock.php index bdc502a9c3..4bc696ace1 100644 --- a/app/code/core/Mage/ProductAlert/Block/Stock.php +++ b/app/code/core/Mage/ProductAlert/Block/Stock.php @@ -26,11 +26,8 @@ /** - * ProductAlert stock block - * - * @category Mage - * @package Mage_ProductAlert - * @author Magento Core Team + * @deprecated after 1.4.1.0 + * @see Mage_ProductAlert_Block_Product_View */ class Mage_ProductAlert_Block_Stock extends Mage_Core_Block_Template { diff --git a/app/code/core/Mage/Reports/Block/Product/Abstract.php b/app/code/core/Mage/Reports/Block/Product/Abstract.php index b7917bcd96..d5f077e0e6 100644 --- a/app/code/core/Mage/Reports/Block/Product/Abstract.php +++ b/app/code/core/Mage/Reports/Block/Product/Abstract.php @@ -111,7 +111,6 @@ public function getItemsCollection() ->addAttributeToSelect($attributes) ->excludeProductIds($this->_getModel()->getExcludeProductIds()) ->addUrlRewrite() - ->setAddedAtOrder() ->setPageSize($this->getPageSize()) ->setCurPage(1); $ids = $this->getProductIds(); @@ -120,6 +119,8 @@ public function getItemsCollection() } else { $this->_collection->addFilterByIds($ids); } + $this->_collection->setAddedAtOrder(); + Mage::getSingleton('catalog/product_visibility') ->addVisibleInSiteFilterToCollection($this->_collection); } diff --git a/app/code/core/Mage/Reports/Model/Mysql4/Order/Collection.php b/app/code/core/Mage/Reports/Model/Mysql4/Order/Collection.php index 6c21d7664d..dccbcc6b7a 100644 --- a/app/code/core/Mage/Reports/Model/Mysql4/Order/Collection.php +++ b/app/code/core/Mage/Reports/Model/Mysql4/Order/Collection.php @@ -285,13 +285,13 @@ protected function _calculateTotalsLive($isFilter = 0) if ($isFilter == 0) { $this->getSelect()->columns(array( - 'revenue' => 'SUM((main_table.base_subtotal-IFNULL(main_table.base_subtotal_refunded,0)-IFNULL(main_table.base_subtotal_canceled,0)-IFNULL(main_table.base_discount_amount,0)+IFNULL(main_table.base_discount_refunded,0))*main_table.base_to_global_rate)', + 'revenue' => 'SUM((main_table.base_subtotal-IFNULL(main_table.base_subtotal_refunded,0)-IFNULL(main_table.base_subtotal_canceled,0)-ABS(IFNULL(main_table.base_discount_amount,0))+IFNULL(main_table.base_discount_refunded,0))*main_table.base_to_global_rate)', 'tax' => 'SUM((main_table.base_tax_amount-IFNULL(main_table.base_tax_refunded,0)-IFNULL(main_table.base_tax_canceled,0))*main_table.base_to_global_rate)', 'shipping' => 'SUM((main_table.base_shipping_amount-IFNULL(main_table.base_shipping_refunded,0)-IFNULL(main_table.base_shipping_canceled,0))*main_table.base_to_global_rate)', )); } else { $this->getSelect()->columns(array( - 'revenue' => 'SUM((main_table.base_subtotal-IFNULL(main_table.base_subtotal_refunded,0)-IFNULL(main_table.base_subtotal_canceled,0)-IFNULL(main_table.base_discount_amount,0)+IFNULL(main_table.base_discount_refunded,0)))', + 'revenue' => 'SUM((main_table.base_subtotal-IFNULL(main_table.base_subtotal_refunded,0)-IFNULL(main_table.base_subtotal_canceled,0)-ABS(IFNULL(main_table.base_discount_amount,0))+IFNULL(main_table.base_discount_refunded,0)))', 'tax' => 'SUM((main_table.base_tax_amount-IFNULL(main_table.base_tax_refunded,0)-IFNULL(main_table.base_tax_canceled,0)))', 'shipping' => 'SUM((main_table.base_shipping_amount-IFNULL(main_table.base_shipping_refunded,0)-IFNULL(main_table.base_shipping_canceled,0)))', )); @@ -370,7 +370,7 @@ public function calculateSales($isFilter = 0) $this->setMainTable('sales/order'); $this->removeAllFieldsFromSelect(); $expr = 'IFNULL(main_table.base_subtotal, 0) - IFNULL(main_table.base_subtotal_refunded, 0)' - . ' - IFNULL(main_table.base_subtotal_canceled, 0) - IFNULL(main_table.base_discount_amount, 0)' + . ' - IFNULL(main_table.base_subtotal_canceled, 0) - ABS(IFNULL(main_table.base_discount_amount, 0))' . ' + IFNULL(main_table.base_discount_refunded, 0)'; $this->getSelect()->columns(array( diff --git a/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Abstract.php b/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Abstract.php index 9501cd360c..044c3e0f4e 100644 --- a/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Abstract.php +++ b/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Abstract.php @@ -165,18 +165,20 @@ public function registerIds($object, $productIds) 'visitor_id' => $object->getVisitorId(), 'customer_id' => $object->getCustomerId(), 'store_id' => $object->getStoreId(), - 'added_at' => now(), ); + $addedAt = new Zend_Date(); $data = array(); foreach ($productIds as $productId) { $productId = (int) $productId; if ($productId) { $row['product_id'] = $productId; + $row['added_at'] = $addedAt->toString(Varien_Date::DATETIME_INTERNAL_FORMAT); $data[] = $row; } + $addedAt->subSecond(1); } if (!empty($data)) { - $this->_getWriteAdapter()->insertOnDuplicate($this->getMainTable(), $data, array('product_id')); + $this->_getWriteAdapter()->insertOnDuplicate($this->getMainTable(), $data, array_keys($row)); } return $this; } diff --git a/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Collection/Abstract.php b/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Collection/Abstract.php index e425c825b7..e0db893750 100644 --- a/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Collection/Abstract.php +++ b/app/code/core/Mage/Reports/Model/Mysql4/Product/Index/Collection/Abstract.php @@ -86,7 +86,7 @@ public function addFilterByIds($ids) if (empty($ids)) { $this->getSelect()->where('0'); } else { - $this->getSelect()->where('entity_id IN(?)', $ids); + $this->getSelect()->where('e.entity_id IN(?)', $ids); } return $this; } diff --git a/app/code/core/Mage/Reports/Model/Mysql4/Product/Sold/Collection.php b/app/code/core/Mage/Reports/Model/Mysql4/Product/Sold/Collection.php index 113e5d52d2..bd57e3f50a 100644 --- a/app/code/core/Mage/Reports/Model/Mysql4/Product/Sold/Collection.php +++ b/app/code/core/Mage/Reports/Model/Mysql4/Product/Sold/Collection.php @@ -59,9 +59,11 @@ public function setDateRange($from, $to) */ public function setStoreIds($storeIds) { - $storeId = array_pop($storeIds); - $this->setStoreId($storeId); - $this->addStoreFilter($storeId); + if (!empty($storeIds[0])) { + $storeIds = array_values($storeIds); + $this->getSelect()->where('order_items.store_id IN(?)', $storeIds); + } + return $this; } } diff --git a/app/code/core/Mage/Reports/Model/Mysql4/Quote/Collection.php b/app/code/core/Mage/Reports/Model/Mysql4/Quote/Collection.php index 27016efd9a..9d076279bc 100644 --- a/app/code/core/Mage/Reports/Model/Mysql4/Quote/Collection.php +++ b/app/code/core/Mage/Reports/Model/Mysql4/Quote/Collection.php @@ -34,10 +34,33 @@ */ class Mage_Reports_Model_Mysql4_Quote_Collection extends Mage_Sales_Model_Mysql4_Quote_Collection { + /** + * Type of total quantity calculation of Products in Carts report + */ + const SELECT_COUNT_SQL_TYPE_CART = 1; + + /** + * Type of total quantity calculation + * @var int + */ + protected $_selectCountSqlType = 0; + protected $_joinedFields = array(); protected $_map = array('fields' => array('store_id' => 'main_table.store_id')); + /** + * Set type for COUNT SQL select + * + * @param int $type + * @return Mage_Reports_Model_Mysql4_Quote_Collection + */ + public function setSelectCountSqlType($type) + { + $this->_selectCountSqlType = $type; + return $this; + } + public function prepareForAbandonedReport($storeIds, $filter = null) { $this->addFieldToFilter('items_count', array('neq' => '0')) @@ -51,6 +74,46 @@ public function prepareForAbandonedReport($storeIds, $filter = null) return $this; } + /** + * Prepare select query for products in carts report + * + * @return Mage_Reports_Model_Mysql4_Quote_Collection + */ + public function prepareForProductsInCarts() + { + $productEntity = Mage::getResourceSingleton('catalog/product_collection'); + $productAttrName = $productEntity->getAttribute('name'); + $productAttrNameId = $productAttrName->getAttributeId(); + $productAttrNameTable = $productAttrName->getBackend()->getTable(); + $productAttrPrice = $productEntity->getAttribute('price'); + $productAttrPriceId = $productAttrPrice->getAttributeId(); + $productAttrPriceTable = $productAttrPrice->getBackend()->getTable(); + + $ordersSubSelect = clone $this->getSelect(); + $ordersSubSelect->reset() + ->from(array('order_items' => $this->getTable('sales/order_item')), new Zend_Db_Expr('COUNT(1)')) + ->where('order_items.product_id = e.entity_id'); + + $this->getSelect() + ->useStraightJoin(true) + ->reset(Zend_Db_Select::COLUMNS) + ->joinInner(array('quote_items' => $this->getTable('sales/quote_item')), 'quote_items.quote_id = main_table.entity_id', null) + ->joinInner(array('e' => $this->getTable('catalog/product')), 'e.entity_id = quote_items.product_id', null) + ->joinInner(array('product_name' => $productAttrNameTable), + "product_name.entity_id = e.entity_id and product_name.attribute_id = {$productAttrNameId}", + array('name'=>'product_name.value')) + ->joinInner(array('product_price' => $productAttrPriceTable), + "product_price.entity_id = e.entity_id and product_price.attribute_id = {$productAttrPriceId}", + array('price'=>'product_price.value')) + ->columns('e.*') + ->columns(array('carts' => new Zend_Db_Expr('count(quote_items.item_id)'))) + ->columns("({$ordersSubSelect}) AS orders") + ->where('main_table.is_active = ?', 1) + ->group('quote_items.product_id'); + + return $this; + } + /** * Add store ids to filter * @@ -143,7 +206,11 @@ public function getSelectCountSql() $countSelect->reset(Zend_Db_Select::COLUMNS); $countSelect->reset(Zend_Db_Select::GROUP); - $countSelect->columns("count(DISTINCT main_table.entity_id)"); + if ($this->_selectCountSqlType == self::SELECT_COUNT_SQL_TYPE_CART) { + $countSelect->columns("count(DISTINCT e.entity_id)"); + } else { + $countSelect->columns("count(DISTINCT main_table.entity_id)"); + } $sql = $countSelect->__toString(); return $sql; diff --git a/app/code/core/Mage/Reports/Model/Mysql4/Report/Collection.php b/app/code/core/Mage/Reports/Model/Mysql4/Report/Collection.php index 09a092a2d6..502163a6aa 100644 --- a/app/code/core/Mage/Reports/Model/Mysql4/Report/Collection.php +++ b/app/code/core/Mage/Reports/Model/Mysql4/Report/Collection.php @@ -196,6 +196,6 @@ public function getReport($from, $to) public function timeShift($datetime) { - return date('Y-m-d H:i:s', strtotime($datetime) - Mage::getModel('core/date')->getGmtOffset()); + return Mage::app()->getLocale()->utcDate(null, $datetime, true, Varien_Date::DATETIME_INTERNAL_FORMAT)->toString(Varien_Date::DATETIME_INTERNAL_FORMAT); } } diff --git a/app/code/core/Mage/Review/Block/Form.php b/app/code/core/Mage/Review/Block/Form.php index 9952abbd27..26ec8fc70e 100644 --- a/app/code/core/Mage/Review/Block/Form.php +++ b/app/code/core/Mage/Review/Block/Form.php @@ -35,6 +35,8 @@ class Mage_Review_Block_Form extends Mage_Core_Block_Template { public function __construct() { + $customerSession = Mage::getSingleton('customer/session'); + parent::__construct(); $data = Mage::getSingleton('review/session')->getFormData(true); @@ -42,12 +44,24 @@ public function __construct() // add logged in customer name as nickname if (!$data->getNickname()) { - $customer = Mage::getSingleton('customer/session')->getCustomer(); + $customer = $customerSession->getCustomer(); if ($customer && $customer->getId()) { $data->setNickname($customer->getFirstname()); } } + $this->setAllowWriteReviewFlag($customerSession->isLoggedIn() || Mage::helper('review')->getIsGuestAllowToWrite()); + if (!$this->getAllowWriteReviewFlag) { + $this->setLoginLink( + Mage::getUrl('customer/account/login/', array( + Mage_Customer_Helper_Data::REFERER_QUERY_PARAM_NAME => Mage::helper('core')->urlEncode( + Mage::getUrl('*/*/*', array('_current' => true)) . + '#review-form') + ) + ) + ); + } + $this->setTemplate('review/form.phtml') ->assign('data', $data) ->assign('messages', Mage::getSingleton('review/session')->getMessages(true)); diff --git a/app/code/core/Mage/Review/Helper/Data.php b/app/code/core/Mage/Review/Helper/Data.php index 73764762b7..31d257e29d 100644 --- a/app/code/core/Mage/Review/Helper/Data.php +++ b/app/code/core/Mage/Review/Helper/Data.php @@ -37,6 +37,15 @@ public function getDetail($origDetail){ return nl2br(Mage::helper('core/string')->truncate($origDetail, 50)); } + /** + * getDetailHtml return short detail info in HTML + * @param string $origDetail Full detail info + * @return string + */ + public function getDetailHtml($origDetail){ + return nl2br(Mage::helper('core/string')->truncate($this->escapeHtml($origDetail), 50)); + } + public function getIsGuestAllowToWrite() { return Mage::getStoreConfigFlag(self::XML_REVIEW_GUETS_ALLOW); diff --git a/app/code/core/Mage/Review/Model/Mysql4/Review/Product/Collection.php b/app/code/core/Mage/Review/Model/Mysql4/Review/Product/Collection.php index f44bb001c6..45ed47e254 100644 --- a/app/code/core/Mage/Review/Model/Mysql4/Review/Product/Collection.php +++ b/app/code/core/Mage/Review/Model/Mysql4/Review/Product/Collection.php @@ -43,6 +43,7 @@ protected function _construct() $this->_init('catalog/product'); $this->setRowIdFieldName('review_id'); $this->_reviewStoreTable = Mage::getSingleton('core/resource')->getTableName('review/review_store'); + $this->_initTables(); } protected function _initSelect() diff --git a/app/code/core/Mage/Review/controllers/ProductController.php b/app/code/core/Mage/Review/controllers/ProductController.php index 922542ea85..9cbdd43383 100644 --- a/app/code/core/Mage/Review/controllers/ProductController.php +++ b/app/code/core/Mage/Review/controllers/ProductController.php @@ -220,7 +220,12 @@ public function listAction() { if ($product = $this->_initProduct()) { Mage::register('productId', $product->getId()); - Mage::getModel('catalog/design')->applyDesign($product, Mage_Catalog_Model_Design::APPLY_FOR_PRODUCT); + + $design = Mage::getSingleton('catalog/design'); + $settings = $design->getDesignSettings($product); + if ($settings->getCustomDesign()) { + $design->applyCustomDesign($settings->getCustomDesign()); + } $this->_initProductLayout($product); // update breadcrumbs diff --git a/app/code/core/Mage/Rss/Block/Catalog/Special.php b/app/code/core/Mage/Rss/Block/Catalog/Special.php index ddb5571a12..f07a7b0ffb 100644 --- a/app/code/core/Mage/Rss/Block/Catalog/Special.php +++ b/app/code/core/Mage/Rss/Block/Catalog/Special.php @@ -33,6 +33,13 @@ */ class Mage_Rss_Block_Catalog_Special extends Mage_Rss_Block_Abstract { + /** + * Zend_Date object for date comparsions + * + * @var Zend_Date $_currentDate + */ + protected static $_currentDate = null; + protected function _construct() { /* @@ -49,39 +56,24 @@ protected function _toHtml() $websiteId = Mage::app()->getStore($storeId)->getWebsiteId(); //customer group id - $custGroup = $this->_getCustomerGroupId(); + $customerGroupId = $this->_getCustomerGroupId(); $product = Mage::getModel('catalog/product'); - $todayDate = $product->getResource()->formatDate(time()); - - $rulePriceWhere = "({{table}}.rule_date is null) or ({{table}}.rule_date='$todayDate' and {{table}}.website_id='$websiteId' and {{table}}.customer_group_id='$custGroup')"; + $fields = array( + 'final_price', + 'price' + ); $specials = $product->setStoreId($storeId)->getResourceCollection() - ->addAttributeToFilter('special_price', array('gt'=>0), 'left') - ->addAttributeToFilter('special_from_date', array('date'=>true, 'to'=> $todayDate), 'left') - ->addAttributeToFilter(array( - array('attribute'=>'special_to_date', 'date'=>true, 'from'=>$todayDate), - array('attribute'=>'special_to_date', 'is' => new Zend_Db_Expr('null')) - ), '', 'left') - ->addAttributeToSort('special_from_date', 'desc') - ->addAttributeToSelect(array('name', 'short_description', 'description', 'price', 'thumbnail', 'special_to_date'), 'inner') - ->joinTable('catalogrule/rule_product_price', 'product_id=entity_id', array('rule_price'=>'rule_price', 'rule_start_date'=>'latest_start_date'), $rulePriceWhere, 'left') - ; - - $rulePriceCollection = Mage::getResourceModel('catalogrule/rule_product_price_collection') - ->addFieldToFilter('website_id', $websiteId) - ->addFieldToFilter('customer_group_id', $custGroup) - ->addFieldToFilter('rule_date', $todayDate) + ->addPriceDataFieldFilter('%s < %s', $fields) + ->addPriceData($customerGroupId, $websiteId) + ->addAttributeToSelect( + array('name', 'short_description', 'description', 'price', 'thumbnail', + 'special_price', 'special_to_date'), + 'left') + ->addAttributeToSort('name', 'asc') ; - $productIds = $rulePriceCollection->getProductIds(); - - if (!empty($productIds)) { - $specials->getSelect()->orWhere('e.entity_id in ('.implode(',',$productIds).')'); - } - - $specials->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds()); - $newurl = Mage::getUrl('rss/catalog/special/store_id/' . $storeId); $title = Mage::helper('rss')->__('%s - Special Products', Mage::app()->getStore()->getFrontendName()); $lang = Mage::getStoreConfig('general/locale/code'); @@ -103,31 +95,38 @@ protected function _toHtml() Mage::getSingleton('core/resource_iterator') ->walk($specials->getSelect(), array(array($this, 'addSpecialXmlCallback')), array('rssObj'=> $rssObj, 'results'=> &$results)); - if(sizeof($results)>0){ - usort($results, array(&$this, 'sortByStartDate')); + if (sizeof($results)>0) { foreach($results as $result){ + // render a row for RSS feed $product->setData($result); + $html = sprintf(' + +
    %s', + $product->getProductUrl(), + $this->helper('catalog/image')->init($product, 'thumbnail')->resize(75, 75), + $this->helper('catalog/output')->productAttribute($product, $product->getDescription(), 'description') + ); - $description = ''. - ''. - '
    '.$product->getDescription(); - + // add price data if needed if ($product->getAllowedPriceInRss()) { - $specialPrice = ($result['use_special'] ? $result['special_price'] : $result['rule_price']); - $description .= '

    Price:'.Mage::helper('core')->currency($product->getPrice()). - ' Special Price:'. Mage::helper('core')->currency($specialPrice). - ($result['use_special'] && $result['special_to_date'] ? '
    Special Expires on: '.$this->formatDate($result['special_to_date'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM) : ''). - '

    '; + $special = ''; + if ($result['use_special']) { + $special = '
    ' . Mage::helper('catalog')->__('Special Expires On: %s', $this->formatDate($result['special_to_date'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM)); + } + $html .= sprintf('

    %s %s%s

    ', + Mage::helper('catalog')->__('Price: %s', Mage::helper('core')->currency($result['price'])), + Mage::helper('catalog')->__('Special Price: %s', Mage::helper('core')->currency($result['final_price'])), + $special + ); } - $description .= '
    '; + $html .= '
    '; - $data = array( - 'title' => $product->getName(), - 'link' => $product->getProductUrl(), - 'description' => $description - ); - $rssObj->_addEntry($data); + $rssObj->_addEntry(array( + 'title' => $product->getName(), + 'link' => $product->getProductUrl(), + 'description' => $html + )); } } return $rssObj->createRssXml(); @@ -140,38 +139,31 @@ protected function _toHtml() */ public function addSpecialXmlCallback($args) { - /* - * RSS state object - */ - $product = new Varien_Object(); - //Product is allowed for RSS initially - $product->setAllowedInRss(true); - $args['product'] = $product; + if (!isset(self::$_currentDate)) { + self::$_currentDate = new Zend_Date(); + } + // dispatch event to determine whether the product will eventually get to the result + $product = new Varien_Object(array('allowed_in_rss' => true, 'allowed_price_in_rss' => true)); + $args['product'] = $product; Mage::dispatchEvent('rss_catalog_special_xml_callback', $args); - if (!$product->getAllowedInRss()) { - //Skip adding product to RSS return; } - $row = $args['row']; - - if ($product->getAllowedPriceInRss()) { - $specialPrice = $row['special_price']; - $rulePrice = $row['rule_price']; - if (!$rulePrice || ($rulePrice && $specialPrice && $specialPrice<=$rulePrice)) { - $row['start_date'] = $row['special_from_date']; - $row['use_special'] = true; - } else { - $row['start_date'] = $row['rule_start_date']; - $row['use_special'] = false; - } - $row['allowed_price_in_rss'] = true; - } else { - $row['start_date'] = null; - $row['allowed_price_in_rss'] = false; - } + // add row to result and determine whether special price is active (less or equal to the final price) + $row = $args['row']; + $row['use_special'] = false; + $row['allowed_price_in_rss'] = $product->getAllowedPriceInRss(); + if (isset($row['special_to_date']) && $row['final_price'] <= $row['special_price'] + && $row['allowed_price_in_rss'] + ) { + $compareDate = self::$_currentDate->compareDate($row['special_to_date'], Varien_Date::DATE_INTERNAL_FORMAT); + if (-1 === $compareDate || 0 === $compareDate) { + $row['use_special'] = true; + } + } + $args['results'][] = $row; } diff --git a/app/code/core/Mage/Rss/etc/config.xml b/app/code/core/Mage/Rss/etc/config.xml index a2247d1d6a..a8d89e7227 100644 --- a/app/code/core/Mage/Rss/etc/config.xml +++ b/app/code/core/Mage/Rss/etc/config.xml @@ -106,7 +106,8 @@ /rss/catalog/review - /rss/catalog/review + /rss/order/new + /rss/catalog/notifystock diff --git a/app/code/core/Mage/Rule/Model/Condition/Abstract.php b/app/code/core/Mage/Rule/Model/Condition/Abstract.php index a2d6a95c45..54e872204c 100644 --- a/app/code/core/Mage/Rule/Model/Condition/Abstract.php +++ b/app/code/core/Mage/Rule/Model/Condition/Abstract.php @@ -79,6 +79,7 @@ public function getDefaultOperatorInputByType() 'numeric' => array('==', '!=', '>=', '>', '<=', '<', '()', '!()'), 'date' => array('==', '>=', '<='), 'select' => array('==', '!='), + 'boolean' => array('==', '!='), 'multiselect' => array('==', '!=', '{}', '!{}'), 'grid' => array('()', '!()'), ); @@ -209,7 +210,11 @@ public function getInputType() public function getOperatorSelectOptions() { - $type = $this->getInputType(); + if ($this->getAttribute() === 'category_ids') { + $type = 'multiselect'; + } else { + $type = $this->getInputType(); + } $opt = array(); $operatorByType = $this->getOperatorByInputType(); foreach ($this->getOperatorOption() as $k=>$v) { diff --git a/app/code/core/Mage/Rule/Model/Rule.php b/app/code/core/Mage/Rule/Model/Rule.php index 3a6aa424e4..a3625512f1 100644 --- a/app/code/core/Mage/Rule/Model/Rule.php +++ b/app/code/core/Mage/Rule/Model/Rule.php @@ -355,10 +355,10 @@ public function setIsReadonly($value) public function validateData(Varien_Object $object) { if($object->getData('from_date') && $object->getData('to_date')){ - $dateStartUnixTime = strtotime($object->getData('from_date')); - $dateEndUnixTime = strtotime($object->getData('to_date')); - - if ($dateEndUnixTime < $dateStartUnixTime) { + $dateStart = new Zend_Date($object->getData('from_date'), Varien_Date::DATE_INTERNAL_FORMAT); + $dateEnd = new Zend_Date($object->getData('to_date'), Varien_Date::DATE_INTERNAL_FORMAT); + + if ($dateStart->compare($dateEnd)===1) { return array(Mage::helper('rule')->__("End Date should be greater than Start Date")); } } diff --git a/app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Agreement.php b/app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Agreement.php index 9c3d1b3160..ee345d39ce 100644 --- a/app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Agreement.php +++ b/app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Agreement.php @@ -44,9 +44,9 @@ class Mage_Sales_Block_Adminhtml_Customer_Edit_Tab_Agreement * Disable filters and paging * */ - public function __construct() + public function _construct() { - parent::__construct(); + parent::_construct(); $this->setId('customer_edit_tab_agreements'); } diff --git a/app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Recurring/Profile.php b/app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Recurring/Profile.php new file mode 100644 index 0000000000..130baf7861 --- /dev/null +++ b/app/code/core/Mage/Sales/Block/Adminhtml/Customer/Edit/Tab/Recurring/Profile.php @@ -0,0 +1,112 @@ + + */ +class Mage_Sales_Block_Adminhtml_Customer_Edit_Tab_Recurring_Profile + extends Mage_Sales_Block_Adminhtml_Recurring_Profile_Grid + implements Mage_Adminhtml_Block_Widget_Tab_Interface +{ + /** + * Disable filters and paging + * + */ + public function _construct() + { + parent::_construct(); + $this->setId('customer_edit_tab_recurring_profile'); + } + + /** + * Return Tab label + * + * @return string + */ + public function getTabLabel() + { + return $this->__('Recurring Profiles (beta)'); + } + + /** + * Return Tab title + * + * @return string + */ + public function getTabTitle() + { + return $this->__('Recurring Profiles (beta)'); + } + + /** + * Can show tab in tabs + * + * @return boolean + */ + public function canShowTab() + { + $customer = Mage::registry('current_customer'); + return (bool)$customer->getId(); + } + + /** + * Tab is hidden + * + * @return boolean + */ + public function isHidden() + { + return false; + } + + /** + * Prepare collection for grid + * + * @return Mage_Sales_Block_Adminhtml_Customer_Edit_Tab_Recurring_Profile + */ + protected function _prepareCollection() + { + $collection = Mage::getResourceModel('sales/recurring_profile_collection') + ->addFieldToFilter('customer_id', Mage::registry('current_customer')->getId()); + if (!$this->getParam($this->getVarNameSort())) { + $collection->setOrder('profile_id', 'desc'); + } + $this->setCollection($collection); + return Mage_Adminhtml_Block_Widget_Grid::_prepareCollection(); + } + + /** + * Defines after which tab, this tab should be rendered + * + * @return string + */ + public function getAfter() + { + return 'orders'; + } +} diff --git a/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/View/Tab/Orders.php b/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/View/Tab/Orders.php index 3fb12955ca..11c49f39b5 100644 --- a/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/View/Tab/Orders.php +++ b/app/code/core/Mage/Sales/Block/Adminhtml/Recurring/Profile/View/Tab/Orders.php @@ -50,7 +50,7 @@ public function __construct() */ protected function _prepareCollection() { - $collection = Mage::getResourceModel('sales/order_collection') + $collection = Mage::getResourceModel('sales/order_grid_collection') ->addRecurringProfilesFilter(Mage::registry('current_recurring_profile')->getId()) ; $this->setCollection($collection); diff --git a/app/code/core/Mage/Sales/Block/Billing/Agreement/View.php b/app/code/core/Mage/Sales/Block/Billing/Agreement/View.php index eaa3f045d8..91ef3ea528 100644 --- a/app/code/core/Mage/Sales/Block/Billing/Agreement/View.php +++ b/app/code/core/Mage/Sales/Block/Billing/Agreement/View.php @@ -161,12 +161,8 @@ protected function _toHtml() 'payment_method' => $this->_billingAgreementInstance->getMethodCode())) ); - $methodCode = $this->_billingAgreementInstance->getMethodCode(); - if (isset($this->_paymentMethods[$methodCode])) { - $this->setPaymentMethodTitle($this->_paymentMethods[$methodCode]); - } else { - $this->setPaymentMethodTitle($methodCode); - } + $paymentMethodTitle = $this->_billingAgreementInstance->getAgreementLabel(); + $this->setPaymentMethodTitle($paymentMethodTitle); $createdAt = $this->_billingAgreementInstance->getCreatedAt(); $updatedAt = $this->_billingAgreementInstance->getUpdatedAt(); diff --git a/app/code/core/Mage/Sales/Block/Billing/Agreements.php b/app/code/core/Mage/Sales/Block/Billing/Agreements.php index 8370b220f9..a985628d38 100644 --- a/app/code/core/Mage/Sales/Block/Billing/Agreements.php +++ b/app/code/core/Mage/Sales/Block/Billing/Agreements.php @@ -95,9 +95,8 @@ public function getItemValue(Mage_Sales_Model_Billing_Agreement $item, $key) $value = $this->getUrl('*/billing_agreement/view', array('agreement' => $item->getAgreementId())); break; case 'payment_method_label': - $this->_loadPaymentMethods(); - $value = isset($this->_paymentMethods[$item->getMethodCode()]) - ? $this->_paymentMethods[$item->getMethodCode()] : $this->__('N/A'); + $label = $item->getAgreementLabel(); + $value = ($label) ? $label : $this->__('N/A'); break; case 'status': $value = $item->getStatusLabel(); diff --git a/app/code/core/Mage/Sales/Block/Order/Comments.php b/app/code/core/Mage/Sales/Block/Order/Comments.php new file mode 100644 index 0000000000..5c68b3fd20 --- /dev/null +++ b/app/code/core/Mage/Sales/Block/Order/Comments.php @@ -0,0 +1,102 @@ +_entity = $entity; + $this->_commentCollection = null; // Changing model and resource model can lead to change of comment collection + return $this; + } + + /** + * Gets comments parent model instance + * + * @return Mage_Sales_Model_Abstract + */ + public function getEntity() + { + return $this->_entity; + } + + /** + * Initialize model comments and return comment collection + * + * @return Mage_Sales_Model_Mysql4_Order_Comment_Collection_Abstract + */ + public function getComments() + { + if (is_null($this->_commentCollection)) { + $entity = $this->getEntity(); + if ($entity instanceof Mage_Sales_Model_Order_Invoice) { + $collectionClass = 'sales/order_invoice_comment_collection'; + } else if ($entity instanceof Mage_Sales_Model_Order_Creditmemo) { + $collectionClass = 'sales/order_creditmemo_comment_collection'; + } else if ($entity instanceof Mage_Sales_Model_Order_Shipment) { + $collectionClass = 'sales/order_shipment_comment_collection'; + } else { + Mage::throwException(Mage::helper('sales')->__('Invalid entity model')); + } + + $this->_commentCollection = Mage::getResourceModel($collectionClass); + $this->_commentCollection->setParentFilter($entity) + ->setCreatedAtOrder() + ->addVisibleOnFrontFilter(); + } + + return $this->_commentCollection; + } + + /** + * Returns whether there are comments to show on frontend + * + * @return bool + */ + public function hasComments() + { + return $this->getComments()->count() > 0; + } +} diff --git a/app/code/core/Mage/Sales/Block/Order/Creditmemo/Items.php b/app/code/core/Mage/Sales/Block/Order/Creditmemo/Items.php index f7f21aa3e9..f3065ac3e3 100644 --- a/app/code/core/Mage/Sales/Block/Order/Creditmemo/Items.php +++ b/app/code/core/Mage/Sales/Block/Order/Creditmemo/Items.php @@ -69,4 +69,22 @@ public function getTotalsHtml($creditmemo) } return $html; } + + /** + * Get html of creditmemo comments block + * + * @param Mage_Sales_Model_Order_Creditmemo $creditmemo + * @return string + */ + public function getCommentsHtml($creditmemo) + { + $html = ''; + $comments = $this->getChild('creditmemo_comments'); + if ($comments) { + $comments->setEntity($creditmemo) + ->setTitle(Mage::helper('sales')->__('About Your Refund')); + $html = $comments->toHtml(); + } + return $html; + } } diff --git a/app/code/core/Mage/Sales/Block/Order/Invoice/Items.php b/app/code/core/Mage/Sales/Block/Order/Invoice/Items.php index 52cfca274b..006e5926b4 100644 --- a/app/code/core/Mage/Sales/Block/Order/Invoice/Items.php +++ b/app/code/core/Mage/Sales/Block/Order/Invoice/Items.php @@ -69,4 +69,22 @@ public function getInvoiceTotalsHtml($invoice) } return $html; } + + /** + * Get html of invoice comments block + * + * @param Mage_Sales_Model_Order_Invoice $invoice + * @return string + */ + public function getInvoiceCommentsHtml($invoice) + { + $html = ''; + $comments = $this->getChild('invoice_comments'); + if ($comments) { + $comments->setEntity($invoice) + ->setTitle(Mage::helper('sales')->__('About Your Invoice')); + $html = $comments->toHtml(); + } + return $html; + } } diff --git a/app/code/core/Mage/Sales/Block/Order/Item/Renderer/Default.php b/app/code/core/Mage/Sales/Block/Order/Item/Renderer/Default.php index c23d9992f0..8820bb8407 100644 --- a/app/code/core/Mage/Sales/Block/Order/Item/Renderer/Default.php +++ b/app/code/core/Mage/Sales/Block/Order/Item/Renderer/Default.php @@ -160,9 +160,9 @@ public function getFormatedOptionValue($optionValue) */ public function getSku() { - if ($this->getOrderItem()->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) { + /*if ($this->getOrderItem()->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) { return $this->getOrderItem()->getProductOptionByCode('simple_sku'); - } + }*/ return $this->getItem()->getSku(); } } diff --git a/app/code/core/Mage/Sales/Block/Order/Print/Shipment.php b/app/code/core/Mage/Sales/Block/Order/Print/Shipment.php index 02dd69b2c1..517250521d 100644 --- a/app/code/core/Mage/Sales/Block/Order/Print/Shipment.php +++ b/app/code/core/Mage/Sales/Block/Order/Print/Shipment.php @@ -34,10 +34,42 @@ class Mage_Sales_Block_Order_Print_Shipment extends Mage_Sales_Block_Items_Abstract { + /** + * Tracks for Shippings + * + * @var array + */ + protected $_tracks = array(); - public function __construct() + /** + * Order shipments collection + * + * @var array|Mage_Sales_Model_Mysql4_Order_Shipment_Collection + */ + protected $_shipmentsCollection; + + /** + * Load all tracks and save it to local cache by shipments + * + * @return Mage_Sales_Block_Order_Print_Shipment + */ + protected function _beforeToHtml() { - parent::__construct(); + $tracksCollection = $this->getOrder()->getTracksCollection(); + + foreach($tracksCollection->getItems() as $track) { + $shipmentId = $track->getParentId(); + $this->_tracks[$shipmentId][] = $track; + } + + $shipment = Mage::registry('current_shipment'); + if($shipment) { + $this->_shipmentsCollection = array($shipment); + } else { + $this->_shipmentsCollection = $this->getOrder()->getShipmentsCollection(); + } + + return parent::_beforeToHtml(); } protected function _prepareLayout() @@ -82,5 +114,73 @@ protected function _prepareItem(Mage_Core_Block_Abstract $renderer) return parent::_prepareItem($renderer); } + + /** + * Retrieve order shipments collection + * + * @return array|Mage_Sales_Model_Mysql4_Order_Shipment_Collection + */ + public function getShipmentsCollection() + { + return $this->_shipmentsCollection; + } + + /** + * Getter for order tracking numbers collection per shipment + * + * @param Mage_Sales_Model_Order_Shipment $shipment + * @return array + */ + public function getShipmentTracks($shipment) + { + return $this->_tracks[$shipment->getId()]; + } + + /** + * Getter for shipment address by format + * + * @param Mage_Sales_Model_Order_Shipment $shipment + * @return string + */ + public function getShipmentAddressFormattedHtml($shipment) + { + $shippingAddress = $shipment->getShippingAddress(); + if(!($shippingAddress instanceof Mage_Sales_Model_Order_Address)) { + return ''; + } + return $shippingAddress->format('html'); + } + + /** + * Getter for billing address of order by format + * + * @param Mage_Sales_Model_Order $order + * @return string + */ + public function getBillingAddressFormattedHtml($order) + { + $billingAddress = $order->getBillingAddress(); + if(!($billingAddress instanceof Mage_Sales_Model_Order_Address)) { + return ''; + } + return $billingAddress->format('html'); + } + + /** + * Getter for billing address of order by format + * + * @param Mage_Sales_Model_Order_Shipment $shipment + * @return array + */ + public function getShipmentItems($shipment) + { + $res = array(); + foreach ($shipment->getItemsCollection() as $item) { + if (!$item->getOrderItem()->getParentItem()) { + $res[] = $item; + } + } + return $res; + } } diff --git a/app/code/core/Mage/Sales/Block/Order/Shipment/Items.php b/app/code/core/Mage/Sales/Block/Order/Shipment/Items.php index 5a2d28e930..0c0d5f136e 100644 --- a/app/code/core/Mage/Sales/Block/Order/Shipment/Items.php +++ b/app/code/core/Mage/Sales/Block/Order/Shipment/Items.php @@ -50,4 +50,22 @@ public function getPrintShipmentUrl($shipment){ public function getPrintAllShipmentsUrl($order){ return Mage::getUrl('*/*/printShipment', array('order_id' => $order->getId())); } + + /** + * Get html of shipment comments block + * + * @param Mage_Sales_Model_Order_Shipment $shipment + * @return string + */ + public function getCommentsHtml($shipment) + { + $html = ''; + $comments = $this->getChild('shipment_comments'); + if ($comments) { + $comments->setEntity($shipment) + ->setTitle(Mage::helper('sales')->__('About Your Shipment')); + $html = $comments->toHtml(); + } + return $html; + } } diff --git a/app/code/core/Mage/Sales/Block/Recurring/Profile/View.php b/app/code/core/Mage/Sales/Block/Recurring/Profile/View.php index 8850eaef06..85363f975a 100644 --- a/app/code/core/Mage/Sales/Block/Recurring/Profile/View.php +++ b/app/code/core/Mage/Sales/Block/Recurring/Profile/View.php @@ -125,6 +125,56 @@ public function prepareItemInfo() $this->_addInfo(array('label' => $label, 'value' => $value,)); } } + + $request = $this->_profile->getInfoValue($key, 'info_buyRequest'); + if (empty($request)) { + return; + } + + $request = unserialize($request); + if (empty($request['options'])) { + return; + } + + $options = Mage::getModel('catalog/product_option')->getCollection() + ->addIdsToFilter(array_keys($request['options'])) + ->addTitleToResult($this->_profile->getInfoValue($key, 'store_id')) + ->addValuesToResult(); + + $productMock = Mage::getModel('catalog/product'); + $quoteItemOptionMock = Mage::getModel('sales/quote_item_option'); + foreach ($options as $option) { + $quoteItemOptionMock->setId($option->getId()); + + $group = $option->groupFactory($option->getType()) + ->setOption($option) + ->setRequest(new Varien_Object($request)) + ->setProduct($productMock) + ->setUseQuotePath(true) + ->setQuoteItemOption($quoteItemOptionMock) + ->validateUserValue($request['options']); + + $skipHtmlEscaping = false; + if ('file' == $option->getType()) { + $skipHtmlEscaping = true; + + $downloadParams = array( + 'id' => $this->_profile->getId(), + 'option_id' => $option->getId(), + 'key' => $request['options'][$option->getId()]['secret_key'] + ); + $group->setCustomOptionDownloadUrl('sales/download/downloadProfileCustomOption') + ->setCustomOptionUrlParams($downloadParams); + } + + $optionValue = $group->prepareForCart(); + + $this->_addInfo(array( + 'label' => $option->getTitle(), + 'value' => $group->getFormattedOptionValue($optionValue), + 'skip_html_escaping' => $skipHtmlEscaping + )); + } } /** @@ -180,7 +230,8 @@ public function prepareAddressInfo() $this->_shouldRenderInfo = true; if ('shipping' == $this->getAddressType()) { - if ('1' == $this->_profile->getInfoValue('order_info', 'is_virtual')) { + if ('1' == $this->_profile->getInfoValue('order_item_info', 'is_virtual')) { + $this->getParentBlock()->unsetChild('sales.recurring.profile.view.shipping'); return; } $key = 'shipping_address_info'; @@ -258,6 +309,24 @@ public function prepareRelatedOrdersFrontendGrid() } } + /** + * Get rendered row value + * + * @param Varien_Object $row + * @return string + */ + public function renderRowValue(Varien_Object $row) + { + $value = $row->getValue(); + if (is_array($value)) { + $value = implode("\n", $value); + } + if (!$row->getSkipHtmlEscaping()) { + $value = $this->escapeHtml($value); + } + return nl2br($value); + } + /** * Prepare related orders collection * diff --git a/app/code/core/Mage/Sales/Model/Billing/Agreement.php b/app/code/core/Mage/Sales/Model/Billing/Agreement.php index 8522427879..ba73a38dbc 100644 --- a/app/code/core/Mage/Sales/Model/Billing/Agreement.php +++ b/app/code/core/Mage/Sales/Model/Billing/Agreement.php @@ -128,13 +128,14 @@ public function place() { $this->verifyToken(); - $this->getPaymentMethodInstance() + $paymentMethodInstance = $this->getPaymentMethodInstance() ->placeBillingAgreement($this); $this->setCustomerId($this->getCustomer()->getId()) ->setMethodCode($this->getMethodCode()) ->setReferenceId($this->getBillingAgreementId()) ->setStatus(self::STATUS_ACTIVE) + ->setAgreementLabel($paymentMethodInstance->getTitle()) ->save(); return $this; } diff --git a/app/code/core/Mage/Sales/Model/Entity/Quote/Address/Attribute/Frontend/Shipping.php b/app/code/core/Mage/Sales/Model/Entity/Quote/Address/Attribute/Frontend/Shipping.php index 66f0f29bbe..c9c4f18d5a 100644 --- a/app/code/core/Mage/Sales/Model/Entity/Quote/Address/Attribute/Frontend/Shipping.php +++ b/app/code/core/Mage/Sales/Model/Entity/Quote/Address/Attribute/Frontend/Shipping.php @@ -31,11 +31,15 @@ class Mage_Sales_Model_Entity_Quote_Address_Attribute_Frontend_Shipping public function fetchTotals(Mage_Sales_Model_Quote_Address $address) { $amount = $address->getShippingAmount(); - if ($amount!=0) { + if ($amount != 0) { + $title = Mage::helper('sales')->__('Shipping & Handling'); + if ($address->getShippingDescription()) { + $title .= ' (' . $address->getShippingDescription() . ')'; + } $address->addTotal(array( - 'code'=>'shipping', - 'title'=>Mage::helper('sales')->__('Shipping & Handling').' ('.$address->getShippingDescription().')', - 'value'=>$address->getShippingAmount() + 'code' => 'shipping', + 'title' => $title, + 'value' => $address->getShippingAmount() )); } return $this; diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Collection/Abstract.php b/app/code/core/Mage/Sales/Model/Mysql4/Collection/Abstract.php index 8d160b7a15..8f11b1a116 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Collection/Abstract.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Collection/Abstract.php @@ -30,9 +30,6 @@ */ abstract class Mage_Sales_Model_Mysql4_Collection_Abstract extends Mage_Core_Model_Mysql4_Collection_Abstract { - protected $_eventPrefix = ''; - protected $_eventObject = ''; - /** * Check if $attribute is Mage_Eav_Model_Entity_Attribute and convert to string field name * diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Address.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Address.php index 0ff192529c..b9631ac111 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Order/Address.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Address.php @@ -30,11 +30,41 @@ */ class Mage_Sales_Model_Mysql4_Order_Address extends Mage_Sales_Model_Mysql4_Order_Abstract { + /** + * Event prefix + * + * @var string + */ protected $_eventPrefix = 'sales_order_address_resource'; + /** + * Resource initialization + */ protected function _construct() { $this->_init('sales/order_address', 'entity_id'); } + /** + * Return configuration for all attributes + * + * @return array + */ + public function getAllAttributes() + { + $attributes = array( + 'city' => Mage::helper('sales')->__('City'), + 'company' => Mage::helper('sales')->__('Company'), + 'country_id' => Mage::helper('sales')->__('Country'), + 'email' => Mage::helper('sales')->__('Email'), + 'firstname' => Mage::helper('sales')->__('First Name'), + 'lastname' => Mage::helper('sales')->__('Last Name'), + 'region_id' => Mage::helper('sales')->__('State/Province'), + 'street' => Mage::helper('sales')->__('Street Address'), + 'telephone' => Mage::helper('sales')->__('Telephone'), + 'postcode' => Mage::helper('sales')->__('Zip/Postal Code') + ); + asort($attributes); + return $attributes; + } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Address/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Address/Collection.php index 69874bf858..54400c2168 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Order/Address/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Address/Collection.php @@ -37,4 +37,20 @@ protected function _construct() { $this->_init('sales/order_address'); } + + /** + * Redeclare after load method for dispatch event + * + * @return Mage_Sales_Model_Mysql4_Order_Address_Collection + */ + protected function _afterLoad() + { + parent::_afterLoad(); + + Mage::dispatchEvent($this->_eventPrefix.'_load_after', array( + $this->_eventObject => $this + )); + + return $this; + } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Collection.php index 3408fed3fa..74d0c9bc04 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Order/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Collection.php @@ -79,7 +79,7 @@ public function getSelectCountSql() */ protected function _getAllIdsSelect($limit = null, $offset = null) { - $idsSelect = parent::getAllIds($limit, $offset); + $idsSelect = parent::_getAllIdsSelect($limit, $offset); $idsSelect->resetJoinLeft(); return $idsSelect; } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Comment/Collection/Abstract.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Comment/Collection/Abstract.php new file mode 100644 index 0000000000..fd780398af --- /dev/null +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Comment/Collection/Abstract.php @@ -0,0 +1,68 @@ +getId(); + } + return $this->addFieldToFilter('parent_id', $parent); + } + + /** + * Adds filter to get only 'visible on front' comments + * + * @param int $flag + * @return Mage_Sales_Model_Mysql4_Order_Comment_Collection_Abstract + */ + public function addVisibleOnFrontFilter($flag = 1) + { + return $this->addFieldToFilter('is_visible_on_front', $flag); + } + + /** + * Set created_at sort order + * + * @param string $direction + * @return Mage_Sales_Model_Mysql4_Order_Comment_Collection_Abstract + */ + public function setCreatedAtOrder($direction='desc') + { + return $this->setOrder('created_at', $direction); + } +} diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Creditmemo/Comment/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Creditmemo/Comment/Collection.php index bb52b27b61..89933e70a1 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Order/Creditmemo/Comment/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Creditmemo/Comment/Collection.php @@ -28,13 +28,26 @@ * Flat sales order creditmemo comments collection * */ -class Mage_Sales_Model_Mysql4_Order_Creditmemo_Comment_Collection extends Mage_Sales_Model_Mysql4_Collection_Abstract +class Mage_Sales_Model_Mysql4_Order_Creditmemo_Comment_Collection extends Mage_Sales_Model_Mysql4_Order_Comment_Collection_Abstract { + /* + * @var string + */ protected $_eventPrefix = 'sales_order_creditmemo_comment_collection'; + + /* + * @var string + */ protected $_eventObject = 'order_creditmemo_comment_collection'; + /* + * Inits creditmemo comment collection + * + * @return void + */ protected function _construct() { + parent::_construct(); $this->_init('sales/order_creditmemo_comment'); } @@ -46,19 +59,6 @@ protected function _construct() */ public function setCreditmemoFilter($creditmemoId) { - $this->addFieldToFilter('parent_id', $creditmemoId); - return $this; - } - - /** - * Set created_at sort order - * - * @param string $direction - * @return Mage_Sales_Model_Mysql4_Order_Creditmemo_Comment_Collection - */ - public function setCreatedAtOrder($direction='desc') - { - $this->setOrder('created_at', $direction); - return $this; + return $this->setParentFilter($creditmemoId); } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Grid/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Grid/Collection.php index b171fb0dab..e0fd7af9f3 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Order/Grid/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Grid/Collection.php @@ -38,4 +38,26 @@ protected function _construct() parent::_construct(); $this->setMainTable('sales/order_grid'); } + + /** + * Get SQL for get record count + * + * @return Varien_Db_Select + */ + public function getSelectCountSql() + { + $this->_renderFilters(); + + $unionSelect = clone $this->getSelect(); + + $unionSelect->reset(Zend_Db_Select::ORDER); + $unionSelect->reset(Zend_Db_Select::LIMIT_COUNT); + $unionSelect->reset(Zend_Db_Select::LIMIT_OFFSET); + + $countSelect = clone $this->getSelect(); + $countSelect->reset(); + $countSelect->from(array('a' => $unionSelect), 'COUNT(*)'); + + return $countSelect; + } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Invoice/Comment/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Invoice/Comment/Collection.php index d9d640c5d4..76e32f0d33 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Order/Invoice/Comment/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Invoice/Comment/Collection.php @@ -28,13 +28,26 @@ * Flat sales order invoice comment collection * */ -class Mage_Sales_Model_Mysql4_Order_Invoice_Comment_Collection extends Mage_Sales_Model_Mysql4_Collection_Abstract +class Mage_Sales_Model_Mysql4_Order_Invoice_Comment_Collection extends Mage_Sales_Model_Mysql4_Order_Comment_Collection_Abstract { + /* + * @var string + */ protected $_eventPrefix = 'sales_order_invoice_comment_collection'; + + /* + * @var string + */ protected $_eventObject = 'order_invoice_comment_collection'; + /* + * Inits invoice comment collection + * + * @return void + */ protected function _construct() { + parent::_construct(); $this->_init('sales/order_invoice_comment'); } @@ -46,19 +59,6 @@ protected function _construct() */ public function setInvoiceFilter($invoiceId) { - $this->addFieldToFilter('parent_id', $invoiceId); - return $this; - } - - /** - * Set created_at sort order - * - * @param string $direction - * @return Mage_Sales_Model_Mysql4_Order_Invoice_Comment_Collection - */ - public function setCreatedAtOrder($direction='desc') - { - $this->setOrder('created_at', $direction); - return $this; + return $this->setParentFilter($invoiceId); } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Order/Shipment/Comment/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Order/Shipment/Comment/Collection.php index c6cb9fd97a..abe6b71177 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Order/Shipment/Comment/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Order/Shipment/Comment/Collection.php @@ -28,13 +28,26 @@ * Flat sales order shipment comments collection * */ -class Mage_Sales_Model_Mysql4_Order_Shipment_Comment_Collection extends Mage_Sales_Model_Mysql4_Collection_Abstract +class Mage_Sales_Model_Mysql4_Order_Shipment_Comment_Collection extends Mage_Sales_Model_Mysql4_Order_Comment_Collection_Abstract { + /* + * @var string + */ protected $_eventPrefix = 'sales_order_shipment_comment_collection'; + + /* + * @var string + */ protected $_eventObject = 'order_shipment_comment_collection'; + /* + * Inits shipment comment collection + * + * @return void + */ protected function _construct() { + parent::_construct(); $this->_init('sales/order_shipment_comment'); } @@ -46,19 +59,6 @@ protected function _construct() */ public function setShipmentFilter($shipmentId) { - $this->addFieldToFilter('parent_id', $shipmentId); - return $this; - } - - /** - * Set created_at sort order - * - * @param string $direction - * @return Mage_Sales_Model_Mysql4_Order_Shipment_Comment_Collection - */ - public function setCreatedAtOrder($direction='desc') - { - $this->setOrder('created_at', $direction); - return $this; + return $this->setParentFilter($shipmentId); } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Attribute/Frontend/Shipping.php b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Attribute/Frontend/Shipping.php index 13ab8015f9..19f4aadc4e 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Attribute/Frontend/Shipping.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Attribute/Frontend/Shipping.php @@ -31,11 +31,15 @@ class Mage_Sales_Model_Mysql4_Quote_Address_Attribute_Frontend_Shipping public function fetchTotals(Mage_Sales_Model_Quote_Address $address) { $amount = $address->getShippingAmount(); - if ($amount!=0) { + if ($amount != 0) { + $title = Mage::helper('sales')->__('Shipping & Handling'); + if ($address->getShippingDescription()) { + $title .= ' (' . $address->getShippingDescription() . ')'; + } $address->addTotal(array( - 'code'=>'shipping', - 'title'=>Mage::helper('sales')->__('Shipping & Handling').' ('.$address->getShippingDescription().')', - 'value'=>$address->getShippingAmount() + 'code' => 'shipping', + 'title' => $title, + 'value' => $address->getShippingAmount() )); } return $this; diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Collection.php index dca47530e5..a79ef8feb2 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Address/Collection.php @@ -35,6 +35,9 @@ class Mage_Sales_Model_Mysql4_Quote_Address_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract { + protected $_eventPrefix = 'sales_quote_address_collection'; + protected $_eventObject = 'quote_address_collection'; + protected function _construct() { $this->_init('sales/quote_address'); @@ -52,4 +55,20 @@ public function setQuoteFilter($quoteId) $this->addFieldToFilter('quote_id', $quoteId ? $quoteId : array('null' => 1)); return $this; } + + /** + * Redeclare after load method for dispatch event + * + * @return Mage_Sales_Model_Mysql4_Quote_Address_Collection + */ + protected function _afterLoad() + { + parent::_afterLoad(); + + Mage::dispatchEvent($this->_eventPrefix.'_load_after', array( + $this->_eventObject => $this + )); + + return $this; + } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Collection.php index ebbaf24048..246d78c399 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Collection.php @@ -116,6 +116,7 @@ public function resetJoinQuotes($quotesTableName, $productId = null) protected function _afterLoad() { parent::_afterLoad(); + /** * Assign parent items */ @@ -131,8 +132,10 @@ protected function _afterLoad() /** * Assign options and products */ - $this->_assignOptions() - ->_assignProducts(); + $this->_assignOptions(); + $this->_assignProducts(); + $this->resetItemsDataChanged(); + return $this; } @@ -151,6 +154,7 @@ protected function _assignOptions() } $productIds = $optionCollection->getProductIds(); $this->_productIds = array_merge($this->_productIds, $productIds); + return $this; } @@ -174,16 +178,24 @@ protected function _assignProducts() ->addAttributeToSelect(Mage::getSingleton('sales/quote_config')->getProductAttributes()) ->addOptionsToResult() ->addStoreFilter() - ->addUrlRewrite(); + ->addUrlRewrite() + ->addTierPriceData(); - Mage::dispatchEvent('sales_quote_item_collection_products_after_load', array('product_collection'=>$productCollection)); + Mage::dispatchEvent('prepare_catalog_product_collection_prices', array( + 'collection' => $productCollection, + 'store_id' => $this->getStoreId(), + )); + Mage::dispatchEvent('sales_quote_item_collection_products_after_load', array( + 'product_collection' => $productCollection + )); $recollectQuote = false; foreach ($this as $item) { - - if ($product = $productCollection->getItemById($item->getProductId())) { + $product = $productCollection->getItemById($item->getProductId()); + if ($product) { $product->setCustomOptions(array()); - + $qtyOptions = array(); + $optionProductIds = array(); foreach ($item->getOptions() as $option) { /** * Call type specified logic for product associated with quote item @@ -193,10 +205,24 @@ protected function _assignProducts() $option, $product ); + + if (is_object($option->getProduct()) && $option->getProduct()->getId() != $product->getId()) { + $optionProductIds[$option->getProduct()->getId()] = $option->getProduct()->getId(); + } } + + if ($optionProductIds) { + foreach ($optionProductIds as $optionProductId) { + $qtyOption = $item->getOptionByCode('product_qty_' . $optionProductId); + if ($qtyOption) { + $qtyOptions[$optionProductId] = $qtyOption; + } + } + } + $item->setQtyOptions($qtyOptions); + $item->setProduct($product); - } - else { + } else { $item->isDeleted(true); $recollectQuote = true; } @@ -207,6 +233,7 @@ protected function _assignProducts() $this->_quote->collectTotals(); } Varien_Profiler::stop('QUOTE:'.__METHOD__); + return $this; } } diff --git a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Option/Collection.php b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Option/Collection.php index a134f98b2a..94d799061a 100644 --- a/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Option/Collection.php +++ b/app/code/core/Mage/Sales/Model/Mysql4/Quote/Item/Option/Collection.php @@ -33,11 +33,58 @@ */ class Mage_Sales_Model_Mysql4_Quote_Item_Option_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract { + /** + * Array of option ids grouped by item id + * + * @var array + */ + protected $_optionsByItem = array(); + + /** + * Array of option ids grouped by product id + * + * @var array + */ + protected $_optionsByProduct = array(); + + /** + * Define resource model for collection + * + * @return void + */ protected function _construct() { $this->_init('sales/quote_item_option'); } + /** + * Fill array of options by item and product + * + * @return Mage_Sales_Model_Mysql4_Quote_Item_Option_Collection + */ + protected function _afterLoad() + { + parent::_afterLoad(); + + foreach ($this as $option) { + $optionId = $option->getId(); + $itemId = $option->getItemId(); + $productId = $option->getProductId(); + if (isset($this->_optionsByItem[$itemId])) { + $this->_optionsByItem[$itemId][] = $optionId; + } else { + $this->_optionsByItem[$itemId] = array($optionId); + } + if (isset($this->_optionsByProduct[$productId])) { + $this->_optionsByProduct[$productId][] = $optionId; + } else { + $this->_optionsByProduct[$productId] = array($optionId); + } + } + + return $this; + } + /** * Apply quote item(s) filter to collection * @@ -50,13 +97,14 @@ public function addItemFilter($item) $this->_totalRecords = 0; $this->_setIsLoaded(true); //$this->addFieldToFilter('item_id', ''); - } elseif (is_array($item)) { + } else if (is_array($item)) { $this->addFieldToFilter('item_id', array('in'=>$item)); - } elseif ($item instanceof Mage_Sales_Model_Quote_Item) { + } else if ($item instanceof Mage_Sales_Model_Quote_Item) { $this->addFieldToFilter('item_id', $item->getId()); } else { $this->addFieldToFilter('item_id', $item); } + return $this; } @@ -67,11 +115,9 @@ public function addItemFilter($item) */ public function getProductIds() { - $ids = array(); - foreach ($this as $item) { - $ids[] = $item->getProductId(); - } - return array_unique($ids); + $this->load(); + + return array_keys($this->_optionsByProduct); } /** @@ -84,17 +130,19 @@ public function getOptionsByItem($item) { if ($item instanceof Mage_Sales_Model_Quote_Item) { $itemId = $item->getId(); - } - else { + } else { $itemId = $item; } + $this->load(); + $options = array(); - foreach ($this as $option) { - if ($option->getItemId() == $itemId) { - $options[] = $option; + if (isset($this->_optionsByItem[$itemId])) { + foreach ($this->_optionsByItem[$itemId] as $optionId) { + $options[] = $this->_items[$optionId]; } } + return $options; } @@ -108,17 +156,19 @@ public function getOptionsByProduct($product) { if ($product instanceof Mage_Catalog_Model_Product) { $productId = $product->getId(); - } - else { + } else { $productId = $product; } + $this->load(); + $options = array(); - foreach ($this as $option) { - if ($option->getProductId() == $productId) { - $options[] = $option; + if (isset($this->_optionsByProduct[$productId])) { + foreach ($this->_optionsByProduct[$productId] as $optionId) { + $options[] = $this->_items[$optionId]; } } + return $options; } } diff --git a/app/code/core/Mage/Sales/Model/Order.php b/app/code/core/Mage/Sales/Model/Order.php index 9901456a43..5b12677b8a 100644 --- a/app/code/core/Mage/Sales/Model/Order.php +++ b/app/code/core/Mage/Sales/Model/Order.php @@ -372,7 +372,7 @@ public function canShip() return false; } - if ($this->getIsVirtual()) { + if ($this->getIsVirtual() || $this->isCanceled()) { return false; } @@ -1600,7 +1600,7 @@ public function addRelatedObject(Mage_Core_Model_Abstract $object) */ public function getCreatedAtFormated($format) { - return Mage::helper('core')->formatDate($this->getCreatedAtStoreDate(), $format); + return Mage::helper('core')->formatDate($this->getCreatedAtStoreDate(), $format, true); } public function getEmailCustomerNote() @@ -1680,7 +1680,7 @@ protected function _checkState() && !$this->canUnhold() && !$this->canInvoice() && !$this->canShip()) { - if ($this->canCreditmemo()) { + if (0 == $this->getBaseGrandTotal() || $this->canCreditmemo()) { if ($this->getState() !== self::STATE_COMPLETE) { $this->_setState(self::STATE_COMPLETE, true, '', $userNotification); } diff --git a/app/code/core/Mage/Sales/Model/Order/Api.php b/app/code/core/Mage/Sales/Model/Order/Api.php index 28a5f0c4fb..3afdf24f4c 100644 --- a/app/code/core/Mage/Sales/Model/Order/Api.php +++ b/app/code/core/Mage/Sales/Model/Order/Api.php @@ -133,6 +133,12 @@ public function info($orderIncrementId) { $order = $this->_initOrder($orderIncrementId); + if ($order->getGiftMessageId() > 0) { + $order->setGiftMessage( + Mage::getSingleton('giftmessage/message')->load($order->getGiftMessageId())->getMessage() + ); + } + $result = $this->_getAttributes($order, 'order'); $result['shipping_address'] = $this->_getAttributes($order->getShippingAddress(), 'order_address'); @@ -140,6 +146,12 @@ public function info($orderIncrementId) $result['items'] = array(); foreach ($order->getAllItems() as $item) { + if ($item->getGiftMessageId() > 0) { + $item->setGiftMessage( + Mage::getSingleton('giftmessage/message')->load($item->getGiftMessageId())->getMessage() + ); + } + $result['items'][] = $this->_getAttributes($item, 'order_item'); } diff --git a/app/code/core/Mage/Sales/Model/Order/Api/V2.php b/app/code/core/Mage/Sales/Model/Order/Api/V2.php index e8a7c33416..86ba322cc5 100644 --- a/app/code/core/Mage/Sales/Model/Order/Api/V2.php +++ b/app/code/core/Mage/Sales/Model/Order/Api/V2.php @@ -80,7 +80,7 @@ public function items($filters = null) if (isset($filters->complex_filter)) { foreach ($filters->complex_filter as $_filter) { $_value = $_filter->value; - $preparedFilters[$_filter->key] = array( + $preparedFilters[][$_filter->key] = array( $_value->key => $_value->value ); } @@ -88,12 +88,14 @@ public function items($filters = null) if (!empty($preparedFilters)) { try { - foreach ($preparedFilters as $field => $value) { - if (isset($this->_attributesMap['order'][$field])) { - $field = $this->_attributesMap['order'][$field]; - } + foreach ($preparedFilters as $preparedFilter) { + foreach ($preparedFilter as $field => $value) { + if (isset($this->_attributesMap['order'][$field])) { + $field = $this->_attributesMap['order'][$field]; + } - $collection->addFieldToFilter($field, $value); + $collection->addFieldToFilter($field, $value); + } } } catch (Mage_Core_Exception $e) { $this->_fault('filters_invalid', $e->getMessage()); diff --git a/app/code/core/Mage/Sales/Model/Order/Creditmemo.php b/app/code/core/Mage/Sales/Model/Order/Creditmemo.php index 2d670f02fa..8e78f4dcf0 100644 --- a/app/code/core/Mage/Sales/Model/Order/Creditmemo.php +++ b/app/code/core/Mage/Sales/Model/Order/Creditmemo.php @@ -487,12 +487,22 @@ public function setAdjustmentNegative($amount) return $this; } - public function addComment($comment, $notify=false) + /** + * Adds comment to credit memo with additional possibility to send it to customer via email + * and show it in customer account + * + * @param bool $notify + * @param bool $visibleOnFront + * + * @return Mage_Sales_Model_Order_Creditmemo + */ + public function addComment($comment, $notify=false, $visibleOnFront=false) { if (!($comment instanceof Mage_Sales_Model_Order_Creditmemo_Comment)) { $comment = Mage::getModel('sales/order_creditmemo_comment') ->setComment($comment) - ->setIsCustomerNotified($notify); + ->setIsCustomerNotified($notify) + ->setIsVisibleOnFront($visibleOnFront); } $comment->setCreditmemo($this) ->setParentId($this->getId()) diff --git a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Item.php b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Item.php index 6331ade8e8..3463643b64 100644 --- a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Item.php +++ b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Item.php @@ -130,7 +130,15 @@ public function setQty($qty) public function register() { $this->getOrderItem()->setQtyRefunded( - $this->getOrderItem()->getQtyRefunded()+$this->getQty() + $this->getOrderItem()->getQtyRefunded() + $this->getQty() + ); + $this->getOrderItem()->setTaxRefunded( + $this->getOrderItem()->getTaxRefunded() + + $this->getOrderItem()->getBaseTaxAmount() * $this->getQty() / $this->getOrderItem()->getQtyOrdered() + ); + $this->getOrderItem()->setHiddenTaxRefunded( + $this->getOrderItem()->getHiddenTaxRefunded() + + $this->getOrderItem()->getHiddenTaxAmount() * $this->getQty() / $this->getOrderItem()->getQtyOrdered() ); return $this; } @@ -140,6 +148,14 @@ public function cancel() $this->getOrderItem()->setQtyRefunded( $this->getOrderItem()->getQtyRefunded()-$this->getQty() ); + $this->getOrderItem()->setTaxRefunded( + $this->getOrderItem()->getTaxRefunded() + - $this->getOrderItem()->getBaseTaxAmount() * $this->getQty() / $this->getOrderItem()->getQtyOrdered() + ); + $this->getOrderItem()->setHiddenTaxRefunded( + $this->getOrderItem()->getHiddenTaxRefunded() + - $this->getOrderItem()->getHiddenTaxAmount() * $this->getQty() / $this->getOrderItem()->getQtyOrdered() + ); return $this; } diff --git a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Shipping.php b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Shipping.php index f3e9db96a3..bc9d55226b 100644 --- a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Shipping.php +++ b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Shipping.php @@ -58,14 +58,29 @@ public function collect(Mage_Sales_Model_Order_Creditmemo $creditmemo) $baseShippingInclTax= $baseShippingAmount; $baseShippingAmount = Mage::app()->getStore()->roundPrice($baseShipping*$part); } - if ($baseShippingAmount<= $baseAllowedAmount) { - if ($baseShipping != 0) { - $shipping = $shipping*$baseShippingAmount/$baseShipping; + /* + * Rounded allowed shipping refund amount is the highest acceptable shipping refund amount. + * Shipping refund amount shouldn't cause errors, if it doesn't exceed that limit. + * Note: ($x < $y + 0.0001) means ($x <= $y) for floats + */ + if ($baseShippingAmount < Mage::app()->getStore()->roundPrice($baseAllowedAmount) + 0.0001) { + /* + * Shipping refund amount should be equated to allowed refund amount, + * if it exceeds that limit. + * Note: ($x > $y - 0.0001) means ($x >= $y) for floats + */ + if ($baseShippingAmount > $baseAllowedAmount - 0.0001) { + $shipping = $allowedAmount; + $baseShipping = $baseAllowedAmount; + } else { + if ($baseShipping != 0) { + $shipping = $shipping * $baseShippingAmount / $baseShipping; + } + $shipping = Mage::app()->getStore()->roundPrice($shipping); + $baseShipping = $baseShippingAmount; } - $shipping = Mage::app()->getStore()->roundPrice($shipping); - $baseShipping = $baseShippingAmount; } else { - $baseAllowedAmount = $order->formatBasePrice($baseAllowedAmount); + $baseAllowedAmount = $order->getBaseCurrency()->format($baseAllowedAmount,null,false); Mage::throwException( Mage::helper('sales')->__('Maximum shipping amount allowed to refund is: %s', $baseAllowedAmount) ); diff --git a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Tax.php index a25bd259a9..4e91365868 100644 --- a/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/core/Mage/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -51,11 +51,17 @@ public function collect(Mage_Sales_Model_Order_Creditmemo $creditmemo) /** * Check item tax amount */ + + if ($item->isLast()) { - $tax = $orderItemTax - $item->getOrderItem()->getTaxRefunded(); - $baseTax = $baseOrderItemTax - $item->getOrderItem()->getTaxRefunded(); - $hiddenTax = $orderItem->getHiddenTaxAmount() - $orderItem->getHiddenTaxRefunded(); - $baseHiddenTax = $orderItem->getBaseHiddenTaxAmount() - $orderItem->getBaseHiddenTaxRefunded(); + $tax = $orderItemTax - $item->getOrderItem()->getTaxRefunded() + - $item->getOrderItem()->getTaxCanceled(); + $baseTax = $baseOrderItemTax - $item->getOrderItem()->getTaxRefunded() + - $item->getOrderItem()->getTaxCanceled(); + $hiddenTax = $orderItem->getHiddenTaxAmount() - $orderItem->getHiddenTaxRefunded() + - $item->getOrderItem()->getHiddenTaxCanceled(); + $baseHiddenTax = $orderItem->getBaseHiddenTaxAmount() - $orderItem->getBaseHiddenTaxRefunded() + - $item->getOrderItem()->getHiddenTaxCanceled(); } else { @@ -69,12 +75,12 @@ public function collect(Mage_Sales_Model_Order_Creditmemo $creditmemo) $hiddenTax = $creditmemo->getStore()->roundPrice($hiddenTax); $baseHiddenTax = $creditmemo->getStore()->roundPrice($baseHiddenTax); } - $item->setTaxAmount($tax); $item->setBaseTaxAmount($baseTax); $item->setHiddenTaxAmount($hiddenTax); $item->setBaseHiddenTaxAmount($baseHiddenTax); + $totalTax += $tax; $baseTotalTax += $baseTax; $totalHiddenTax += $hiddenTax; diff --git a/app/code/core/Mage/Sales/Model/Order/Invoice.php b/app/code/core/Mage/Sales/Model/Order/Invoice.php index d1ecdf2cfb..a2648e790e 100644 --- a/app/code/core/Mage/Sales/Model/Order/Invoice.php +++ b/app/code/core/Mage/Sales/Model/Order/Invoice.php @@ -543,12 +543,22 @@ public function isLast() return true; } - public function addComment($comment, $notify=false) + /** + * Adds comment to invoice with additional possibility to send it to customer via email + * and show it in customer account + * + * @param bool $notify + * @param bool $visibleOnFront + * + * @return Mage_Sales_Model_Order_Invoice + */ + public function addComment($comment, $notify=false, $visibleOnFront=false) { if (!($comment instanceof Mage_Sales_Model_Order_Invoice_Comment)) { $comment = Mage::getModel('sales/order_invoice_comment') ->setComment($comment) - ->setIsCustomerNotified($notify); + ->setIsCustomerNotified($notify) + ->setIsVisibleOnFront($visibleOnFront); } $comment->setInvoice($this) ->setStoreId($this->getStoreId()) diff --git a/app/code/core/Mage/Sales/Model/Order/Item.php b/app/code/core/Mage/Sales/Model/Order/Item.php index 51b405bcf3..5330fe4b67 100644 --- a/app/code/core/Mage/Sales/Model/Order/Item.php +++ b/app/code/core/Mage/Sales/Model/Order/Item.php @@ -236,6 +236,9 @@ public function getOrder() public function getStatusId() { $backordered = (float)$this->getQtyBackordered(); + if (!$backordered && $this->getHasChildren()) { + $backordered = (float)$this->_getQtyChildrenBackordered(); + } $canceled = (float)$this->getQtyCanceled(); $invoiced = (float)$this->getQtyInvoiced(); $ordered = (float)$this->getQtyOrdered(); @@ -274,6 +277,21 @@ public function getStatusId() return self::STATUS_MIXED; } + /** + * Retrieve backordered qty of children items + * + * @return float|null + */ + protected function _getQtyChildrenBackordered() + { + $backordered = null; + foreach ($this->_children as $childItem) { + $backordered += (float)$childItem->getQtyBackordered(); + } + + return $backordered; + } + /** * Retrieve status * @@ -310,6 +328,8 @@ public function cancel() if ($this->getStatusId() !== self::STATUS_CANCELED) { Mage::dispatchEvent('sales_order_item_cancel', array('item'=>$this)); $this->setQtyCanceled($this->getQtyToCancel()); + $this->setTaxCanceled($this->getTaxCanceled() + $this->getBaseTaxAmount() * $this->getQtyCanceled() / $this->getQtyOrdered()); + $this->setHiddenTaxCanceled($this->getHiddenTaxCanceled() + $this->getHiddenTaxAmount() * $this->getQtyCanceled() / $this->getQtyOrdered()); } return $this; } diff --git a/app/code/core/Mage/Sales/Model/Order/Payment.php b/app/code/core/Mage/Sales/Model/Order/Payment.php index 3ef6df424e..42ac4e3e7c 100644 --- a/app/code/core/Mage/Sales/Model/Order/Payment.php +++ b/app/code/core/Mage/Sales/Model/Order/Payment.php @@ -562,23 +562,39 @@ public function registerRefundNotification($amount) return $this; } $order = $this->getOrder(); + $invoice = $this->_getInvoiceForTransactionId($this->getParentTransactionId()); - // create an offline creditmemo (from order), if the entire grand total of order is covered by this refund - $creditmemo = null; - if ($amount == $order->getBaseGrandTotal()) { - /* - $creditmemo = $order->prepareCreditmemo()->register()->refund(); - $this->_updateTotals(array( - 'amount_refunded' => $creditmemo->getGrandTotal(), - 'shipping_refunded' => $creditmemo->getShippingRefunded(), - 'base_shipping_refunded' => $creditmemo->getBaseShippingRefunded() - )); - $order->addRelatedObject($creditmemo); - $this->setCreatedCreditmemo($creditmemo); - */ + $baseGrandTotal = ($invoice) ? $invoice->getBaseGrandTotal() : $order->getBaseGrandTotal(); + $amountRefundLeft = $baseGrandTotal - $order->getBaseTotalRefunded(); + if ($amountRefundLeft < $amount) { + $amount = $amountRefundLeft; } - $this->_updateTotals(array('base_amount_refunded_online' => $amount)); + if ($order->getBaseTotalRefunded() > 0) { + $adjustment = array('adjustment_positive' => $amount); + } else { + $adjustment = array('adjustment_negative' => $baseGrandTotal - $amount); + } + + $serviceModel = Mage::getModel('sales/service_order', $order); + if ($invoice) { + $creditmemo = $serviceModel->prepareInvoiceCreditmemo($invoice, $adjustment); + } else { + $creditmemo = $serviceModel->prepareCreditmemo($adjustment); + } + + $creditmemo->setPaymentRefundDisallowed(true) + ->setAutomaticallyCreated(true) + ->register() + ->addComment(Mage::helper('sales')->__('Credit memo has been created automatically')) + ->save(); + + $this->_updateTotals(array( + 'amount_refunded' => $creditmemo->getGrandTotal(), + 'base_amount_refunded_online' => $amount + )); + + $this->setCreatedCreditmemo($creditmemo); // update transactions and order state $transaction = $this->_addTransaction(Mage_Sales_Model_Order_Payment_Transaction::TYPE_REFUND, $creditmemo); $message = $this->_prependMessage( @@ -734,7 +750,7 @@ public function registerPaymentReviewAction($action, $isOnline) $message = Mage::helper('sales')->__('Registered update about approved payment.'); } elseif ($this->getIsTransactionDenied()) { $result = false; - $message = Mage::helper('sales')->__('Registered update about approved payment.'); + $message = Mage::helper('sales')->__('Registered update about denied payment.'); } else { $result = -1; $message = Mage::helper('sales')->__('There is no update for the payment.'); diff --git a/app/code/core/Mage/Sales/Model/Order/Pdf/Abstract.php b/app/code/core/Mage/Sales/Model/Order/Pdf/Abstract.php index 438cb70be6..d7c4891a86 100644 --- a/app/code/core/Mage/Sales/Model/Order/Pdf/Abstract.php +++ b/app/code/core/Mage/Sales/Model/Order/Pdf/Abstract.php @@ -180,8 +180,16 @@ protected function _formatAddress($address) return $return; } - protected function insertOrder(&$page, $order, $putOrderId = true) + protected function insertOrder(&$page, $obj, $putOrderId = true) { + if ($obj instanceof Mage_Sales_Model_Order) { + $shipment = null; + $order = $obj; + } elseif ($obj instanceof Mage_Sales_Model_Order_Shipment) { + $shipment = $obj; + $order = $shipment->getOrder(); + } + /* @var $order Mage_Sales_Model_Order */ $page->setFillColor(new Zend_Pdf_Color_GrayScale(0.5)); @@ -313,7 +321,11 @@ protected function insertOrder(&$page, $order, $putOrderId = true) $page->drawText($totalShippingChargesText, 285, $yShipments-7, 'UTF-8'); $yShipments -=10; - $tracks = $order->getTracksCollection(); + + $tracks = array(); + if ($shipment) { + $tracks = $shipment->getAllTracks(); + } if (count($tracks)) { $page->setFillColor(new Zend_Pdf_Color_Rgb(0.93, 0.92, 0.92)); $page->setLineWidth(0.5); @@ -329,7 +341,7 @@ protected function insertOrder(&$page, $order, $putOrderId = true) $yShipments -=17; $this->_setFontRegular($page, 6); - foreach ($order->getTracksCollection() as $track) { + foreach ($tracks as $track) { $CarrierCode = $track->getCarrierCode(); if ($CarrierCode!='custom') @@ -685,10 +697,10 @@ public function drawLineBlocks(Zend_Pdf_Page $page, array $draw, array $pageSett foreach ($lines as $line) { $maxHeight = 0; foreach ($line as $column) { - $fontSize = empty($column['font_size']) ? 7 : $column['font_size']; + $fontSize = empty($column['font_size']) ? 7 : $column['font_size']; if (!empty($column['font_file'])) { $font = Zend_Pdf_Font::fontWithPath($column['font_file']); - $page->setFont($font); + $page->setFont($font, $fontSize); } else { $fontStyle = empty($column['font']) ? 'regular' : $column['font']; diff --git a/app/code/core/Mage/Sales/Model/Order/Pdf/Creditmemo.php b/app/code/core/Mage/Sales/Model/Order/Pdf/Creditmemo.php index ea04efb33a..c1187a4e80 100644 --- a/app/code/core/Mage/Sales/Model/Order/Pdf/Creditmemo.php +++ b/app/code/core/Mage/Sales/Model/Order/Pdf/Creditmemo.php @@ -47,6 +47,7 @@ public function getPdf($creditmemos = array()) foreach ($creditmemos as $creditmemo) { if ($creditmemo->getStoreId()) { Mage::app()->getLocale()->emulate($creditmemo->getStoreId()); + Mage::app()->setCurrentStore($creditmemo->getStoreId()); } $page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); $pdf->pages[] = $page; diff --git a/app/code/core/Mage/Sales/Model/Order/Pdf/Invoice.php b/app/code/core/Mage/Sales/Model/Order/Pdf/Invoice.php index f4f0d5a01b..5e49add060 100644 --- a/app/code/core/Mage/Sales/Model/Order/Pdf/Invoice.php +++ b/app/code/core/Mage/Sales/Model/Order/Pdf/Invoice.php @@ -47,6 +47,7 @@ public function getPdf($invoices = array()) foreach ($invoices as $invoice) { if ($invoice->getStoreId()) { Mage::app()->getLocale()->emulate($invoice->getStoreId()); + Mage::app()->setCurrentStore($invoice->getStoreId()); } $page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); $pdf->pages[] = $page; diff --git a/app/code/core/Mage/Sales/Model/Order/Pdf/Shipment.php b/app/code/core/Mage/Sales/Model/Order/Pdf/Shipment.php index 62395b6b41..62763e3c89 100644 --- a/app/code/core/Mage/Sales/Model/Order/Pdf/Shipment.php +++ b/app/code/core/Mage/Sales/Model/Order/Pdf/Shipment.php @@ -46,6 +46,7 @@ public function getPdf($shipments = array()) foreach ($shipments as $shipment) { if ($shipment->getStoreId()) { Mage::app()->getLocale()->emulate($shipment->getStoreId()); + Mage::app()->setCurrentStore($shipment->getStoreId()); } $page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4); $pdf->pages[] = $page; @@ -59,7 +60,7 @@ public function getPdf($shipments = array()) $this->insertAddress($page, $shipment->getStore()); /* Add head */ - $this->insertOrder($page, $order, Mage::getStoreConfigFlag(self::XML_PATH_SALES_PDF_SHIPMENT_PUT_ORDER_ID, $order->getStoreId())); + $this->insertOrder($page, $shipment, Mage::getStoreConfigFlag(self::XML_PATH_SALES_PDF_SHIPMENT_PUT_ORDER_ID, $order->getStoreId())); $page->setFillColor(new Zend_Pdf_Color_GrayScale(1)); $this->_setFontRegular($page); diff --git a/app/code/core/Mage/Sales/Model/Order/Shipment.php b/app/code/core/Mage/Sales/Model/Order/Shipment.php index 346b23ac71..dd336625b5 100644 --- a/app/code/core/Mage/Sales/Model/Order/Shipment.php +++ b/app/code/core/Mage/Sales/Model/Order/Shipment.php @@ -275,12 +275,22 @@ public function addTrack(Mage_Sales_Model_Order_Shipment_Track $track) return $this; } - public function addComment($comment, $notify=false) + /** + * Adds comment to shipment with additional possibility to send it to customer via email + * and show it in customer account + * + * @param bool $notify + * @param bool $visibleOnFront + * + * @return Mage_Sales_Model_Order_Shipment + */ + public function addComment($comment, $notify=false, $visibleOnFront=false) { if (!($comment instanceof Mage_Sales_Model_Order_Shipment_Comment)) { $comment = Mage::getModel('sales/order_shipment_comment') ->setComment($comment) - ->setIsCustomerNotified($notify); + ->setIsCustomerNotified($notify) + ->setIsVisibleOnFront($visibleOnFront); } $comment->setShipment($this) ->setParentId($this->getId()) @@ -323,11 +333,6 @@ public function sendEmail($notifyCustomer=true, $comment='') return $this; } - $currentDesign = Mage::getDesign()->setAllGetOld(array( - 'package' => Mage::getStoreConfig('design/package/name', $this->getStoreId()), - 'store' => $this->getStoreId() - )); - $translate = Mage::getSingleton('core/translate'); /* @var $translate Mage_Core_Model_Translate */ $translate->setTranslateInline(false); @@ -339,6 +344,12 @@ public function sendEmail($notifyCustomer=true, $comment='') if (!$notifyCustomer && !$copyTo) { return $this; } + + $currentDesign = Mage::getDesign()->setAllGetOld(array( + 'package' => Mage::getStoreConfig('design/package/name', $this->getStoreId()), + 'store' => $this->getStoreId() + )); + $paymentBlock = Mage::helper('payment')->getInfoBlock($order->getPayment()) ->setIsSecureMode(true); $paymentBlock->getMethod()->setStore($order->getStore()->getId()); @@ -410,10 +421,6 @@ public function sendUpdateEmail($notifyCustomer = true, $comment='') return $this; } - $currentDesign = Mage::getDesign()->setAllGetOld(array( - 'package' => Mage::getStoreConfig('design/package/name', $this->getStoreId()), - )); - $translate = Mage::getSingleton('core/translate'); /* @var $translate Mage_Core_Model_Translate */ $translate->setTranslateInline(false); @@ -427,6 +434,10 @@ public function sendUpdateEmail($notifyCustomer = true, $comment='') return $this; } + $currentDesign = Mage::getDesign()->setAllGetOld(array( + 'package' => Mage::getStoreConfig('design/package/name', $this->getStoreId()), + )); + $mailTemplate = Mage::getModel('core/email_template'); if ($order->getCustomerIsGuest()) { diff --git a/app/code/core/Mage/Sales/Model/Quote.php b/app/code/core/Mage/Sales/Model/Quote.php index bd1c22369d..bb1a5c52cc 100644 --- a/app/code/core/Mage/Sales/Model/Quote.php +++ b/app/code/core/Mage/Sales/Model/Quote.php @@ -249,24 +249,46 @@ public function loadActive($quoteId) * @return Mage_Sales_Model_Quote */ public function assignCustomer(Mage_Customer_Model_Customer $customer) + { + return $this->assignCustomerWithAddressChange($customer); + } + + /** + * Assign customer model to quote with billing and shipping address change + * + * @param Mage_Customer_Model_Customer $customer + * @param Mage_Sales_Model_Quote_Address $billingAddress + * @param Mage_Sales_Model_Quote_Address $shippingAddress + * @return Mage_Sales_Model_Quote + */ + public function assignCustomerWithAddressChange( + Mage_Customer_Model_Customer $customer, + Mage_Sales_Model_Quote_Address $billingAddress = null, + Mage_Sales_Model_Quote_Address $shippingAddress = null + ) { if ($customer->getId()) { $this->setCustomer($customer); - $defaultBillingAddress = $customer->getDefaultBillingAddress(); - if ($defaultBillingAddress && $defaultBillingAddress->getId()) { - $billingAddress = Mage::getModel('sales/quote_address') - ->importCustomerAddress($defaultBillingAddress); + if (!is_null($billingAddress)) { $this->setBillingAddress($billingAddress); + } else { + $defaultBillingAddress = $customer->getDefaultBillingAddress(); + if ($defaultBillingAddress && $defaultBillingAddress->getId()) { + $billingAddress = Mage::getModel('sales/quote_address') + ->importCustomerAddress($defaultBillingAddress); + $this->setBillingAddress($billingAddress); + } } - $defaultShippingAddress= $customer->getDefaultShippingAddress(); - if ($defaultShippingAddress && $defaultShippingAddress->getId()) { - $shippingAddress = Mage::getModel('sales/quote_address') - ->importCustomerAddress($defaultShippingAddress); - } - else { - $shippingAddress = Mage::getModel('sales/quote_address'); + if (is_null($shippingAddress)) { + $defaultShippingAddress = $customer->getDefaultShippingAddress(); + if ($defaultShippingAddress && $defaultShippingAddress->getId()) { + $shippingAddress = Mage::getModel('sales/quote_address') + ->importCustomerAddress($defaultShippingAddress); + } else { + $shippingAddress = Mage::getModel('sales/quote_address'); + } } $this->setShippingAddress($shippingAddress); } @@ -307,6 +329,21 @@ public function getCustomer() return $this->_customer; } + /** + * Retrieve customer group id + * + * @return int + */ + public function getCustomerGroupId() + { + if ($this->getCustomerId()) { + return ($this->getData('customer_group_id')) ? $this->getData('customer_group_id') + : $this->getCustomer()->getGroupId(); + } else { + return Mage_Customer_Model_Group::NOT_LOGGED_IN_ID; + } + } + public function getCustomerTaxClassId() { /* @@ -606,6 +643,7 @@ public function getItemById($itemId) public function removeItem($itemId) { if ($item = $this->getItemById($itemId)) { + $item->setQuote($this); /** * If we remove item from quote - we can't use multishipping mode */ @@ -1124,6 +1162,7 @@ public function isVirtual() $countItems ++; if (!$_item->getProduct()->getIsVirtual()) { $isVirtual = false; + break; } } return $countItems == 0 ? false : $isVirtual; diff --git a/app/code/core/Mage/Sales/Model/Quote/Address.php b/app/code/core/Mage/Sales/Model/Quote/Address.php index 876a634c16..367f4f452e 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Address.php +++ b/app/code/core/Mage/Sales/Model/Quote/Address.php @@ -257,47 +257,70 @@ public function getItemsCollection() */ public function getAllItems() { - $quoteItems = $this->getQuote()->getItemsCollection(); - $addressItems = $this->getItemsCollection(); - - $items = array(); - if ($this->getQuote()->getIsMultiShipping() && $addressItems->count() > 0) { - foreach ($addressItems as $aItem) { - if ($aItem->isDeleted() || !$this->_filterNominal($aItem)) { - continue; - } - - if (!$aItem->getQuoteItemImported()) { - $qItem = $this->getQuote()->getItemById($aItem->getQuoteItemId()); - if ($qItem) { - //$this->addItem($aItem); - $aItem->importQuoteItem($qItem); + // We calculate item list once and cache it in three arrays - all items, nominal, non-nominal + $key = 'cached_items_' . ($this->_nominalOnly ? 'nominal' : ($this->_nominalOnly === false ? 'nonnominal' : 'all')); + if (!$this->hasData($key)) { + // For compatibility we will use $this->_filterNominal to divide nominal items from non-nominal (because it can be overloaded) + // So keep current flag $this->_nominalOnly and restore it after cycle + $wasNominal = $this->_nominalOnly; + $this->_nominalOnly = true; // Now $this->_filterNominal() will return positive values for nominal items + + $quoteItems = $this->getQuote()->getItemsCollection(); + $addressItems = $this->getItemsCollection(); + + $items = array(); + $nominalItems = array(); + $nonNominalItems = array(); + if ($this->getQuote()->getIsMultiShipping() && $addressItems->count() > 0) { + foreach ($addressItems as $aItem) { + if ($aItem->isDeleted()) { + continue; } - } - $items[] = $aItem; - } - } else { - $isQuoteVirtual = $this->getQuote()->isVirtual(); - foreach ($quoteItems as $qItem) { - if ($qItem->isDeleted() || !$this->_filterNominal($qItem)) { - continue; - } - /** - * For virtual quote we assign all items to billing address - */ - if ($isQuoteVirtual) { - if ($this->getAddressType() == self::TYPE_BILLING) { - $items[] = $qItem; + if (!$aItem->getQuoteItemImported()) { + $qItem = $this->getQuote()->getItemById($aItem->getQuoteItemId()); + if ($qItem) { + $aItem->importQuoteItem($qItem); + } + } + $items[] = $aItem; + if ($this->_filterNominal($aItem)) { + $nominalItems[] = $aItem; + } else { + $nonNominalItems[] = $aItem; } - } else { - if ($this->getAddressType() == self::TYPE_SHIPPING) { + } + } else { + /* + * For virtual quote we assign items only to billing address, otherwise - only to shipping address + */ + $addressType = $this->getAddressType(); + $canAddItems = $this->getQuote()->isVirtual() ? ($addressType == self::TYPE_BILLING) : ($addressType == self::TYPE_SHIPPING); + + if ($canAddItems) { + foreach ($quoteItems as $qItem) { + if ($qItem->isDeleted()) { + continue; + } $items[] = $qItem; + if ($this->_filterNominal($qItem)) { + $nominalItems[] = $qItem; + } else { + $nonNominalItems[] = $qItem; + } } } } + + // Cache calculated lists + $this->setData('cached_items_all', $items); + $this->setData('cached_items_nominal', $nominalItems); + $this->setData('cached_items_nonnominal', $nonNominalItems); + + $this->_nominalOnly = $wasNominal; // Restore original value before we changed it } + $items = $this->getData($key); return $items; } @@ -679,6 +702,7 @@ public function collectShippingRates() */ public function requestShippingRates(Mage_Sales_Model_Quote_Item_Abstract $item = null) { + /** @var $request Mage_Shipping_Model_Rate_Request */ $request = Mage::getModel('shipping/rate_request'); $request->setAllItems($item ? array($item) : $this->getAllItems()); $request->setDestCountryId($this->getCountryId()); diff --git a/app/code/core/Mage/Sales/Model/Quote/Address/Total/Shipping.php b/app/code/core/Mage/Sales/Model/Quote/Address/Total/Shipping.php index b4b257269d..e8eed9739b 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Address/Total/Shipping.php +++ b/app/code/core/Mage/Sales/Model/Quote/Address/Total/Shipping.php @@ -165,7 +165,8 @@ public function collect(Mage_Sales_Model_Quote_Address $address) $amountPrice = $address->getQuote()->getStore()->convertPrice($rate->getPrice(), false); $this->_setAmount($amountPrice); $this->_setBaseAmount($rate->getPrice()); - $address->setShippingDescription($rate->getCarrierTitle().' - '.$rate->getMethodTitle()); + $shippingDescription = $rate->getCarrierTitle() . ' - ' . $rate->getMethodTitle(); + $address->setShippingDescription(trim($shippingDescription, '-')); break; } } @@ -183,11 +184,15 @@ public function collect(Mage_Sales_Model_Quote_Address $address) public function fetch(Mage_Sales_Model_Quote_Address $address) { $amount = $address->getShippingAmount(); - if ($amount!=0 || $address->getShippingDescription()) { + if ($amount != 0 || $address->getShippingDescription()) { + $title = Mage::helper('sales')->__('Shipping & Handling'); + if ($address->getShippingDescription()) { + $title .= ' (' . $address->getShippingDescription() . ')'; + } $address->addTotal(array( - 'code'=>$this->getCode(), - 'title'=>Mage::helper('sales')->__('Shipping & Handling').' ('.$address->getShippingDescription().')', - 'value'=>$address->getShippingAmount() + 'code' => $this->getCode(), + 'title' => $title, + 'value' => $address->getShippingAmount() )); } return $this; diff --git a/app/code/core/Mage/Sales/Model/Quote/Address/Total/Subtotal.php b/app/code/core/Mage/Sales/Model/Quote/Address/Total/Subtotal.php index 934d03fd74..d3a143e957 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Address/Total/Subtotal.php +++ b/app/code/core/Mage/Sales/Model/Quote/Address/Total/Subtotal.php @@ -90,7 +90,7 @@ protected function _initItem($address, $item) } /** - * Quote super mode flag meen whot we work with quote without restriction + * Quote super mode flag mean what we work with quote without restriction */ if ($item->getQuote()->getIsSuperMode()) { if (!$product) { @@ -110,11 +110,13 @@ protected function _initItem($address, $item) $quoteItem->getProduct(), $quoteItem->getQty() ); - $item->setPrice($finalPrice); + $item->setPrice($finalPrice) + ->setBaseOriginalPrice($finalPrice); $item->calcRowTotal(); } else if (!$quoteItem->getParentItem()) { $finalPrice = $product->getFinalPrice($quoteItem->getQty()); - $item->setPrice($finalPrice); + $item->setPrice($finalPrice) + ->setBaseOriginalPrice($finalPrice); $item->calcRowTotal(); $this->_addAmount($item->getRowTotal()); $this->_addBaseAmount($item->getBaseRowTotal()); diff --git a/app/code/core/Mage/Sales/Model/Quote/Config.php b/app/code/core/Mage/Sales/Model/Quote/Config.php index 7a7dd3b420..4da3e404fc 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Config.php +++ b/app/code/core/Mage/Sales/Model/Quote/Config.php @@ -32,6 +32,9 @@ class Mage_Sales_Model_Quote_Config public function getProductAttributes() { $attributes = Mage::getConfig()->getNode(self::XML_PATH_QUOTE_PRODUCT_ATTRIBUTES)->asArray(); + $transfer = new Varien_Object($attributes); + Mage::dispatchEvent('sales_quote_config_get_product_attributes', array('attributes' => $transfer)); + $attributes = $transfer->getData(); return array_keys($attributes); } diff --git a/app/code/core/Mage/Sales/Model/Quote/Item.php b/app/code/core/Mage/Sales/Model/Quote/Item.php index c8d0d4ec95..205faafc67 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Item.php +++ b/app/code/core/Mage/Sales/Model/Quote/Item.php @@ -169,8 +169,6 @@ public function addQty($qty) public function setQty($qty) { $qty = $this->_prepareQty($qty); - - $oldQty = $this->_getData('qty'); $this->setData('qty', $qty); @@ -182,6 +180,7 @@ public function setQty($qty) if ($this->getUseOldQty()) { $this->setData('qty', $oldQty); } + return $this; } @@ -196,23 +195,39 @@ public function setQty($qty) */ public function getQtyOptions() { - $productIds = array(); - $return = array(); - foreach ($this->getOptions() as $option) { - /* @var $option Mage_Sales_Model_Quote_Item_Option */ - if (is_object($option->getProduct()) && $option->getProduct()->getId() != $this->getProduct()->getId() - && !isset($productIds[$option->getProduct()->getId()])) { - $productIds[$option->getProduct()->getId()] = $option->getProduct()->getId(); + $qtyOptions = $this->getData('qty_options'); + if (is_null($qtyOptions)) { + $productIds = array(); + $qtyOptions = array(); + foreach ($this->getOptions() as $option) { + /** @var $option Mage_Sales_Model_Quote_Item_Option */ + if (is_object($option->getProduct()) && $option->getProduct()->getId() != $this->getProduct()->getId()) { + $productIds[$option->getProduct()->getId()] = $option->getProduct()->getId(); + } } - } - foreach ($productIds as $productId) { - if ($option = $this->getOptionByCode('product_qty_' . $productId)) { - $return[$productId] = $option; + foreach ($productIds as $productId) { + $option = $this->getOptionByCode('product_qty_' . $productId); + if ($option) { + $qtyOptions[$productId] = $option; + } } + + $this->setData('qty_options', $qtyOptions); } - return $return; + return $qtyOptions; + } + + /** + * Set option product with Qty + * + * @param $qtyOptions + * @return Mage_Sales_Model_Quote_Item + */ + public function setQtyOptions($qtyOptions) + { + return $this->setData('qty_options', $qtyOptions); } /** @@ -242,7 +257,7 @@ public function setProduct($product) { if ($this->getQuote()) { $product->setStoreId($this->getQuote()->getStoreId()); - $product->setCustomerGroupId($this->getQuote()->getCustomer()->getGroupId()); + $product->setCustomerGroupId($this->getQuote()->getCustomerGroupId()); } $this->setData('product', $product) ->setProductId($product->getId()) @@ -254,6 +269,7 @@ public function setProduct($product) ->setBaseCost($product->getCost()) ->setIsRecurring($product->getIsRecurring()) ; + if ($product->getStockItem()) { $this->setIsQtyDecimal($product->getStockItem()->getIsQtyDecimal()); } @@ -263,6 +279,7 @@ public function setProduct($product) 'quote_item'=>$this )); + // if ($options = $product->getCustomOptions()) { // foreach ($options as $option) { // $this->addOption($option); @@ -283,7 +300,6 @@ public function getProduct() $product = Mage::getModel('catalog/product') ->setStoreId($this->getQuote()->getStoreId()) ->load($this->getProductId()); - $this->setProduct($product); } @@ -510,9 +526,9 @@ public function addOption($option) */ public function updateQtyOption(Varien_Object $option, $value) { - $optionProduct = $option->getProduct(); + $optionProduct = $option->getProduct(); + $options = $this->getQtyOptions(); - $options = $this->getQtyOptions(); if (isset($options[$optionProduct->getId()])) { $options[$optionProduct->getId()]->setValue($value); } @@ -531,7 +547,8 @@ public function updateQtyOption(Varien_Object $option, $value) */ public function removeOption($code) { - if ($option = $this->getOptionByCode($code)) { + $option = $this->getOptionByCode($code); + if ($option) { $option->isDeleted(true); } return $this; @@ -568,23 +585,54 @@ public function getOptionByCode($code) return null; } + /** + * Checks that item model has data changes. + * Call save item options if model isn't need to save in DB + * + * @return boolean + */ + protected function _hasModelChanged() + { + if (!$this->hasDataChanges()) { + return false; + } + + $result = $this->_getResource()->hasDataChanged($this); + if ($result === false) { + $this->_saveItemOptions(); + } + + return $result; + } + /** * Save item options * * @return Mage_Sales_Model_Quote_Item */ - protected function _afterSave() + protected function _saveItemOptions() { foreach ($this->_options as $index => $option) { if ($option->isDeleted()) { $option->delete(); unset($this->_options[$index]); unset($this->_optionsByCode[$option->getCode()]); - } - else { + } else { $option->save(); } } + + return $this; + } + + /** + * Save item options after item saved + * + * @return Mage_Sales_Model_Quote_Item + */ + protected function _afterSave() + { + $this->_saveItemOptions(); return parent::_afterSave(); } diff --git a/app/code/core/Mage/Sales/Model/Quote/Item/Abstract.php b/app/code/core/Mage/Sales/Model/Quote/Item/Abstract.php index d0822120d3..89da5b4e43 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Item/Abstract.php +++ b/app/code/core/Mage/Sales/Model/Quote/Item/Abstract.php @@ -27,6 +27,13 @@ /** * Quote item abstract model * + * Price attributes: + * - price - initial item price, declared during product association + * - original_price - product price before any calculations + * - calculation_price - prices for item totals calculation + * - custom_price - new price that can be declared by user and recalculated during calculation process + * - original_custom_price - original defined value of custom price without any convertion + * * @category Mage * @package Mage_Sales * @author Magento Core Team @@ -108,9 +115,9 @@ public function addChild($child) } /** - * Set masseges for quote item + * Set messages for quote item * - * @param mixed $messages + * @param mixed $messages * @return Mage_Sales_Model_Quote_Item_Abstract */ public function setMessage($messages) { @@ -139,7 +146,7 @@ public function addMessage($message) * Get messages array of quote item * * @param bool $string flag for converting messages to string - * @return array | string + * @return array|string */ public function getMessage($string = true) { @@ -252,7 +259,7 @@ public function getCalculationPrice() if ($this->hasOriginalCustomPrice()) { $price = $this->getOriginalCustomPrice(); } else { - $price = $this->getOriginalPrice(); + $price = $this->getConvertedPrice(); } $this->setData('calculation_price', $price); } @@ -267,8 +274,8 @@ public function getCalculationPrice() public function getBaseCalculationPrice() { if (!$this->hasBaseCalculationPrice()) { - if ($this->hasCustomPrice()) { - $price = (float) $this->getCustomPrice(); + if ($this->hasOriginalCustomPrice()) { + $price = (float) $this->getOriginalCustomPrice(); if ($price) { $rate = $this->getStore()->convertPrice($price) / $price; $price = $price / $rate; @@ -308,7 +315,7 @@ public function getIsNominal() /** * Get original price (retrieved from product) for item. - * Original price value is in current selected currency + * Original price value is in quote selected currency * * @return float */ @@ -316,7 +323,7 @@ public function getOriginalPrice() { $price = $this->_getData('original_price'); if (is_null($price)) { - $price = $this->getStore()->convertPrice($this->getPrice()); + $price = $this->getStore()->convertPrice($this->getBaseOriginalPrice()); $this->setData('original_price', $price); } return $price; @@ -330,7 +337,6 @@ public function getOriginalPrice() */ public function setOriginalPrice($price) { - $this->setCalculationPrice(null); return $this->setData('original_price', $price); } @@ -341,17 +347,7 @@ public function setOriginalPrice($price) */ public function getBaseOriginalPrice() { - return $this->getPrice(); - } - - /** - * Get item price (item price always exclude price) - * - * @return decimal - */ - public function getPrice() - { - return $this->_getData('price'); + return $this->_getData('base_original_price'); } /** @@ -368,7 +364,17 @@ public function setCustomPrice($value) } /** - * Specify item price (base calculation price will be refreshed too) + * Get item price. Item price currency is website base currency. + * + * @return decimal + */ + public function getPrice() + { + return $this->_getData('price'); + } + + /** + * Specify item price (base calculation price and converted price will be refreshed too) * * @param float $value * @return Mage_Sales_Model_Quote_Item_Abstract @@ -376,9 +382,36 @@ public function setCustomPrice($value) public function setPrice($value) { $this->setBaseCalculationPrice(null); + $this->setConvertedPrice(null); return $this->setData('price', $value); } + /** + * Get item price converted to quote currency + * @return float + */ + public function getConvertedPrice() + { + $price = $this->_getData('converted_price'); + if (is_null($price)) { + $price = $this->getStore()->convertPrice($this->getPrice()); + $this->setData('converted_price', $price); + } + return $price; + } + + /** + * Set new value for converted price + * @param float $value + * @return Mage_Sales_Model_Quote_Item_Abstract + */ + public function setConvertedPrice($value) + { + $this->setCalculationPrice(null); + $this->setData('converted_price', $value); + return $this; + } + /** * Clone quote item * @@ -399,7 +432,8 @@ public function __clone() * * @return bool */ - public function isChildrenCalculated() { + public function isChildrenCalculated() + { if ($this->getParentItem()) { $calculate = $this->getParentItem()->getProduct()->getPriceType(); } else { @@ -419,7 +453,8 @@ public function isChildrenCalculated() { * * @return bool */ - public function isShipSeparately() { + public function isShipSeparately() + { if ($this->getParentItem()) { $shipmentType = $this->getParentItem()->getProduct()->getShipmentType(); } else { diff --git a/app/code/core/Mage/Sales/Model/Quote/Item/Option.php b/app/code/core/Mage/Sales/Model/Quote/Item/Option.php index dd37fa42d6..6a0c7521ab 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Item/Option.php +++ b/app/code/core/Mage/Sales/Model/Quote/Item/Option.php @@ -44,6 +44,20 @@ protected function _construct() $this->_init('sales/quote_item_option'); } + /** + * Checks that item option model has data changes + * + * @return boolean + */ + protected function _hasModelChanged() + { + if (!$this->hasDataChanges()) { + return false; + } + + return $this->_getResource()->hasDataChanged($this); + } + /** * Set quote item * diff --git a/app/code/core/Mage/Sales/Model/Quote/Payment.php b/app/code/core/Mage/Sales/Model/Quote/Payment.php index a37479a1b3..ea45ee5b09 100644 --- a/app/code/core/Mage/Sales/Model/Quote/Payment.php +++ b/app/code/core/Mage/Sales/Model/Quote/Payment.php @@ -113,15 +113,15 @@ public function importData(array $data) */ protected function _beforeSave() { + if ($this->getQuote()) { + $this->setQuoteId($this->getQuote()->getId()); + } try { $method = $this->getMethodInstance(); } catch (Mage_Core_Exception $e) { return parent::_beforeSave(); } $method->prepareSave(); - if ($this->getQuote()) { - $this->setQuoteId($this->getQuote()->getId()); - } return parent::_beforeSave(); } diff --git a/app/code/core/Mage/Sales/Model/Recurring/Profile.php b/app/code/core/Mage/Sales/Model/Recurring/Profile.php index 95ce16828d..ed5092b724 100644 --- a/app/code/core/Mage/Sales/Model/Recurring/Profile.php +++ b/app/code/core/Mage/Sales/Model/Recurring/Profile.php @@ -370,6 +370,12 @@ public function importQuoteItem(Mage_Sales_Model_Quote_Item_Abstract $item) $orderItemInfo = $item->getData(); $this->_cleanupArray($orderItemInfo); + + $customOptions = $item->getOptionsByCode(); + if ($customOptions['info_buyRequest']) { + $orderItemInfo['info_buyRequest'] = $customOptions['info_buyRequest']->getValue(); + } + $this->setOrderItemInfo($orderItemInfo); return $this->_filterValues(); diff --git a/app/code/core/Mage/Sales/controllers/DownloadController.php b/app/code/core/Mage/Sales/controllers/DownloadController.php index 836893766e..1c023fb28a 100644 --- a/app/code/core/Mage/Sales/controllers/DownloadController.php +++ b/app/code/core/Mage/Sales/controllers/DownloadController.php @@ -37,51 +37,87 @@ class Mage_Sales_DownloadController extends Mage_Core_Controller_Front_Action /** * Custom options downloader + * + * @param mixed $info */ - public function downloadCustomOptionAction () + protected function _downloadFileAction($info) { - $quoteItemOptionId = $this->getRequest()->getParam('id'); $secretKey = $this->getRequest()->getParam('key'); - $option = Mage::getModel('sales/quote_item_option')->load($quoteItemOptionId); - - if ($option->getId()) { - - try { - $info = unserialize($option->getValue()); + try { + if ($secretKey != $info['secret_key']) { + throw new Exception(); + } - if ($secretKey != $info['secret_key']) { + $filePath = Mage::getBaseDir() . $info['order_path']; + if (!is_file($filePath) || !is_readable($filePath)) { + // try get file from quote + $filePath = Mage::getBaseDir() . $info['quote_path']; + if (!is_file($filePath) || !is_readable($filePath)) { throw new Exception(); } + } - $filePath = Mage::getBaseDir() . $info['order_path']; - if (!is_file($filePath) || !is_readable($filePath)) { - // try get file from quote - $filePath = Mage::getBaseDir() . $info['quote_path']; - if (!is_file($filePath) || !is_readable($filePath)) { - throw new Exception(); - } - } + $this->getResponse() + ->setHttpResponseCode(200) + ->setHeader('Pragma', 'public', true) + ->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true) + ->setHeader('Content-type', $info['type'], true) + ->setHeader('Content-Length', $info['size']) + ->setHeader('Content-Disposition', 'inline' . '; filename='.$info['title']); - $this->getResponse() - ->setHttpResponseCode(200) - ->setHeader('Pragma', 'public', true) - ->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true) - ->setHeader('Content-type', $info['type'], true) - ->setHeader('Content-Length', $info['size']) - ->setHeader('Content-Disposition', 'inline' . '; filename='.$info['title']); + $this->getResponse() + ->clearBody(); + $this->getResponse() + ->sendHeaders(); - $this->getResponse() - ->clearBody(); - $this->getResponse() - ->sendHeaders(); + readfile($filePath); - readfile($filePath); + } catch (Exception $e) { + $this->_forward('noRoute'); + } + } + /** + * Profile custom options download action + */ + public function downloadProfileCustomOptionAction() + { + $recurringProfile = Mage::getModel('sales/recurring_profile')->load($this->getRequest()->getParam('id')); - } catch (Exception $e) { + if (!$recurringProfile->getId()) { + $this->_forward('noRoute'); + } + + $orderItemInfo = $recurringProfile->getData('order_item_info'); + try { + $request = unserialize($orderItemInfo['info_buyRequest']); + if (!isset($request['options'][$this->getRequest()->getParam('option_id')])) { $this->_forward('noRoute'); + return; } + $this->_downloadFileAction($request['options'][$this->getRequest()->getParam('option_id')]); + } catch (Exception $e) { + $this->_forward('noRoute'); + } + $info = array( + '' + ); + } + + /** + * Custom options download action + */ + public function downloadCustomOptionAction() + { + $quoteItemOptionId = $this->getRequest()->getParam('id'); + $option = Mage::getModel('sales/quote_item_option')->load($quoteItemOptionId); - } else { + if (!$option->getId()) { + $this->_forward('noRoute'); + } + try { + $info = unserialize($option->getValue()); + $this->_downloadFileAction($info); + } catch (Exception $e) { $this->_forward('noRoute'); } } diff --git a/app/code/core/Mage/Sales/etc/config.xml b/app/code/core/Mage/Sales/etc/config.xml index ba78a0fb17..421d51eee2 100644 --- a/app/code/core/Mage/Sales/etc/config.xml +++ b/app/code/core/Mage/Sales/etc/config.xml @@ -28,7 +28,7 @@ - 1.4.0.15 + 1.4.0.21 @@ -155,7 +155,7 @@ ** ** ** - * + ** @@ -198,7 +198,7 @@ * * * - base_original_price + * * * * @@ -625,6 +625,7 @@ + diff --git a/app/code/core/Mage/Sales/etc/wsdl.xml b/app/code/core/Mage/Sales/etc/wsdl.xml index 8c21739f07..5da6c65335 100644 --- a/app/code/core/Mage/Sales/etc/wsdl.xml +++ b/app/code/core/Mage/Sales/etc/wsdl.xml @@ -72,6 +72,8 @@ + + @@ -153,6 +155,8 @@ + + @@ -220,6 +224,7 @@ + diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-0.9.28-0.9.29.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-0.9.28-0.9.29.php index 2ccdb28165..430e796081 100644 --- a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-0.9.28-0.9.29.php +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-0.9.28-0.9.29.php @@ -27,12 +27,12 @@ $installer = $this; /* @var $installer Mage_Sales_Model_Mysql4_Setup */ -$installer->getConnection()->addColumn($this->getTable('sales/order'), 'discount_refunded', 'decimal(12,4) default NULL AFTER `subtotal_canceled`'); -$installer->getConnection()->addColumn($this->getTable('sales/order'), 'discount_canceled', 'decimal(12,4) default NULL AFTER `discount_refunded`'); -$installer->getConnection()->addColumn($this->getTable('sales/order'), 'discount_invoiced', 'decimal(12,4) default NULL AFTER `discount_canceled`'); -$installer->getConnection()->addColumn($this->getTable('sales/order'), 'base_discount_refunded', 'decimal(12,4) default NULL AFTER `base_subtotal_canceled`'); -$installer->getConnection()->addColumn($this->getTable('sales/order'), 'base_discount_canceled', 'decimal(12,4) default NULL AFTER `base_discount_refunded`'); -$installer->getConnection()->addColumn($this->getTable('sales/order'), 'base_discount_invoiced', 'decimal(12,4) default NULL AFTER `base_discount_canceled`'); +$installer->getConnection()->addColumn($this->getTable('sales_order'), 'discount_refunded', 'decimal(12,4) default NULL AFTER `subtotal_canceled`'); +$installer->getConnection()->addColumn($this->getTable('sales_order'), 'discount_canceled', 'decimal(12,4) default NULL AFTER `discount_refunded`'); +$installer->getConnection()->addColumn($this->getTable('sales_order'), 'discount_invoiced', 'decimal(12,4) default NULL AFTER `discount_canceled`'); +$installer->getConnection()->addColumn($this->getTable('sales_order'), 'base_discount_refunded', 'decimal(12,4) default NULL AFTER `base_subtotal_canceled`'); +$installer->getConnection()->addColumn($this->getTable('sales_order'), 'base_discount_canceled', 'decimal(12,4) default NULL AFTER `base_discount_refunded`'); +$installer->getConnection()->addColumn($this->getTable('sales_order'), 'base_discount_invoiced', 'decimal(12,4) default NULL AFTER `base_discount_canceled`'); $installer->addAttribute('order', 'discount_refunded', array('type'=>'static')); $installer->addAttribute('order', 'discount_canceled', array('type'=>'static')); @@ -55,6 +55,8 @@ "; $ordersEntity = $installer->getEntityType('order'); +// hardcoding `sales_order` due to change in config.xml for 'sales/order' from `sales_order` to `sales_flat_order` +$ordersEntity['entity_table'] = 'sales_order'; $ordersTable = $installer->getTable($ordersEntity['entity_table']); // Update discount_refunded (base_discount_refunded) @@ -66,9 +68,9 @@ $baseDiscountAttributeId = $installer->getAttributeId($entityTypeId, 'base_discount_amount'); $baseDiscountAttributeTable = $installer->getAttributeTable($entityTypeId, 'base_discount_amount'); -$temporaryTableName = $installer->getConnection()->quoteIdentifier('sales_sql_update' . crc32(uniqid('sales'))); +$temporaryTableName = 'sales_sql_update' . crc32(uniqid('sales')); -$preparedSql = 'CREATE TEMPORARY TABLE ' . $temporaryTableName . ' ' . sprintf($sql, +$preparedSql = 'CREATE TEMPORARY TABLE ' . $installer->getConnection()->quoteIdentifier($temporaryTableName) . ' ' . sprintf($sql, $orderAttributeTable, $discountAttributeTable, $discountAttributeId, @@ -93,7 +95,7 @@ ); $installer->getConnection()->query( - 'DROP TEMPORARY TABLE ' . $temporaryTableName + 'DROP TEMPORARY TABLE ' . $installer->getConnection()->quoteIdentifier($temporaryTableName) ); // Update discount_invoiced (base_discount_invoiced) @@ -105,7 +107,7 @@ $baseDiscountAttributeId = $installer->getAttributeId($entityTypeId, 'base_discount_amount'); $baseDiscountAttributeTable = $installer->getAttributeTable($entityTypeId, 'base_discount_amount'); -$preparedSql = 'CREATE TEMPORARY TABLE ' . $temporaryTableName . ' ' . sprintf($sql, +$preparedSql = 'CREATE TEMPORARY TABLE ' . $installer->getConnection()->quoteIdentifier($temporaryTableName) . ' ' . sprintf($sql, $orderAttributeTable, $discountAttributeTable, $discountAttributeId, @@ -130,12 +132,14 @@ ); $installer->getConnection()->query( - 'DROP TEMPORARY TABLE ' . $temporaryTableName + 'DROP TEMPORARY TABLE ' . $installer->getConnection()->quoteIdentifier($temporaryTableName) ); // Update discount_canceled (base_discount_canceled) $statusAttributeId = $installer->getAttributeId($ordersEntity['entity_type_id'], 'status'); -$statusAttributeTable = $installer->getAttributeTable($ordersEntity['entity_type_id'], 'status'); +// hardcoding `sales_order_varchar` due to change in config.xml for 'sales/order' from `sales_order` to `sales_flat_order` +$statusAttributeTable = $installer->getTable($ordersTable.'_varchar'); + $select = $installer->getConnection()->select(); $select->from( array('s' => $statusAttributeTable), @@ -148,5 +152,5 @@ UPDATE `{$ordersTable}` SET `discount_canceled`=`discount_amount`-`discount_invoiced`, `base_discount_canceled`=`base_discount_amount`-`base_discount_invoiced` - WHERE `entity_id`=IN({$select->assemble()}); + WHERE `entity_id` IN({$select->assemble()}); "); diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.3.99-1.4.0.0.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.3.99-1.4.0.0.php index dc7e55cc82..777b7efb0c 100644 --- a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.3.99-1.4.0.0.php +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.3.99-1.4.0.0.php @@ -1141,6 +1141,40 @@ $installer->getConnection()->query('DROP TEMPORARY TABLE ' . $temporaryTable); +/** + * Workaround for the coupon_code attribute that may be missed in the Mage_SalesRule/sql/mysql4-upgrade-0.7.10-0.7.11.php + * The problem is that Mage_SalesRule depends on Mage_Sales and sometimes the attribute doesn't get updated before this line of code. + * As a result: an existing column in the sales_flat_order table, but wrong type in the attribute registry and sometimes even data lost + * Reproduces on upgrading from 1.4.0.x to 1.4.1.0 + * + * Test case: + * 1) Have Magento instance without flat sales yet, and without Mage_SalesRule/sql/mysql4-upgrade-0.7.10-0.7.11.php + * 2) Upgrade it to the flat one instantly (runs this upgrade). Without this code the proper upgrade of coupon_code is missed. Data is lost. + * 3) The Mage_SalesRule/sql/mysql4-upgrade-0.7.10-0.7.11.php runs AFTER this code, because it depends on Mage_Sales. But it is too late. + * Result: the attribute has wrong type and data may be lost depending on upgrade history. + */ +$orderEntityType = $installer->getEntityType('order'); +$orderEntityTypeId = $orderEntityType['entity_type_id']; +$attribute = $installer->getAttribute($orderEntityTypeId, 'coupon_code'); + +if ($attribute && is_array($attribute) && isset($attribute['backend_type']) && $attribute['backend_type'] !== 'static') { + try { + $installer->getConnection()->beginTransaction(); + $installer->run(" + UPDATE {$installer->getTable('sales_flat_order')} AS o, {$installer->getTable('sales_order_entity_varchar')} AS od + SET o.{$attribute['attribute_code']} = od.value + WHERE od.entity_id = o.entity_id + AND od.attribute_id = {$attribute['attribute_id']} + AND od.entity_type_id = {$orderEntityTypeId} + "); + $installer->updateAttribute($orderEntityTypeId, $attribute['attribute_code'], array('backend_type' => 'static')); + $installer->getConnection()->commit(); + } catch (Exception $e) { + $installer->getConnection()->rollback(); + throw $e; + } +} + // Remove previous tables $tablesToDrop = array( 'sales_order_entity_decimal', diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.15-1.4.0.16.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.15-1.4.0.16.php new file mode 100644 index 0000000000..6f1d7614a8 --- /dev/null +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.15-1.4.0.16.php @@ -0,0 +1,31 @@ +getConnection()->addColumn($installer->getTable('sales/order_item'), 'tax_canceled', 'decimal(12,4) NULL'); +$installer->getConnection()->addColumn($installer->getTable('sales/order_item'), 'hidden_tax_canceled', 'decimal(12,4) NULL'); +$installer->getConnection()->addColumn($installer->getTable('sales/order_item'), 'tax_refunded', 'decimal(12,4) NULL'); diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.16-1.4.0.17.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.16-1.4.0.17.php new file mode 100644 index 0000000000..300b812499 --- /dev/null +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.16-1.4.0.17.php @@ -0,0 +1,43 @@ +getTable('sales/billing_agreement'); + +$installer->getConnection()->addColumn($billingAgreementTable, + 'store_id', 'smallint(5) unsigned DEFAULT NULL'); + +$installer->getConnection()->addConstraint( + 'FK_BILLING_AGREEMENT_STORE', + $billingAgreementTable, + 'store_id', + $installer->getTable('core/store'), + 'store_id', + 'SET NULL', + 'CASCADE' +); diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.17-1.4.0.18.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.17-1.4.0.18.php new file mode 100644 index 0000000000..e749322256 --- /dev/null +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.17-1.4.0.18.php @@ -0,0 +1,37 @@ +startSetup(); +$installer->getConnection()->addColumn($installer->getTable('sales/invoice_comment'), 'is_visible_on_front', + 'tinyint(1) unsigned not null default 0 after `is_customer_notified`'); +$installer->getConnection()->addColumn($installer->getTable('sales/shipment_comment'), 'is_visible_on_front', + 'tinyint(1) unsigned not null default 0 after `is_customer_notified`'); +$installer->getConnection()->addColumn($installer->getTable('sales/creditmemo_comment'), 'is_visible_on_front', + 'tinyint(1) unsigned not null default 0 after `is_customer_notified`'); +$installer->endSetup(); diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.18-1.4.0.19.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.18-1.4.0.19.php new file mode 100644 index 0000000000..2f350067c5 --- /dev/null +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.18-1.4.0.19.php @@ -0,0 +1,33 @@ +getTable('sales/billing_agreement'); + +$installer->getConnection()->addColumn($billingAgreementTable, + 'agreement_label', 'varchar(255)'); diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.19-1.4.0.20.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.19-1.4.0.20.php new file mode 100644 index 0000000000..09d8a91fc9 --- /dev/null +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.19-1.4.0.20.php @@ -0,0 +1,31 @@ +getConnection()->addKey($installer->getTable('sales/quote'), 'IDX_IS_ACTIVE', 'is_active'); +$installer->getConnection()->addKey($installer->getTable('sales/order_item'), 'IDX_PRODUCT_ID', 'product_id'); diff --git a/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.20-1.4.0.21.php b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.20-1.4.0.21.php new file mode 100644 index 0000000000..f8c59acd2a --- /dev/null +++ b/app/code/core/Mage/Sales/sql/sales_setup/mysql4-upgrade-1.4.0.20-1.4.0.21.php @@ -0,0 +1,71 @@ + 'FK_PRODUCT_ORDERED_AGGREGATED_%s_STORE_ID', + 'column' => 'store_id', + 'refTable' => 'core/store', + 'refColumn' => 'store_id' + ), + array( + 'name' => 'FK_PRODUCT_ORDERED_AGGREGATED_%s_PRODUCT_ID', + 'column' => 'product_id', + 'refTable' => 'catalog/product', + 'refColumn' => 'entity_id' + ) +); + +/* + * Alter foreign keys to add 'CASCADE' instead of 'SET_NULL' action + * Also remove all wrong report records with NULL in 'product_id' field + */ +$connection = $installer->getConnection(); +foreach ($frequencies as $frequency) { + $tableName = $installer->getTable('sales/bestsellers_aggregated_' . $frequency); + + foreach ($foreignKeys as $fkInfo) { + $connection->addConstraint( + sprintf($fkInfo['name'], strtoupper($frequency)), + $tableName, + $fkInfo['column'], + $installer->getTable($fkInfo['refTable']), + $fkInfo['refColumn'] + ); + } + + $connection->delete($tableName, 'product_id IS NULL'); +} diff --git a/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Rule.php b/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Rule.php index f11ca1b77b..e13ece23de 100644 --- a/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Rule.php +++ b/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Rule.php @@ -86,8 +86,8 @@ protected function _aggregateByOrderCreatedAt($from, $to) 'coupon_code' => 'coupon_code', 'coupon_uses' => 'COUNT(`entity_id`)', 'subtotal_amount' => 'SUM((`base_subtotal` - IFNULL(`base_subtotal_canceled`, 0)) * `base_to_global_rate`)', - 'discount_amount' => 'SUM((`base_discount_amount` - IFNULL(`base_discount_canceled`, 0)) * `base_to_global_rate`)', - 'total_amount' => 'SUM((`base_subtotal` - IFNULL(`base_subtotal_canceled`, 0) - IFNULL(`base_discount_amount` - IFNULL(`base_discount_canceled`, 0), 0)) * `base_to_global_rate`)', + 'discount_amount' => 'SUM((ABS(`base_discount_amount`) - IFNULL(`base_discount_canceled`, 0)) * `base_to_global_rate`)', + 'total_amount' => 'SUM((`base_subtotal` - IFNULL(`base_subtotal_canceled`, 0) + IFNULL(ABS(`base_discount_amount`) - IFNULL(`base_discount_canceled`, 0), 0)) * `base_to_global_rate`)', 'subtotal_amount_actual' => 'SUM((`base_subtotal_invoiced` - IFNULL(`base_subtotal_refunded`, 0)) * `base_to_global_rate`)', 'discount_amount_actual' => 'SUM((`base_discount_invoiced` - IFNULL(`base_discount_refunded`, 0)) * `base_to_global_rate`)', 'total_amount_actual' => 'SUM((`base_subtotal_invoiced` - IFNULL(`base_subtotal_refunded`, 0) - IFNULL(`base_discount_invoiced` - IFNULL(`base_discount_refunded`, 0), 0)) * `base_to_global_rate`)', diff --git a/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Updatedat/Collection.php b/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Updatedat/Collection.php index 30cbbcc750..4190b82407 100644 --- a/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Updatedat/Collection.php +++ b/app/code/core/Mage/SalesRule/Model/Mysql4/Report/Updatedat/Collection.php @@ -39,8 +39,8 @@ class Mage_SalesRule_Model_Mysql4_Report_Updatedat_Collection extends Mage_Sales 'coupon_code' => 'e.coupon_code', 'coupon_uses' => 'COUNT(e.`entity_id`)', 'subtotal_amount' => 'SUM((e.`base_subtotal` - IFNULL(e.`base_subtotal_canceled`, 0)) * e.`base_to_global_rate`)', - 'discount_amount' => 'SUM((e.`base_discount_amount` - IFNULL(e.`base_discount_canceled`, 0)) * e.`base_to_global_rate`)', - 'total_amount' => 'SUM((e.`base_subtotal` - IFNULL(e.`base_subtotal_canceled`, 0) - IFNULL(e.`base_discount_amount` - IFNULL(e.`base_discount_canceled`, 0), 0)) * e.`base_to_global_rate`)', + 'discount_amount' => 'SUM((ABS(e.`base_discount_amount`) - IFNULL(e.`base_discount_canceled`, 0)) * e.`base_to_global_rate`)', + 'total_amount' => 'SUM((e.`base_subtotal` - IFNULL(e.`base_subtotal_canceled`, 0) + IFNULL(ABS(e.`base_discount_amount`) - IFNULL(e.`base_discount_canceled`, 0), 0)) * e.`base_to_global_rate`)', 'subtotal_amount_actual' => 'SUM((e.`base_subtotal_invoiced` - IFNULL(e.`base_subtotal_refunded`, 0)) * e.`base_to_global_rate`)', 'discount_amount_actual' => 'SUM((e.`base_discount_invoiced` - IFNULL(e.`base_discount_refunded`, 0)) * e.`base_to_global_rate`)', 'total_amount_actual' => 'SUM((e.`base_subtotal_invoiced` - IFNULL(e.`base_subtotal_refunded`, 0) - IFNULL(e.`base_discount_invoiced` - IFNULL(e.`base_discount_refunded`, 0), 0)) * e.`base_to_global_rate`)', diff --git a/app/code/core/Mage/SalesRule/Model/Mysql4/Rule.php b/app/code/core/Mage/SalesRule/Model/Mysql4/Rule.php index cf2e0bcc59..c9cd3c773d 100644 --- a/app/code/core/Mage/SalesRule/Model/Mysql4/Rule.php +++ b/app/code/core/Mage/SalesRule/Model/Mysql4/Rule.php @@ -127,4 +127,64 @@ public function getStoreLabel($ruleId, $storeId) ->order('store_id DESC'); return $this->_getReadAdapter()->fetchOne($select); } + + /** + * Return codes of all product attributes currently used in promo rules for specified customer group and website + * + * @param unknown_type $websiteId + * @param unknown_type $customerGroupId + * @return mixed + */ + public function getActiveAttributes($websiteId, $customerGroupId) + { + $read = $this->_getReadAdapter(); + $select = $read->select() + ->from(array('a' => $this->getTable('salesrule/product_attribute')), + new Zend_Db_Expr('DISTINCT ea.attribute_code')) + ->joinInner(array('ea' => $this->getTable('eav/attribute')), 'ea.attribute_id = a.attribute_id', '') + ; + return $read->fetchAll($select); + } + + /** + * Save product attributes currently used in conditions and actions of rule + * + * @param Mage_SalesRule_Model_Rule $rule + * @param mixed $attributes + * return Mage_SalesRule_Model_Mysql4_Rule + */ + public function setActualProductAttributes($rule, $attributes) + { + $write = $this->_getWriteAdapter(); + $write->delete($this->getTable('salesrule/product_attribute'), + $write->quoteInto('rule_id=?', $rule->getId())); + + //Getting attribute IDs for attribute codes + $attributeIds = array(); + $select = $this->_getReadAdapter()->select() + ->from(array('a'=>$this->getTable('eav/attribute')), array('a.attribute_id')) + ->where('a.attribute_code IN (?)', array($attributes)); + $attributesFound = $this->_getReadAdapter()->fetchAll($select); + if ($attributesFound) { + foreach ($attributesFound as $attribute) { + $attributeIds[] = $attribute['attribute_id']; + } + + $data = array(); + foreach (explode(',', $rule->getCustomerGroupIds()) as $customerGroupId) { + foreach (explode(',', $rule->getWebsiteIds()) as $websiteId) { + foreach ($attributeIds as $attribute) { + $data[] = array ( + 'rule_id' => $rule->getId(), + 'website_id' => $websiteId, + 'customer_group_id' => $customerGroupId, + 'attribute_id' => $attribute + ); + } + } + } + $write->insertMultiple($this->getTable('salesrule/product_attribute'), $data); + } + return $this; + } } diff --git a/app/code/core/Mage/SalesRule/Model/Mysql4/Rule/Collection.php b/app/code/core/Mage/SalesRule/Model/Mysql4/Rule/Collection.php index 6c59a2995e..ec41f31e93 100644 --- a/app/code/core/Mage/SalesRule/Model/Mysql4/Rule/Collection.php +++ b/app/code/core/Mage/SalesRule/Model/Mysql4/Rule/Collection.php @@ -30,6 +30,7 @@ class Mage_SalesRule_Model_Mysql4_Rule_Collection extends Mage_Core_Model_Mysql4 protected function _construct() { $this->_init('salesrule/rule'); + $this->_map['fields']['rule_id'] = 'main_table.rule_id'; } public function setValidationFilter($websiteId, $customerGroupId, $couponCode='', $now=null) @@ -119,7 +120,7 @@ public function addAttributeInConditionFilter($attributeCode) $field = $this->_getMappedField('actions_serialized'); $aCond = $this->_getConditionSql($field, array('like' => $match)); - $this->getSelect()->where(sprintf('(%s OR %s)', $cCond, $aCond)); + $this->getSelect()->where(sprintf('(%s OR %s)', $cCond, $aCond), null, Varien_Db_Select::TYPE_CONDITION); return $this; } diff --git a/app/code/core/Mage/SalesRule/Model/Observer.php b/app/code/core/Mage/SalesRule/Model/Observer.php index 487d757d0a..6d80a14769 100644 --- a/app/code/core/Mage/SalesRule/Model/Observer.php +++ b/app/code/core/Mage/SalesRule/Model/Observer.php @@ -118,7 +118,7 @@ public function sales_order_afterPlace($observer) * Refresh sales coupons report statistics for last day * * @param Mage_Cron_Model_Schedule $schedule - * @return Mage_Tax_Model_Observer + * @return Mage_SalesRule_Model_Observer */ public function aggregateSalesReportCouponsData($schedule) { @@ -130,36 +130,34 @@ public function aggregateSalesReportCouponsData($schedule) return $this; } - /** - * After delete attribute check rules that contains deleted attribute - * If rules was found they will seted to inactive and added notice to admin session + * Check rules that contains affected attribute + * If rules were found they will be set to inactive and notice will be add to admin session * - * @param Varien_Event_Observer $observer - * @return Mage_CatalogRule_Model_Observer + * @param string $attributeCode + * @return Mage_SalesRule_Model_Observer */ - public function catalogAttributeDeleteAfter(Varien_Event_Observer $observer) + protected function _checkSalesRulesAvailability($attributeCode) { - $attribute = $observer->getEvent()->getAttribute(); - $attributeCode = $attribute->getAttributeCode(); - if ($attribute->getIsUsedForPromoRules()) { - /* @var $collection Mage_CatalogRule_Model_Mysql4_Rule_Collection */ - $collection = Mage::getResourceModel('salesrule/rule_collection') - ->addAttributeInConditionFilter($attributeCode); - $hasRule = false; - foreach ($collection as $rule) { - /* @var $rule Mage_CatalogRule_Model_Rule */ - $rule->setIsActive(0); - $this->_removeAttributeFromConditions($rule->getConditions(), $attributeCode); - $this->_removeAttributeFromConditions($rule->getActions(), $attributeCode); - $rule->save(); - $hasRule = true; - } + /* @var $collection Mage_SalesRule_Model_Mysql4_Rule_Collection */ + $collection = Mage::getResourceModel('salesrule/rule_collection') + ->addAttributeInConditionFilter($attributeCode); + + $disabledRulesCount = 0; + foreach ($collection as $rule) { + /* @var $rule Mage_SalesRule_Model_Rule */ + $rule->setIsActive(0); + /* @var $rule->getConditions() Mage_SalesRule_Model_Rule_Condition_Combine */ + $this->_removeAttributeFromConditions($rule->getConditions(), $attributeCode); + $this->_removeAttributeFromConditions($rule->getActions(), $attributeCode); + $rule->save(); + + $disabledRulesCount++; + } - if ($hasRule) { - Mage::getSingleton('adminhtml/session')->addWarning( - Mage::helper('salesrule')->__('Shopping Cart Price Rules based on deleted attribute "%s" has been disabled.', $attributeCode)); - } + if ($disabledRulesCount) { + Mage::getSingleton('adminhtml/session')->addWarning( + Mage::helper('salesrule')->__('%d Shopping Cart Price Rules based on "%s" attribute have been disabled.', $disabledRulesCount, $attributeCode)); } return $this; @@ -186,5 +184,62 @@ protected function _removeAttributeFromConditions($combine, $attributeCode) } $combine->setConditions($conditions); } + + /** + * After save attribute if it is not used for promo rules already check rules for containing this attribute + * + * @param Varien_Event_Observer $observer + * @return Mage_SalesRule_Model_Observer + */ + public function catalogAttributeSaveAfter(Varien_Event_Observer $observer) + { + $attribute = $observer->getEvent()->getAttribute(); + if ($attribute->dataHasChangedFor('is_used_for_promo_rules') && !$attribute->getIsUsedForPromoRules()) { + $this->_checkSalesRulesAvailability($attribute->getAttributeCode()); + } + + return $this; + } + + /** + * After delete attribute check rules that contains deleted attribute + * If rules was found they will seted to inactive and added notice to admin session + * + * @param Varien_Event_Observer $observer + * @return Mage_SalesRule_Model_Observer + */ + public function catalogAttributeDeleteAfter(Varien_Event_Observer $observer) + { + $attribute = $observer->getEvent()->getAttribute(); + if ($attribute->getIsUsedForPromoRules()) { + $this->_checkSalesRulesAvailability($attribute->getAttributeCode()); + } + + return $this; + } + + /** + * Append sales rule product attributes to select by quote item collection + * + * @param Varien_Event_Observer $observer + * @return Mage_SalesRule_Model_Observer + */ + public function addProductAttributes(Varien_Event_Observer $observer) + { + // @var Varien_Object + $attributesTransfer = $observer->getEvent()->getAttributes(); + + $attributes = Mage::getResourceModel('salesrule/rule') + ->getActiveAttributes( + Mage::app()->getWebsite()->getId(), + Mage::getSingleton('customer/session')->getCustomer()->getGroupId() + ); + $result = array(); + foreach ($attributes as $attribute) { + $result[$attribute['attribute_code']] = true; + } + $attributesTransfer->addData($result); + return $this; + } } diff --git a/app/code/core/Mage/SalesRule/Model/Quote/Discount.php b/app/code/core/Mage/SalesRule/Model/Quote/Discount.php index 5ae2ac42b2..63b24d5ba1 100644 --- a/app/code/core/Mage/SalesRule/Model/Quote/Discount.php +++ b/app/code/core/Mage/SalesRule/Model/Quote/Discount.php @@ -64,6 +64,8 @@ public function collect(Mage_Sales_Model_Quote_Address $address) ); $this->_calculator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode()); + $this->_calculator->initTotals($items, $address); + $address->setDiscountDescription(array()); foreach ($items as $item) { diff --git a/app/code/core/Mage/SalesRule/Model/Quote/Freeshipping.php b/app/code/core/Mage/SalesRule/Model/Quote/Freeshipping.php index f934e0a7a6..d942bc5b14 100644 --- a/app/code/core/Mage/SalesRule/Model/Quote/Freeshipping.php +++ b/app/code/core/Mage/SalesRule/Model/Quote/Freeshipping.php @@ -59,8 +59,10 @@ public function collect(Mage_Sales_Model_Quote_Address $address) } $this->_calculator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode()); + $isAllFree = true; foreach ($items as $item) { if ($item->getNoDiscount()) { + $isAllFree = false; $item->setFreeShipping(false); } else { /** @@ -70,20 +72,25 @@ public function collect(Mage_Sales_Model_Quote_Address $address) continue; } $this->_calculator->processFreeShipping($item); + $isItemFree = (bool)$item->getFreeShipping(); + $isAllFree = $isAllFree && $isItemFree; if ($item->getHasChildren() && $item->isChildrenCalculated()) { foreach ($item->getChildren() as $child) { $this->_calculator->processFreeShipping($child); /** * Parent free shipping we apply to all children */ - if ($item->getFreeShipping()) { - $child->setFreeShipping($item->getFreeShipping()); + if ($isItemFree) { + $child->setFreeShipping($isItemFree); } } } } } + if ($isAllFree && !$address->getFreeShipping()) { + $address->setFreeShipping(true); + } return $this; } diff --git a/app/code/core/Mage/SalesRule/Model/Rule.php b/app/code/core/Mage/SalesRule/Model/Rule.php index dbd4ed570c..0a9544a844 100644 --- a/app/code/core/Mage/SalesRule/Model/Rule.php +++ b/app/code/core/Mage/SalesRule/Model/Rule.php @@ -34,6 +34,17 @@ class Mage_SalesRule_Model_Rule extends Mage_Rule_Model_Rule const COUPON_TYPE_SPECIFIC = 2; const COUPON_TYPE_AUTO = 3; + /** + * Rule type actions + */ + const TO_PERCENT_ACTION = 'to_percent'; + const BY_PERCENT_ACTION = 'by_percent'; + const TO_FIXED_ACTION = 'to_fixed'; + const BY_FIXED_ACTION = 'by_fixed'; + const CART_FIXED_ACTION = 'cart_fixed'; + const BUY_X_GET_Y_ACTION = 'buy_x_get_y'; + + /** * @var Mage_SalesRule_Model_Coupon_CodegeneratorInterface */ @@ -206,7 +217,7 @@ public function getResourceCollection() } /** - * Save rule labels after rule save + * Save rule labels after rule save and process product attributes used in actions and conditions * * @return Mage_SalesRule_Model_Rule */ @@ -226,6 +237,15 @@ protected function _afterSave() } else { $this->getPrimaryCoupon()->delete(); } + + //Saving attributes used in rule + $ruleProductAttributes = array_merge( + $this->_getUsedAttributes($this->getConditionsSerialized()), + $this->_getUsedAttributes($this->getActionsSerialized()) + ); + if (count($ruleProductAttributes)) { + $this->getResource()->setActualProductAttributes($this, $ruleProductAttributes); + } return parent::_afterSave(); } @@ -352,4 +372,22 @@ public function acquireCoupon($saveNewlyCreated = true, $saveAttemptCount = 10) return $coupon; } + + /** + * Return all product attributes used on serialized action or condition + * + * @param string $serializedString + * @return array + */ + protected function _getUsedAttributes($serializedString) + { + $result = array(); + if (preg_match_all('~s:32:"salesrule/rule_condition_product";s:9:"attribute";s:\d+:"(.*?)"~s', + $serializedString, $matches)){ + foreach ($matches[1] as $offset => $attributeCode) { + $result[] = $attributeCode; + } + } + return $result; + } } diff --git a/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product.php b/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product.php index 4a6eeff7f0..1f369a8664 100644 --- a/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product.php +++ b/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product.php @@ -44,11 +44,18 @@ protected function _addSpecialAttributes(array &$attributes) */ public function validate(Varien_Object $object) { - $product = Mage::getModel('catalog/product') - ->load($object->getProductId()) + $product = false; + if ($object->getProduct() instanceof Mage_Catalog_Model_Product) { + $product = $object->getProduct(); + } else { + $product = Mage::getModel('catalog/product') + ->load($object->getProductId()); + } + + $product ->setQuoteItemQty($object->getQty()) - ->setQuoteItemPrice($object->getPrice()) - ->setQuoteItemRowTotal($object->getRowTotal()); + ->setQuoteItemPrice($object->getPrice()) // possible bug: need to use $object->getBasePrice() + ->setQuoteItemRowTotal($object->getBaseRowTotal()); return parent::validate($product); } diff --git a/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product/Subselect.php b/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product/Subselect.php index ce769b7017..1a4dfe1f05 100644 --- a/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product/Subselect.php +++ b/app/code/core/Mage/SalesRule/Model/Rule/Condition/Product/Subselect.php @@ -67,7 +67,7 @@ public function loadAttributeOptions() $hlp = Mage::helper('salesrule'); $this->setAttributeOption(array( 'qty' => $hlp->__('total quantity'), - 'row_total' => $hlp->__('total amount'), + 'base_row_total' => $hlp->__('total amount'), )); return $this; } diff --git a/app/code/core/Mage/SalesRule/Model/Validator.php b/app/code/core/Mage/SalesRule/Model/Validator.php index bc6d084a9a..f3283be909 100644 --- a/app/code/core/Mage/SalesRule/Model/Validator.php +++ b/app/code/core/Mage/SalesRule/Model/Validator.php @@ -54,11 +54,11 @@ class Mage_SalesRule_Model_Validator extends Mage_Core_Model_Abstract */ protected $_isFirstTimeProcessRun = false; - protected function _construct() - { - parent::_construct(); - $this->_init('salesrule/validator'); - } + /** + * Information about item totals for rules. + * @var array + */ + protected $_rulesItemTotals = array(); /** * Init validator @@ -242,12 +242,11 @@ public function process(Mage_Sales_Model_Quote_Item_Abstract $item) $address->setAppliedRuleIds(''); } - $itemPrice = $item->getDiscountCalculationPrice(); - if ($itemPrice !== null) { - $baseItemPrice = $item->getBaseDiscountCalculationPrice(); - } else { - $itemPrice = $item->getCalculationPrice(); - $baseItemPrice = $item->getBaseCalculationPrice(); + $itemPrice = $this->_getItemPrice($item); + $baseItemPrice = $this->_getItemBasePrice($item); + + if ($itemPrice <= 0) { + return $this; } $appliedRuleIds = array(); @@ -260,17 +259,17 @@ public function process(Mage_Sales_Model_Quote_Item_Abstract $item) if (!$rule->getActions()->validate($item)) { continue; } - $qty = $item->getTotalQty(); - $qty = $rule->getDiscountQty() ? min($qty, $rule->getDiscountQty()) : $qty; + + $qty = $this->_getItemQty($item, $rule); $rulePercent = min(100, $rule->getDiscountAmount()); $discountAmount = 0; $baseDiscountAmount = 0; switch ($rule->getSimpleAction()) { - case 'to_percent': + case Mage_SalesRule_Model_Rule::TO_PERCENT_ACTION: $rulePercent = max(0, 100-$rule->getDiscountAmount()); //no break; - case 'by_percent': + case Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION: $step = $rule->getDiscountStep(); if ($step) { $qty = floor($qty/$step)*$step; @@ -283,13 +282,13 @@ public function process(Mage_Sales_Model_Quote_Item_Abstract $item) $item->setDiscountPercent($discountPercent); } break; - case 'to_fixed': + case Mage_SalesRule_Model_Rule::TO_FIXED_ACTION: $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount()); $discountAmount = $qty*($itemPrice-$quoteAmount); $baseDiscountAmount= $qty*($baseItemPrice-$rule->getDiscountAmount()); break; - case 'by_fixed': + case Mage_SalesRule_Model_Rule::BY_FIXED_ACTION: $step = $rule->getDiscountStep(); if ($step) { $qty = floor($qty/$step)*$step; @@ -299,42 +298,53 @@ public function process(Mage_Sales_Model_Quote_Item_Abstract $item) $baseDiscountAmount = $qty*$rule->getDiscountAmount(); break; - case 'cart_fixed': + case Mage_SalesRule_Model_Rule::CART_FIXED_ACTION: + if (empty($this->_rulesItemTotals[$rule->getId()])) { + Mage::throwException(Mage::helper('salesrule')->__('Item totals are not set for rule.')); + } $cartRules = $address->getCartFixedRules(); if (!isset($cartRules[$rule->getId()])) { $cartRules[$rule->getId()] = $rule->getDiscountAmount(); } + if ($cartRules[$rule->getId()] > 0) { - $quoteAmount = $quote->getStore()->convertPrice($cartRules[$rule->getId()]); - /** - * We can't use row total here because row total not include tax - */ - $discountAmount = min($itemPrice*$qty - $item->getDiscountAmount(), $quoteAmount); - $baseDiscountAmount = min($baseItemPrice*$qty - $item->getBaseDiscountAmount(), $cartRules[$rule->getId()]); + if (1 >= $this->_rulesItemTotals[$rule->getId()]['items_count']) { + $quoteAmount = $quote->getStore()->convertPrice($cartRules[$rule->getId()]); + + $discountAmount = min($itemPrice * $qty, $quoteAmount); + $baseDiscountAmount = min($baseItemPrice * $qty, $cartRules[$rule->getId()]); + } else { + $discountRate = $baseItemPrice * $qty / $this->_rulesItemTotals[$rule->getId()]['base_items_price']; + $maximumItemDiscount = $rule->getDiscountAmount() * $discountRate; + $quoteAmount = $quote->getStore()->convertPrice($maximumItemDiscount); + + $discountAmount = min($itemPrice * $qty, $quoteAmount); + $baseDiscountAmount = min($baseItemPrice * $qty, $maximumItemDiscount); + $this->_rulesItemTotals[$rule->getId()]['items_count']--; + } $cartRules[$rule->getId()] -= $baseDiscountAmount; } $address->setCartFixedRules($cartRules); break; - case 'buy_x_get_y': + case Mage_SalesRule_Model_Rule::BUY_X_GET_Y_ACTION: $x = $rule->getDiscountStep(); $y = $rule->getDiscountAmount(); if (!$x || $y>=$x) { break; } - $buy = 0; $free = 0; - while ($buy+$free<$qty) { - $buy += $x; - if ($buy+$free>=$qty) { - break; - } - $free += min($y, $qty-$buy-$free); - if ($buy+$free>=$qty) { - break; - } + $buyAndDiscountQty = $x + $y; + + $fullRuleQtyPeriod = floor($qty / $buyAndDiscountQty); + $freeQty = $qty - $fullRuleQtyPeriod * $buyAndDiscountQty; + + $discountQty = $fullRuleQtyPeriod * $y; + if ($freeQty > $x) { + $discountQty += $freeQty - $x; } - $discountAmount = $free*$itemPrice; - $baseDiscountAmount= $free*$baseItemPrice; + + $discountAmount = $discountQty * $itemPrice; + $baseDiscountAmount= $discountQty * $baseItemPrice; break; } @@ -424,26 +434,26 @@ public function processShippingAmount(Mage_Sales_Model_Quote_Address $address) $baseDiscountAmount = 0; $rulePercent = min(100, $rule->getDiscountAmount()); switch ($rule->getSimpleAction()) { - case 'to_percent': + case Mage_SalesRule_Model_Rule::TO_PERCENT_ACTION: $rulePercent = max(0, 100-$rule->getDiscountAmount()); - case 'by_percent': + case Mage_SalesRule_Model_Rule::BY_PERCENT_ACTION: $discountAmount = ($shippingAmount - $address->getShippingDiscountAmount()) * $rulePercent/100; $baseDiscountAmount= ($baseShippingAmount - $address->getBaseShippingDiscountAmount()) * $rulePercent/100; $discountPercent = min(100, $address->getShippingDiscountPercent()+$rulePercent); $address->setShippingDiscountPercent($discountPercent); break; - case 'to_fixed': + case Mage_SalesRule_Model_Rule::TO_FIXED_ACTION: $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount()); $discountAmount = $shippingAmount-$quoteAmount; $baseDiscountAmount= $baseShippingAmount-$rule->getDiscountAmount(); break; - case 'by_fixed': + case Mage_SalesRule_Model_Rule::BY_FIXED_ACTION: $quoteAmount = $quote->getStore()->convertPrice($rule->getDiscountAmount()); $discountAmount = $quoteAmount; $baseDiscountAmount = $rule->getDiscountAmount(); break; - case 'cart_fixed': + case Mage_SalesRule_Model_Rule::CART_FIXED_ACTION: $cartRules = $address->getCartFixedRules(); if (!isset($cartRules[$rule->getId()])) { $cartRules[$rule->getId()] = $rule->getDiscountAmount(); @@ -490,6 +500,49 @@ public function mergeIds($a1, $a2, $asString=true) return $a; } + /** + * Calculate quote totals for each rule and save results + * + * @param mixed $items + * @param Mage_Sales_Model_Quote_Address $address + * @return Mage_SalesRule_Model_Validator + */ + public function initTotals($items, Mage_Sales_Model_Quote_Address $address) + { + $address->setCartFixedRules(array()); + + if (!$items) { + return $this; + } + + foreach ($this->_getRules() as $rule) { + if (Mage_SalesRule_Model_Rule::CART_FIXED_ACTION == $rule->getSimpleAction() + && $this->_canProcessRule($rule, $address)) { + + $ruleTotalItemsPrice = 0; + $ruleTotalBaseItemsPrice = 0; + $validItemsCount = 0; + + foreach ($items as $item) { + if (!$rule->getActions()->validate($item)) { + continue; + } + $qty = $this->_getItemQty($item, $rule); + $ruleTotalItemsPrice += $this->_getItemPrice($item) * $qty; + $ruleTotalBaseItemsPrice += $this->_getItemBasePrice($item) * $qty; + $validItemsCount++; + } + + $this->_rulesItemTotals[$rule->getId()] = array( + 'items_price' => $ruleTotalItemsPrice, + 'base_items_price' => $ruleTotalBaseItemsPrice, + 'items_count' => $validItemsCount, + ); + } + } + return $this; + } + /** * Retrieve subordinate coupon IDs * @@ -530,6 +583,43 @@ protected function _addDiscountDescription($address, $rule) return $this; } + /** + * Return item price + * + * @param Mage_Sales_Model_Quote_Item_Abstract $item + * @return float + */ + protected function _getItemPrice($item) + { + $price = $item->getDiscountCalculationPrice(); + return ($price !== null) ? $price : $item->getCalculationPrice(); + } + + /** + * Return item base price + * + * @param Mage_Sales_Model_Quote_Item_Abstract $item + * @return float + */ + protected function _getItemBasePrice($item) + { + $price = $item->getDiscountCalculationPrice(); + return ($price !== null) ? $item->getBaseDiscountCalculationPrice() : $item->getBaseCalculationPrice(); + } + + /** + * Return discount item qty + * + * @param Mage_Sales_Model_Quote_Item_Abstract $item + * @param Mage_SalesRule_Model_Rule $rule + * @return int + */ + protected function _getItemQty($item, $rule) + { + $qty = $item->getTotalQty(); + return $rule->getDiscountQty() ? min($qty, $rule->getDiscountQty()) : $qty; + } + /** * Convert address discount description array to string * @@ -550,4 +640,7 @@ public function prepareDescription($address, $separator=', ') $address->setDiscountDescription($description); return $this; } + + + } diff --git a/app/code/core/Mage/SalesRule/etc/config.xml b/app/code/core/Mage/SalesRule/etc/config.xml index bef9cb4417..aacdaa7325 100644 --- a/app/code/core/Mage/SalesRule/etc/config.xml +++ b/app/code/core/Mage/SalesRule/etc/config.xml @@ -28,7 +28,7 @@ - 1.4.0.0.4 + 1.4.0.0.6 @@ -56,6 +56,7 @@ coupon_aggregated_order
    + salesrule_product_attribute
    @@ -83,6 +84,14 @@ + + + + salesrule/observer + addProductAttributes + + + @@ -126,6 +135,14 @@ + + + + salesrule/observer + catalogAttributeSaveAfter + + + diff --git a/app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.4-1.4.0.0.5.php b/app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.4-1.4.0.0.5.php new file mode 100644 index 0000000000..f47ad91dcc --- /dev/null +++ b/app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.4-1.4.0.0.5.php @@ -0,0 +1,67 @@ +run(" +CREATE TABLE `{$this->getTable('salesrule/product_attribute')}` ( + `rule_id` int(10) unsigned NOT NULL, + `website_id` smallint(5) unsigned NOT NULL, + `customer_group_id` smallint(5) unsigned NOT NULL, + `attribute_id` smallint(5) unsigned NOT NULL, + PRIMARY KEY (`rule_id`,`website_id`,`customer_group_id`,`attribute_id`), + KEY `IDX_WEBSITE` (`website_id`), + KEY `IDX_CUSTOMER_GROUP` (`customer_group_id`), + KEY `IDX_ATTRIBUTE` (`attribute_id`), + CONSTRAINT `FK_SALESRULE_PRODUCT_ATTRIBUTE_ATTRIBUTE` FOREIGN KEY (`attribute_id`) REFERENCES `{$this->getTable('eav/attribute')}` (`attribute_id`) ON DELETE CASCADE, + CONSTRAINT `FK_SALESRULE_PRODUCT_ATTRIBUTE_CUSTOMER_GROUP` FOREIGN KEY (`customer_group_id`) REFERENCES `{$this->getTable('customer/customer_group')}` (`customer_group_id`) ON DELETE CASCADE, + CONSTRAINT `FK_SALESRULE_PRODUCT_ATTRIBUTE_RULE` FOREIGN KEY (`rule_id`) REFERENCES `{$this->getTable('salesrule/rule')}` (`rule_id`) ON DELETE CASCADE, + CONSTRAINT `FK_SALESRULE_PRODUCT_ATTRIBUTE_WEBSITE` FOREIGN KEY (`website_id`) REFERENCES `{$this->getTable('core/website')}` (`website_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +"); + +/** + * We need to fill new table with product attributes already used in promo rules + */ +$installer->run(" +INSERT INTO `{$this->getTable('salesrule/product_attribute')}` + SELECT + sr.rule_id, + cw.website_id, + cg.customer_group_id, + ea.attribute_id + FROM `{$this->getTable('salesrule/rule')}` AS sr + INNER JOIN `{$this->getTable('core/website')}` AS cw + ON FIND_IN_SET(cw.website_id, sr.website_ids) + INNER JOIN `{$this->getTable('customer/customer_group')}` AS cg + ON FIND_IN_SET(cg.customer_group_id , sr.customer_group_ids) + INNER JOIN `{$this->getTable('eav/attribute')}` AS ea + ON ea.entity_type_id = {$installer->getEntityTypeId('catalog_product')} + WHERE + sr.conditions_serialized LIKE CONCAT('%s:32:\"salesrule/rule_condition_product\";s:9:\"attribute\";s:', LENGTH(ea.attribute_code), ':\"', ea.attribute_code, '\"%') + OR sr.actions_serialized LIKE CONCAT('%s:32:\"salesrule/rule_condition_product\";s:9:\"attribute\";s:', LENGTH(ea.attribute_code), ':\"', ea.attribute_code, '\"%') +"); diff --git a/app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.5-1.4.0.0.6.php b/app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.5-1.4.0.0.6.php new file mode 100644 index 0000000000..f5c8fb14a7 --- /dev/null +++ b/app/code/core/Mage/SalesRule/sql/salesrule_setup/mysql4-upgrade-1.4.0.0.5-1.4.0.0.6.php @@ -0,0 +1,52 @@ +startSetup(); + +$installer->getConnection()->dropForeignKey( + $installer->getTable('salesrule/coupon_usage'), + 'FK_SALESRULE_COUPON_CUSTOMER_COUPON_ID_CUSTOMER_ENTITY' +); + +$installer->getConnection()->dropForeignKey( + $installer->getTable('salesrule/coupon_usage'), + 'FK_SALESRULE_COUPON_CUSTOMER_CUSTOMER_ID_CUSTOMER_ENTITY' +); + +$installer->getConnection()->addConstraint('FK_SALESRULE_CPN_CUST_CPN_ID_CUST_ENTITY', + $installer->getTable('salesrule/coupon_usage'), 'coupon_id', + $installer->getTable('salesrule/coupon'), 'coupon_id' +); + + +$installer->getConnection()->addConstraint('FK_SALESRULE_CPN_CUST_CUST_ID_CUST_ENTITY', + $installer->getTable('salesrule/coupon_usage'), 'customer_id', + $installer->getTable('customer_entity'), 'entity_id' +); + +$installer->endSetup(); diff --git a/app/code/core/Mage/Shipping/Block/Tracking/Popup.php b/app/code/core/Mage/Shipping/Block/Tracking/Popup.php index d4b9d03ba9..9a944f8c36 100644 --- a/app/code/core/Mage/Shipping/Block/Tracking/Popup.php +++ b/app/code/core/Mage/Shipping/Block/Tracking/Popup.php @@ -129,7 +129,10 @@ protected function _initShipment() */ public function getTrackingInfo() { - return Mage::registry('current_shipping_info')->getTrackingInfo(); + /* @var $info Mage_Shipping_Model_Info */ + $info = Mage::registry('current_shipping_info'); + + return $info->getTrackingInfo(); } /** @@ -215,8 +218,10 @@ public function formatDeliveryDateTime($date, $time) */ public function formatDeliveryDate($date) { - $format = Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM); - return Mage::app()->getLocale()->date(strtotime($date), Zend_Date::TIMESTAMP, null, false) + /* @var $locale Mage_Core_Model_Locale */ + $locale = Mage::app()->getLocale(); + $format = $locale->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM); + return $locale->date(strtotime($date), Zend_Date::TIMESTAMP, null, false) ->toString($format); } @@ -232,8 +237,12 @@ public function formatDeliveryTime($time, $date = null) if (!empty($date)) { $time = $date . ' ' . $time; } - $format = Mage::app()->getLocale()->getTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT); - return Mage::app()->getLocale()->date(strtotime($time), Zend_Date::TIMESTAMP, null, false) + + /* @var $locale Mage_Core_Model_Locale */ + $locale = Mage::app()->getLocale(); + + $format = $locale->getTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT); + return $locale->date(strtotime($time), Zend_Date::TIMESTAMP, null, false) ->toString($format); } diff --git a/app/code/core/Mage/Shipping/Helper/Data.php b/app/code/core/Mage/Shipping/Helper/Data.php index 9958c846ec..e17e253f68 100644 --- a/app/code/core/Mage/Shipping/Helper/Data.php +++ b/app/code/core/Mage/Shipping/Helper/Data.php @@ -72,7 +72,8 @@ protected function _getTrackingUrl($key, $model, $method = 'getId') 'hash' => Mage::helper('core')->urlEncode("{$key}:{$model->$method()}:{$model->getProtectCode()}") ); } - $storeModel = Mage::app()->getStore($model->getStoreId()); + $storeId = is_object($model) ? $model->getStoreId() : null; + $storeModel = Mage::app()->getStore($storeId); return $storeModel->getUrl('shipping/tracking/popup', $param); } @@ -85,6 +86,9 @@ protected function _getTrackingUrl($key, $model, $method = 'getId') */ public function getTrackingPopUpUrlByOrderId($order = '') { + if ($order && !is_object($order)) { + $order = Mage::getModel('sales/order')->load($order); + } return $this->_getTrackingUrl('order_id', $order); } @@ -97,6 +101,9 @@ public function getTrackingPopUpUrlByOrderId($order = '') */ public function getTrackingPopUpUrlByTrackId($track = '') { + if ($track && !is_object($track)) { + $track = Mage::getModel('sales/order_shipment_track')->load($track); + } return $this->_getTrackingUrl('track_id', $track, 'getEntityId'); } @@ -109,6 +116,9 @@ public function getTrackingPopUpUrlByTrackId($track = '') */ public function getTrackingPopUpUrlByShipId($ship = '') { + if ($ship && !is_object($ship)) { + $ship = Mage::getModel('sales/order_shipment')->load($ship); + } return $this->_getTrackingUrl('ship_id', $ship); } diff --git a/app/code/core/Mage/Shipping/Model/Carrier/Abstract.php b/app/code/core/Mage/Shipping/Model/Carrier/Abstract.php index 24bce14b3e..2361607041 100644 --- a/app/code/core/Mage/Shipping/Model/Carrier/Abstract.php +++ b/app/code/core/Mage/Shipping/Model/Carrier/Abstract.php @@ -156,6 +156,10 @@ public function getSortOrder() return $this->getConfigData('sort_order'); } + /** + * @param Mage_Shipping_Model_Rate_Request $request + * @return void + */ protected function _updateFreeMethodQuote($request) { if ($request->getFreeMethodWeight()==$request->getPackageWeight() diff --git a/app/code/core/Mage/Shipping/Model/Carrier/Tablerate.php b/app/code/core/Mage/Shipping/Model/Carrier/Tablerate.php index 92a78f4a48..286af389db 100644 --- a/app/code/core/Mage/Shipping/Model/Carrier/Tablerate.php +++ b/app/code/core/Mage/Shipping/Model/Carrier/Tablerate.php @@ -120,7 +120,11 @@ public function collectRates(Mage_Shipping_Model_Rate_Request $request) $method->setMethod('bestway'); $method->setMethodTitle($this->getConfigData('name')); - $shippingPrice = $this->getFinalPriceWithHandlingFee($rate['price']); + if ($request->getFreeShipping() === true || ($request->getPackageQty() == $freeQty)) { + $shippingPrice = 0; + } else { + $shippingPrice = $this->getFinalPriceWithHandlingFee($rate['price']); + } $method->setPrice($shippingPrice); $method->setCost($rate['cost']); diff --git a/app/code/core/Mage/Shipping/Model/Info.php b/app/code/core/Mage/Shipping/Model/Info.php index 1e57f6106d..95010123f3 100644 --- a/app/code/core/Mage/Shipping/Model/Info.php +++ b/app/code/core/Mage/Shipping/Model/Info.php @@ -42,7 +42,9 @@ class Mage_Shipping_Model_Info extends Varien_Object */ public function loadByHash($hash) { - $data = Mage::helper('shipping')->decodeTrackingHash($hash); + /* @var $helper Mage_Shipping_Helper_Data */ + $helper = Mage::helper('shipping'); + $data = $helper->decodeTrackingHash($hash); if (!empty($data)) { $this->setData($data['key'], $data['id']); $this->setProtectCode($data['hash']); @@ -91,8 +93,9 @@ protected function _initOrder() */ protected function _initShipment() { - $ship = Mage::getModel('sales/order_shipment')->load($this->getShipId()); - + /* @var $model Mage_Sales_Model_Order_Shipment */ + $model = Mage::getModel('sales/order_shipment'); + $ship = $model->load($this->getShipId()); if (!$ship->getEntityId() || $this->getProtectCode() != $ship->getProtectCode()) { return false; } diff --git a/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate.php b/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate.php index 095b6f8a4e..ba19d9db93 100644 --- a/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate.php +++ b/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate.php @@ -33,274 +33,427 @@ */ class Mage_Shipping_Model_Mysql4_Carrier_Tablerate extends Mage_Core_Model_Mysql4_Abstract { + /** + * Import table rates website ID + * + * @var int + */ + protected $_importWebsiteId = 0; + + /** + * Errors in import process + * + * @var array + */ + protected $_importErrors = array(); + + /** + * Count of imported table rates + * + * @var int + */ + protected $_importedRows = 0; + + /** + * Array of unique table rate keys to protect from duplicates + * + * @var array + */ + protected $_importUniqueHash = array(); + + /** + * Array of countries keyed by iso2 code + * + * @var array + */ + protected $_importIso2Countries; + + /** + * Array of countries keyed by iso3 code + * + * @var array + */ + protected $_importIso3Countries; + + /** + * Associative array of countries and regions + * [country_id][region_code] = region_id + * + * @var array + */ + protected $_importRegions; + + /** + * Import Table Rate condition name + * + * @var string + */ + protected $_importConditionName; + + /** + * Array of condition full names + * + * @var array + */ + protected $_conditionFullNames = array(); + + /** + * Define main table and id field name + * + * @return void + */ protected function _construct() { $this->_init('shipping/tablerate', 'pk'); } + /** + * Return table rate array or false by rate request + * + * @param Mage_Shipping_Model_Rate_Request $request + * @return array|false + */ public function getRate(Mage_Shipping_Model_Rate_Request $request) { - $read = $this->_getReadAdapter(); - $write = $this->_getWriteAdapter(); - - $select = $read->select()->from($this->getMainTable()); - /* - //commented out code since we don't want to get state by using zip code - if (!$request->getDestCountryId() && !$request->getDestRegionId()) { - - // assuming that request is coming from shopping cart - // for shipping prices pre-estimation... - - // also probably it will be required to move this part to - // Sales/Model/Quote/Address.php ! - - $selectCountry = $read->select()->from(Mage::getSingleton('core/resource')->getTableName('usa/postcode'), array('country_id', 'region_id')); - $selectCountry->where('postcode=?', $request->getDestPostcode()); - $selectCountry->limit(1); - $countryRegion = $read->fetchRow($selectCountry); - $region = $read->quote($countryRegion['region_id']); - $country = $read->quote($countryRegion['country_id']); - } else { - $region = $read->quote($request->getDestRegionId()); - $country = $read->quote($request->getDestCountryId()); - } - */ -// $bind = array( -// 'zip' => $read->quote($request->getDestPostcode()), -// 'region' => $read->quote($request->getDestRegionId()), -// 'country' => $read->quote($request->getDestCountryId()) -// ); - $select->where( - $read->quoteInto(" (dest_country_id=? ", $request->getDestCountryId()). - $read->quoteInto(" AND dest_region_id=? ", $request->getDestRegionId()). - $read->quoteInto(" AND dest_zip=?) ", $request->getDestPostcode()). - - $read->quoteInto(" OR (dest_country_id=? ", $request->getDestCountryId()). - $read->quoteInto(" AND dest_region_id=? AND dest_zip='') ", $request->getDestRegionId()). - - $read->quoteInto(" OR (dest_country_id=? AND dest_region_id='0' AND dest_zip='') ", $request->getDestCountryId()). - - $read->quoteInto(" OR (dest_country_id=? AND dest_region_id='0' ", $request->getDestCountryId()). - $read->quoteInto(" AND dest_zip=?) ", $request->getDestPostcode()). - - " OR (dest_country_id='0' AND dest_region_id='0' AND dest_zip='')" + $adapter = $this->_getReadAdapter(); + $bind = array( + ':website_id' => (int)$request->getWebsiteId(), + ':country_id' => $request->getDestCountryId(), + ':region_id' => $request->getDestRegionId(), + ':postcode' => $request->getDestPostcode() ); - -// $select->where("(dest_zip=:zip) -// OR (dest_region_id=:region AND dest_zip='') -// OR (dest_country_id=:country AND dest_region_id='0' AND dest_zip='') -// OR (dest_country_id='0' AND dest_region_id='0' AND dest_zip='')"); + $select = $adapter->select() + ->from($this->getMainTable()) + ->where('website_id=:website_id') + ->order(array('dest_country_id DESC', 'dest_region_id DESC', 'dest_zip DESC')) + ->limit(1); + + // render destination condition + $orWhere = '(' . implode(') OR (', array( + "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = :postcode", + "dest_country_id = :country_id AND dest_region_id = :region_id AND dest_zip = ''", + "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = ''", + "dest_country_id = :country_id AND dest_region_id = 0 AND dest_zip = :postcode", + "dest_country_id = '0' AND dest_region_id = 0 AND dest_zip = ''", + )) . ')'; + $select->where($orWhere); + + // render condition by condition name if (is_array($request->getConditionName())) { - $i = 0; + $orWhere = array(); + $i = 0; foreach ($request->getConditionName() as $conditionName) { - if ($i == 0) { - $select->where('condition_name=?', $conditionName); - } else { - $select->orWhere('condition_name=?', $conditionName); - } - $select->where('condition_value<=?', $request->getData($conditionName)); - $i++; + $bindNameKey = sprintf(':condition_name_%d', $i); + $bindValueKey = sprintf(':condition_value_%d', $i); + $orWhere[] = "(condition_name = {$bindNameKey} AND condition_value <= {$bindValueKey})"; + $bind[$bindNameKey] = $conditionName; + $bind[$bindValueKey] = $request->getData($conditionName); + $i ++; + } + + if ($orWhere) { + $select->where(implode(' OR ', $orWhere)); } } else { - $select->where('condition_name=?', $request->getConditionName()); - $select->where('condition_value<=?', $request->getData($request->getConditionName())); + $bind[':condition_name'] = $request->getConditionName(); + $bind[':condition_value'] = $request->getData($request->getConditionName()); + + $select->where('condition_name = :condition_name'); + $select->where('condition_value <= :condition_value'); } - $select->where('website_id=?', $request->getWebsiteId()); - - $select->order('dest_country_id DESC'); - $select->order('dest_region_id DESC'); - $select->order('dest_zip DESC'); - $select->order('condition_value DESC'); - $select->limit(1); - - /* - pdo has an issue. we cannot use bind - */ - $row = $read->fetchRow($select); - return $row; + + return $adapter->fetchRow($select, $bind); } /** * Upload table rate file and import data from it * * @param Varien_Object $object - * @return bool|Mage_Shipping_Model_Mysql4_Carrier_Tablerate + * @throws Mage_Core_Exception + * @return Mage_Shipping_Model_Mysql4_Carrier_Tablerate */ public function uploadAndImport(Varien_Object $object) { - if (!isset($_FILES['groups'])) { - return false; + if (empty($_FILES['groups']['tmp_name']['tablerate']['fields']['import']['value'])) { + return $this; } + $csvFile = $_FILES['groups']['tmp_name']['tablerate']['fields']['import']['value']; + $website = Mage::app()->getWebsite($object->getScopeId()); + + $this->_importWebsiteId = (int)$website->getId(); + $this->_importUniqueHash = array(); + $this->_importErrors = array(); + $this->_importedRows = 0; + + $io = new Varien_Io_File(); + $info = pathinfo($csvFile); + $io->open(array('path' => $info['dirname'])); + $io->streamOpen($info['basename'], 'r'); + + // check and skip headers + $headers = $io->streamReadCsv(); + if ($headers === false || count($headers) < 5) { + $io->streamClose(); + Mage::throwException(Mage::helper('shipping')->__('Invalid Table Rates File Format')); + } - if (!empty($csvFile)) { + if ($object->getData('groups/tablerate/fields/condition_name/inherit') == '1') { + $conditionName = (string)Mage::getConfig()->getNode('default/carriers/tablerate/condition_name'); + } else { + $conditionName = $object->getData('groups/tablerate/fields/condition_name/value'); + } + $this->_importConditionName = $conditionName; - $csv = trim(file_get_contents($csvFile)); + $adapter = $this->_getWriteAdapter(); + $adapter->beginTransaction(); - $table = Mage::getSingleton('core/resource')->getTableName('shipping/tablerate'); + try { + $rowNumber = 1; + $importData = array(); - $websiteId = $object->getScopeId(); - $websiteModel = Mage::app()->getWebsite($websiteId); - /* - getting condition name from post instead of the following commented logic - */ + $this->_loadDirectoryCountries(); + $this->_loadDirectoryRegions(); - if (isset($_POST['groups']['tablerate']['fields']['condition_name']['inherit'])) { - $conditionName = (string)Mage::getConfig()->getNode('default/carriers/tablerate/condition_name'); - } else { - $conditionName = $_POST['groups']['tablerate']['fields']['condition_name']['value']; - } + // delete old data by website and condition name + $condition = array( + 'website_id = ?' => $this->_importWebsiteId, + 'condition_name = ?' => $this->_importConditionName + ); + $adapter->delete($this->getMainTable(), $condition); -// $conditionName = $object->getValue(); -// if ($conditionName{0} == '_') { -// $conditionName = Mage::helper('core/string')->substr($conditionName, 1, strpos($conditionName, '/')-1); -// } else { -// $conditionName = $websiteModel->getConfig('carriers/tablerate/condition_name'); -// } - $conditionFullName = Mage::getModel('shipping/carrier_tablerate')->getCode('condition_name_short', $conditionName); - if (!empty($csv)) { - $exceptions = array(); - $csvLines = explode("\n", $csv); - $csvLine = array_shift($csvLines); - $csvLine = $this->_getCsvValues($csvLine); - if (count($csvLine) < 5) { - $exceptions[0] = Mage::helper('shipping')->__('Invalid Table Rates File Format'); - } + while (false !== ($csvLine = $io->streamReadCsv())) { + $rowNumber ++; - $countryCodes = array(); - $regionCodes = array(); - foreach ($csvLines as $k=>$csvLine) { - $csvLine = $this->_getCsvValues($csvLine); - if (count($csvLine) > 0 && count($csvLine) < 5) { - $exceptions[0] = Mage::helper('shipping')->__('Invalid Table Rates File Format'); - } else { - $countryCodes[] = $csvLine[0]; - $regionCodes[] = $csvLine[1]; - } + if (empty($csvLine)) { + continue; } - if (empty($exceptions)) { - $data = array(); - $countryCodesToIds = array(); - $regionCodesToIds = array(); - $countryCodesIso2 = array(); - - $countryCollection = Mage::getResourceModel('directory/country_collection')->addCountryCodeFilter($countryCodes)->load(); - foreach ($countryCollection->getItems() as $country) { - $countryCodesToIds[$country->getData('iso3_code')] = $country->getData('country_id'); - $countryCodesToIds[$country->getData('iso2_code')] = $country->getData('country_id'); - $countryCodesIso2[] = $country->getData('iso2_code'); - } - - $regionCollection = Mage::getResourceModel('directory/region_collection') - ->addRegionCodeFilter($regionCodes) - ->addCountryFilter($countryCodesIso2) - ->load(); - - foreach ($regionCollection->getItems() as $region) { - $regionCodesToIds[$countryCodesToIds[$region->getData('country_id')]][$region->getData('code')] = $region->getData('region_id'); - } - - foreach ($csvLines as $k=>$csvLine) { - $csvLine = $this->_getCsvValues($csvLine); - - if (empty($countryCodesToIds) || !array_key_exists($csvLine[0], $countryCodesToIds)) { - $countryId = '0'; - if ($csvLine[0] != '*' && $csvLine[0] != '') { - $exceptions[] = Mage::helper('shipping')->__('Invalid Country "%s" in the Row #%s.', $csvLine[0], ($k+1)); - } - } else { - $countryId = $countryCodesToIds[$csvLine[0]]; - } - - if (!isset($countryCodesToIds[$csvLine[0]]) - || !isset($regionCodesToIds[$countryCodesToIds[$csvLine[0]]]) - || !array_key_exists($csvLine[1], $regionCodesToIds[$countryCodesToIds[$csvLine[0]]])) { - $regionId = '0'; - if ($csvLine[1] != '*' && $csvLine[1] != '') { - $exceptions[] = Mage::helper('shipping')->__('Invalid Region/State "%s" in the Row #%s.', $csvLine[1], ($k+1)); - } - } else { - $regionId = $regionCodesToIds[$countryCodesToIds[$csvLine[0]]][$csvLine[1]]; - } - - if ($csvLine[2] == '*' || $csvLine[2] == '') { - $zip = ''; - } else { - $zip = $csvLine[2]; - } - - if (!$this->_isPositiveDecimalNumber($csvLine[3]) || $csvLine[3] == '*' || $csvLine[3] == '') { - $exceptions[] = Mage::helper('shipping')->__('Invalid %s "%s" in the Row #%s.', $conditionFullName, $csvLine[3], ($k+1)); - } else { - $csvLine[3] = (float)$csvLine[3]; - } - - if (!$this->_isPositiveDecimalNumber($csvLine[4])) { - $exceptions[] = Mage::helper('shipping')->__('Invalid Shipping Price "%s" in the Row #%s.', $csvLine[4], ($k+1)); - } else { - $csvLine[4] = (float)$csvLine[4]; - } - - $data[] = array('website_id'=>$websiteId, 'dest_country_id'=>$countryId, 'dest_region_id'=>$regionId, 'dest_zip'=>$zip, 'condition_name'=>$conditionName, 'condition_value'=>$csvLine[3], 'price'=>$csvLine[4]); - $dataDetails[] = array('country'=>$csvLine[0], 'region'=>$csvLine[1]); - } - } - if (empty($exceptions)) { - $connection = $this->_getWriteAdapter(); - - $condition = array( - $connection->quoteInto('website_id = ?', $websiteId), - $connection->quoteInto('condition_name = ?', $conditionName), - ); - $connection->delete($table, $condition); - - foreach($data as $k=>$dataLine) { - try { - $connection->insert($table, $dataLine); - } catch (Exception $e) { - $exceptions[] = Mage::helper('shipping')->__('Duplicate Row #%s (Country "%s", Region/State "%s", Zip "%s" and Value "%s").', ($k+1), $dataDetails[$k]['country'], $dataDetails[$k]['region'], $dataLine['dest_zip'], $dataLine['condition_value']); - } - } + $row = $this->_getImportRow($csvLine, $rowNumber); + if ($row !== false) { + $importData[] = $row; } - if (!empty($exceptions)) { - throw new Exception( "\n" . implode("\n", $exceptions) ); + if (count($importData) == 5000) { + $this->_saveImportData($importData); + $importData = array(); } } + $this->_saveImportData($importData); + $io->streamClose(); + } catch (Mage_Core_Exception $e) { + $adapter->rollback(); + $io->streamClose(); + Mage::throwException($e->getMessage()); + } catch (Exception $e) { + $adapter->rollback(); + $io->streamClose(); + Mage::logException($e); + Mage::throwException(Mage::helper('shipping')->__('An error occurred while import table rates.')); } + + $adapter->commit(); + + if ($this->_importErrors) { + $error = Mage::helper('shipping')->__('%1$d records have been imported. See the following list of errors for each record that has not been imported: %2$s', + $this->_importedRows, implode(" \n", $this->_importErrors)); + Mage::throwException($error); + } + return $this; } - protected function _getCsvValues($string, $separator=",") + /** + * Load directory countries + * + * @return Mage_Shipping_Model_Mysql4_Carrier_Tablerate + */ + protected function _loadDirectoryCountries() { - $elements = explode($separator, trim($string)); - for ($i = 0; $i < count($elements); $i++) { - $nquotes = substr_count($elements[$i], '"'); - if ($nquotes %2 == 1) { - for ($j = $i+1; $j < count($elements); $j++) { - if (substr_count($elements[$j], '"') > 0) { - // Put the quoted string's pieces back together again - array_splice($elements, $i, $j-$i+1, implode($separator, array_slice($elements, $i, $j-$i+1))); - break; - } - } - } - if ($nquotes > 0) { - // Remove first and last quotes, then merge pairs of quotes - $qstr =& $elements[$i]; - $qstr = substr_replace($qstr, '', strpos($qstr, '"'), 1); - $qstr = substr_replace($qstr, '', strrpos($qstr, '"'), 1); - $qstr = str_replace('""', '"', $qstr); - } - $elements[$i] = trim($elements[$i]); + if (!is_null($this->_importIso2Countries) && !is_null($this->_importIso3Countries)) { + return $this; + } + + $this->_importIso2Countries = array(); + $this->_importIso3Countries = array(); + + /** @var $collection Mage_Directory_Model_Mysql4_Country_Collection */ + $collection = Mage::getResourceModel('directory/country_collection'); + foreach ($collection->getData() as $row) { + $this->_importIso2Countries[$row['iso2_code']] = $row['country_id']; + $this->_importIso3Countries[$row['iso3_code']] = $row['country_id']; } - return $elements; + + return $this; + } + + /** + * Load directory regions + * + * @return Mage_Shipping_Model_Mysql4_Carrier_Tablerate + */ + protected function _loadDirectoryRegions() + { + if (!is_null($this->_importRegions)) { + return $this; + } + + $this->_importRegions = array(); + + /** @var $collection Mage_Directory_Model_Mysql4_Region_Collection */ + $collection = Mage::getResourceModel('directory/region_collection'); + foreach ($collection->getData() as $row) { + $this->_importRegions[$row['country_id']][$row['code']] = (int)$row['region_id']; + } + + return $this; } - protected function _isPositiveDecimalNumber($n) + /** + * Return import condition full name by condition name code + * + * @return string + */ + protected function _getConditionFullName($conditionName) { - return preg_match ("/^[0-9]+(\.[0-9]*)?$/", $n); + if (!isset($this->_conditionFullNames[$conditionName])) { + $name = Mage::getSingleton('shipping/carrier_tablerate')->getCode('condition_name_short', $conditionName); + $this->_conditionFullNames[$conditionName] = $name; + } + + return $this->_conditionFullNames[$conditionName]; } + /** + * Validate row for import and return table rate array or false + * Error will be add to _importErrors array + * + * @param array $row + * @param int $rowNumber + * @return array|false + */ + protected function _getImportRow($row, $rowNumber = 0) + { + // validate row + if (count($row) < 5) { + $this->_importErrors[] = Mage::helper('shipping')->__('Invalid Table Rates format in the Row #%s', + $rowNumber); + return false; + } + // validate country + if (isset($this->_importIso2Countries[$row[0]])) { + $countryId = $this->_importIso2Countries[$row[0]]; + } else if (isset($this->_importIso3Countries[$row[0]])) { + $countryId = $this->_importIso3Countries[$row[0]]; + } else if ($row[0] == '*' || $row[0] == '') { + $countryId = '0'; + } else { + $this->_importErrors[] = Mage::helper('shipping')->__('Invalid Country "%s" in the Row #%s.', + $row[0], $rowNumber); + return false; + } + + // validate region + if ($countryId != '0' && isset($this->_importRegions[$countryId][$row[1]])) { + $regionId = $this->_importRegions[$countryId][$row[1]]; + } else if ($row[1] == '*' || $row[1] == '') { + $regionId = 0; + } else { + $this->_importErrors[] = Mage::helper('shipping')->__('Invalid Region/State "%s" in the Row #%s.', + $row[1], $rowNumber); + return false; + } + + // detect zip code + if ($row[2] == '*' || $row[2] == '') { + $zipCode = ''; + } else { + $zipCode = $row[2]; + } + + // validate condition value + $value = $this->_parseDecimalValue($row[3]); + if ($value === false) { + $this->_importErrors[] = Mage::helper('shipping')->__('Invalid %s "%s" in the Row #%s.', + $this->_getConditionFullName($this->_importConditionName), $row[3], $rowNumber); + return false; + } + + // validate price + $price = $this->_parseDecimalValue($row[4]); + if ($price === false) { + $this->_importErrors[] = Mage::helper('shipping')->__('Invalid Shipping Price "%s" in the Row #%s.', + $row[4], $rowNumber); + return false; + } + + // protect from duplicate + $hash = sprintf("%s-%d-%s-%F", $countryId, $regionId, $zipCode, $value); + if (isset($this->_importUniqueHash[$hash])) { + $this->_importErrors[] = Mage::helper('shipping')->__('Duplicate Row #%s (Country "%s", Region/State "%s", Zip "%s" and Value "%s").', + $rowNumber, $row[0], $row[1], $zipCode, $value); + return false; + } + $this->_importUniqueHash[$hash] = true; + + return array( + $this->_importWebsiteId, // website_id + $countryId, // dest_country_id + $regionId, // dest_region_id, + $zipCode, // dest_zip + $this->_importConditionName,// condition_name, + $value, // condition_value + $price // price + ); + } + + /** + * Save import data batch + * + * @param array $data + * @return Mage_Shipping_Model_Mysql4_Carrier_Tablerate + */ + protected function _saveImportData(array $data) + { + if (!empty($data)) { + $columns = array('website_id', 'dest_country_id', 'dest_region_id', 'dest_zip', + 'condition_name', 'condition_value', 'price'); + $this->_getWriteAdapter()->insertArray($this->getMainTable(), $columns, $data); + $this->_importedRows += count($data); + } + + return $this; + } + + /** + * Parse and validate positive decimal value + * Return false if value is not decimal or is not positive + * + * @param string $value + * @return bool|float + */ + protected function _parseDecimalValue($value) + { + if (!is_numeric($value)) { + return false; + } + $value = (float)sprintf('%.4F', $value); + if ($value < 0.0000) { + return false; + } + return $value; + } + + /** + * Parse and validate positive decimal value + * + * @see Mage_Shipping_Model_Mysql4_Carrier_Tablerate::_parseDecimalValue() + * @deprecated since 1.4.1.0 + * @param string $value + * @return bool|float + */ + protected function _isPositiveDecimalNumber($value) + { + return $this->_parseDecimalValue($value); + } } diff --git a/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate/Collection.php b/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate/Collection.php index 8f8e478bd6..6f0a6de817 100644 --- a/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate/Collection.php +++ b/app/code/core/Mage/Shipping/Model/Mysql4/Carrier/Tablerate/Collection.php @@ -31,44 +31,96 @@ * @package Mage_Shipping * @author Magento Core Team */ -class Mage_Shipping_Model_Mysql4_Carrier_Tablerate_Collection extends Varien_Data_Collection_Db +class Mage_Shipping_Model_Mysql4_Carrier_Tablerate_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract { + /** + * main table name + * + * @deprecated since 1.4.1.0 + * @var string + */ protected $_shipTable; + + /** + * directory/country table name + * + * @var string + */ protected $_countryTable; + + /** + * directory/country_region table name + * + * @var string + */ protected $_regionTable; - public function __construct() + /** + * Define resource model and item + * + */ + protected function _construct() { - parent::__construct(Mage::getSingleton('core/resource')->getConnection('shipping_read')); - $this->_shipTable = Mage::getSingleton('core/resource')->getTableName('shipping/tablerate'); - $this->_countryTable = Mage::getSingleton('core/resource')->getTableName('directory/country'); - $this->_regionTable = Mage::getSingleton('core/resource')->getTableName('directory/country_region'); - $this->_select->from(array("s" => $this->_shipTable)) - ->joinLeft(array("c" => $this->_countryTable), 'c.country_id = s.dest_country_id', 'iso3_code AS dest_country') - ->joinLeft(array("r" => $this->_regionTable), 'r.region_id = s.dest_region_id', 'code AS dest_region') - ->order(array("dest_country", "dest_region", "dest_zip")); - $this->_setIdFieldName('pk'); - return $this; + $this->_init('shipping/carrier_tablerate'); + $this->_shipTable = $this->getMainTable(); + $this->_countryTable = $this->getTable('directory/country'); + $this->_regionTable = $this->getTable('directory/country_region'); } - public function setWebsiteFilter($websiteId) + /** + * Initialize select, add country iso3 code and region name + * + * @return void + */ + public function _initSelect() { - $this->_select->where("website_id = ?", $websiteId); + parent::_initSelect(); - return $this; + $this->_select + ->joinLeft( + array('country_table' => $this->_countryTable), + 'country_table.country_id = main_table.dest_country_id', + array('dest_country' => 'iso3_code')) + ->joinLeft( + array('region_table' => $this->_regionTable), + 'region_table.region_id = main_table.dest_region_id', + array('dest_region' => 'code')); + + $this->addOrder('dest_country', self::SORT_ORDER_ASC); + $this->addOrder('dest_region', self::SORT_ORDER_ASC); + $this->addOrder('dest_zip', self::SORT_ORDER_ASC); } - public function setConditionFilter($conditionName) + /** + * Add website filter to collection + * + * @param int $websiteId + * @return Mage_Shipping_Model_Mysql4_Carrier_Tablerate_Collection + */ + public function setWebsiteFilter($websiteId) { - $this->_select->where("condition_name = ?", $conditionName); + return $this->addFieldToFilter('website_id', $websiteId); + } - return $this; + /** + * Add condition name (code) filter to collection + * + * @param string $conditionName + * @return Mage_Shipping_Model_Mysql4_Carrier_Tablerate_Collection + */ + public function setConditionFilter($conditionName) + { + return $this->addFieldToFilter('condition_name', $conditionName); } + /** + * Add country filter to collection + * + * @param string $countryId + * @return Mage_Shipping_Model_Mysql4_Carrier_Tablerate_Collection + */ public function setCountryFilter($countryId) { - $this->_select->where("dest_country_id = ?", $countryId); - - return $this; + return $this->addFieldToFilter('dest_country_id', $countryId); } } diff --git a/app/code/core/Mage/Shipping/Model/Rate/Request.php b/app/code/core/Mage/Shipping/Model/Rate/Request.php index 7e3b6d4822..5b6fce56d5 100644 --- a/app/code/core/Mage/Shipping/Model/Rate/Request.php +++ b/app/code/core/Mage/Shipping/Model/Rate/Request.php @@ -55,8 +55,86 @@ * - pickup: CC * - container: CP * - address: RES + * + * @method int getStoreId() + * @method Mage_Shipping_Model_Rate_Request setStoreId(int $value) + * @method int getWebsiteId() + * @method Mage_Shipping_Model_Rate_Request setWebsiteId(int $value) + * @method string getBaseCurrency() + * @method Mage_Shipping_Model_Rate_Request setBaseCurrency(string $value) + * + * @method Mage_Shipping_Model_Rate_Request setAllItems(array $items) + * @method array getAllItems() + * + * @method Mage_Shipping_Model_Rate_Request setOrigCountryId(string $value) + * @method string getOrigCountryId() + * @method Mage_Shipping_Model_Rate_Request setOrigRegionId(int $value) + * @method int getOrigRegionId() + * @method Mage_Shipping_Model_Rate_Request setOrigPostcode(string $value) + * @method string getOrigPostcode() + * @method Mage_Shipping_Model_Rate_Request setOrigCity(string $value) + * @method string getOrigCity() + * + * @method Mage_Shipping_Model_Rate_Request setDestCountryId(string $value) + * @method string getDestCountryId() + * @method Mage_Shipping_Model_Rate_Request setDestRegionId(int $value) + * @method int getDestRegionId() + * @method Mage_Shipping_Model_Rate_Request setDestRegionCode(string $value) + * @method string getDestRegionCode() + * @method Mage_Shipping_Model_Rate_Request setDestPostcode(string $value) + * @method string getDestPostcode() + * @method Mage_Shipping_Model_Rate_Request setDestCity(string $value) + * @method string getDestCity() + * @method Mage_Shipping_Model_Rate_Request setDestStreet(string $value) + * @method string getDestStreet() + * + * @method Mage_Shipping_Model_Rate_Request setPackageValue(float $value) + * @method float getPackageValue() + * @method Mage_Shipping_Model_Rate_Request setPackageValueWithDiscount(float $value) + * @method float getPackageValueWithDiscount() + * @method Mage_Shipping_Model_Rate_Request setPackagePhysicalValue(float $value) + * @method float getPackagePhysicalValue() + * @method Mage_Shipping_Model_Rate_Request setPackageQty(float $value) + * @method float getPackageQty() + * @method Mage_Shipping_Model_Rate_Request setPackageWeight(float $value) + * @method float getPackageWeight() + * @method Mage_Shipping_Model_Rate_Request setPackageHeight(int $value) + * @method int getPackageHeight() + * @method Mage_Shipping_Model_Rate_Request setPackageWidth(int $value) + * @method int getPackageWidth() + * @method Mage_Shipping_Model_Rate_Request setPackageDepth(int $value) + * @method int getPackageDepth() + * @method Mage_Shipping_Model_Rate_Request setPackageCurrency(string $value) + * @method string getPackageCurrency() + * + * @method Mage_Shipping_Model_Rate_Request setOrderTotalQty(float $value) + * @method float getOrderTotalQty() + * @method Mage_Shipping_Model_Rate_Request setOrderSubtotal(float $value) + * @method float getOrderSubtotal() + * + * @method boolean getFreeShipping() + * @method Mage_Shipping_Model_Rate_Request setFreeShipping(boolean $flag) + * @method float getFreeMethodWeight() + * @method Mage_Shipping_Model_Rate_Request setFreeMethodWeight(float $value) + * + * @method Mage_Shipping_Model_Rate_Request setOptionInsurance(boolean $value) + * @method boolean getOptionInsurance() + * @method Mage_Shipping_Model_Rate_Request setOptionHandling(float $flag) + * @method float getOptionHandling() + * + * @method Mage_Shipping_Model_Rate_Request setConditionName(array $value) + * @method Mage_Shipping_Model_Rate_Request setConditionName(string $value) + * @method string getConditionName() + * @method array getConditionName() + * + * @method Mage_Shipping_Model_Rate_Request setLimitCarrier(string $value) + * @method string getLimitCarrier() + * @method Mage_Shipping_Model_Rate_Request setLimitMethod(string $value) + * @method string getLimitMethod() + * + * @category Mage + * @package Mage_Shipping + * @author Magento Core Team */ class Mage_Shipping_Model_Rate_Request extends Varien_Object -{ - -} +{} diff --git a/app/code/core/Mage/Shipping/Model/Shipping.php b/app/code/core/Mage/Shipping/Model/Shipping.php index 5c7445fa51..9fc1a5da60 100644 --- a/app/code/core/Mage/Shipping/Model/Shipping.php +++ b/app/code/core/Mage/Shipping/Model/Shipping.php @@ -157,6 +157,7 @@ public function collectCarrierRates($carrierCode, $request) public function collectRatesByAddress(Varien_Object $address, $limitCarrier=null) { + /** @var $request Mage_Shipping_Model_Rate_Request */ $request = Mage::getModel('shipping/rate_request'); $request->setAllItems($address->getAllItems()); $request->setDestCountryId($address->getCountryId()); diff --git a/app/code/core/Mage/Tag/Model/Mysql4/Customer/Collection.php b/app/code/core/Mage/Tag/Model/Mysql4/Customer/Collection.php index 289d20246d..6074103a2d 100644 --- a/app/code/core/Mage/Tag/Model/Mysql4/Customer/Collection.php +++ b/app/code/core/Mage/Tag/Model/Mysql4/Customer/Collection.php @@ -254,7 +254,8 @@ public function getCountAttribute() public function addFieldToFilter($attribute, $condition=null){ if ($attribute == 'name') { - $this->getSelect()->where($this->_getConditionSql('t.name', $condition)); + $where = $this->_getConditionSql('t.name', $condition); + $this->getSelect()->where($where, null, Varien_Db_Select::TYPE_CONDITION); return $this; } else { return parent::addFieldToFilter($attribute, $condition); diff --git a/app/code/core/Mage/Tag/Model/Mysql4/Product/Collection.php b/app/code/core/Mage/Tag/Model/Mysql4/Product/Collection.php index e18eca456c..428862cfd0 100644 --- a/app/code/core/Mage/Tag/Model/Mysql4/Product/Collection.php +++ b/app/code/core/Mage/Tag/Model/Mysql4/Product/Collection.php @@ -372,7 +372,13 @@ protected function _joinFields() )) ->join(array('t' => $tagTable), 't.tag_id = relation.tag_id', - array('tag_id', 'name', 'tag_status' => 'status', 'tag_name' => 'name', 'store_id' => 'first_store_id') + array( + 'tag_id', + 'name', + 'tag_status' => 'status', + 'tag_name' => 'name', + 'store_id' => 'IF(t.first_store_id = 0, relation.store_id, t.first_store_id)' + ) ); return $this; diff --git a/app/code/core/Mage/Tag/Model/Mysql4/Tag/Collection.php b/app/code/core/Mage/Tag/Model/Mysql4/Tag/Collection.php index 567aa7687e..30347489d9 100644 --- a/app/code/core/Mage/Tag/Model/Mysql4/Tag/Collection.php +++ b/app/code/core/Mage/Tag/Model/Mysql4/Tag/Collection.php @@ -144,15 +144,21 @@ public function addPopularity($limit = null) public function addSummary($storeId) { if (!$this->getFlag('summary')) { - $joinCondition = $this->getConnection()->quoteInto(' AND summary.store_id IN(?)', $storeId); + $tableAlias = 'summary'; + $joinCondition = $this->getConnection()->quoteInto(' AND '. $tableAlias .'.store_id IN(?)', $storeId); $this->getSelect() ->joinLeft( - array('summary'=>$this->getTable('tag/summary')), - 'main_table.tag_id=summary.tag_id' . $joinCondition, + array($tableAlias => $this->getTable('tag/summary')), + 'main_table.tag_id='. $tableAlias .'.tag_id' . $joinCondition, array('store_id','popularity', 'customers', 'products' )); + $this->addFilterToMap('store_id', $tableAlias . '.store_id'); + $this->addFilterToMap('popularity', $tableAlias . '.popularity'); + $this->addFilterToMap('customers', $tableAlias . '.customers'); + $this->addFilterToMap('products', $tableAlias . '.products'); + $this->setFlag('summary', true); } return $this; @@ -264,9 +270,10 @@ public function addStoreFilter($storeId, $allFilter = true) public function setActiveFilter() { - $this->getSelect()->where('relation.active = 1'); + $statusActive = Mage_Tag_Model_Tag_Relation::STATUS_ACTIVE; + $this->getSelect()->where('relation.active = ?', $statusActive); if($this->getFlag('prelation')) { - $this->getSelect()->where('prelation.active = 1'); + $this->getSelect()->where('prelation.active = ?', $statusActive); } return $this; } diff --git a/app/code/core/Mage/Tag/Model/Mysql4/Tag/Relation.php b/app/code/core/Mage/Tag/Model/Mysql4/Tag/Relation.php index a7864d4bd7..8a2b29b26e 100644 --- a/app/code/core/Mage/Tag/Model/Mysql4/Tag/Relation.php +++ b/app/code/core/Mage/Tag/Model/Mysql4/Tag/Relation.php @@ -83,14 +83,19 @@ public function getProductIds($model) { $select = $this->_getReadAdapter()->select() ->from($this->getMainTable(), 'product_id') - ->where("tag_id=?", $model->getTagId()); + ->where("{$this->getMainTable()}.tag_id=?", $model->getTagId()); if (!is_null($model->getCustomerId())) { - $select->where('customer_id=?', $model->getCustomerId()); + $select->where("{$this->getMainTable()}.customer_id=?", $model->getCustomerId()); } if ($model->hasStoreId()) { - $select->where('store_id = ?', $model->getStoreId()); + $select->where("{$this->getMainTable()}.store_id = ?", $model->getStoreId()); + } + + if (!is_null($model->getStatusFilter())) { + $select->join($this->getTable('tag/tag'), "{$this->getTable('tag/tag')}.tag_id = {$this->getMainTable()}.tag_id") + ->where("{$this->getTable('tag/tag')}.status = ?", $model->getStatusFilter()); } return $this->_getReadAdapter()->fetchCol($select); @@ -123,7 +128,7 @@ public function deactivate($tagId, $customerId) { $condition = $this->_getWriteAdapter()->quoteInto('tag_id = ?', $tagId) . ' AND '; $condition.= $this->_getWriteAdapter()->quoteInto('customer_id = ?', $customerId); - $data = array('active'=>0); + $data = array('active' => Mage_Tag_Model_Tag_Relation::STATUS_NOT_ACTIVE); $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition); return $this; } diff --git a/app/code/core/Mage/Tag/Model/Tag.php b/app/code/core/Mage/Tag/Model/Tag.php index d8167397c6..c5ce4865f9 100644 --- a/app/code/core/Mage/Tag/Model/Tag.php +++ b/app/code/core/Mage/Tag/Model/Tag.php @@ -253,6 +253,7 @@ public function getRelatedProductIds() return Mage::getModel('tag/tag_relation') ->setTagId($this->getTagId()) ->setStoreId($this->getStoreId()) + ->setStatusFilter($this->getStatusFilter()) ->setCustomerId(null) ->getProductIds(); } diff --git a/app/code/core/Mage/Tag/Model/Tag/Relation.php b/app/code/core/Mage/Tag/Model/Tag/Relation.php index 6dadb4aa16..2266bda60c 100644 --- a/app/code/core/Mage/Tag/Model/Tag/Relation.php +++ b/app/code/core/Mage/Tag/Model/Tag/Relation.php @@ -34,7 +34,11 @@ */ class Mage_Tag_Model_Tag_Relation extends Mage_Core_Model_Abstract { - const STATUS_ACTIVE = 1; + /** + * Relation statuses + */ + const STATUS_ACTIVE = 1; + const STATUS_NOT_ACTIVE = 0; /** * Entity code. diff --git a/app/code/core/Mage/Tag/controllers/IndexController.php b/app/code/core/Mage/Tag/controllers/IndexController.php index 9d85bd62bf..023a08ba71 100644 --- a/app/code/core/Mage/Tag/controllers/IndexController.php +++ b/app/code/core/Mage/Tag/controllers/IndexController.php @@ -59,10 +59,12 @@ public function saveAction() $tagNamesArr = $this->_cleanTags($this->_extractTags($tagName)); - $counter = new Varien_Object(array("new" => 0, - "exist" => array(), - "success" => array(), - "recurrence" => array())); + $counter = new Varien_Object(array( + "new" => 0, + "exist" => array(), + "success" => array(), + "recurrence" => array()) + ); $tagModel = Mage::getModel('tag/tag'); $tagRelationModel = Mage::getModel('tag/tag_relation'); @@ -77,7 +79,7 @@ public function saveAction() ->setStoreId($storeId) ->setProductId($productId) ->setCustomerId($customerId) - ->setActive(1) + ->setActive(Mage_Tag_Model_Tag_Relation::STATUS_ACTIVE) ->setCreatedAt( $tagRelationModel->getResource()->formatDate(time()) ); if (!$tagModel->getId()) { @@ -87,7 +89,6 @@ public function saveAction() ->save(); $tagRelationModel->setTagId($tagModel->getId())->save(); - $counter->setNew($counter->getNew() + 1); } else { $tagStatus = $tagModel->getStatus(); @@ -96,7 +97,14 @@ public function saveAction() switch($tagStatus) { case $tagModel->getApprovedStatus(): if($this->_checkLinkBetweenTagProduct($tagRelationModel)) { - if(!$this->_checkLinkBetweenTagCustomerProduct($tagRelationModel, $tagModel)) { + $relation = $this->_getLinkBetweenTagCustomerProduct($tagRelationModel, $tagModel); + if ($relation->getId()) { + if (!$relation->getActive()) { + $tagRelationModel + ->setId($relation->getId()) + ->save(); + } + } else { $tagRelationModel->save(); } $counter->setExist(array_merge($counter->getExist(), array($tagName))); @@ -106,7 +114,14 @@ public function saveAction() } break; case $tagModel->getPendingStatus(): - if(!$this->_checkLinkBetweenTagCustomerProduct($tagRelationModel, $tagModel)) { + $relation = $this->_getLinkBetweenTagCustomerProduct($tagRelationModel, $tagModel); + if ($relation->getId()) { + if (!$relation->getActive()) { + $tagRelationModel + ->setId($relation->getId()) + ->save(); + } + } else { $tagRelationModel->save(); } $counter->setNew($counter->getNew() + 1); @@ -123,9 +138,7 @@ public function saveAction() } } } - $this->_fillMessageBox($counter); - } catch (Exception $e) { Mage::logException($e); $session->addError($this->__('Unable to save tag(s).')); @@ -137,7 +150,7 @@ public function saveAction() /** * Checks inputed tags on the correctness of symbols and split string to array of tags - * + * * @param string $tagNamesInString * @return array */ @@ -148,7 +161,7 @@ protected function _extractTags($tagNamesInString) /** * Clears the tag from the separating characters. - * + * * @param array $tagNamesArr * @return array */ @@ -166,7 +179,7 @@ protected function _cleanTags(array $tagNamesArr) /** * Checks whether the already marked this product in this store by this tag. - * + * * @param Mage_Tag_Model_Tag_Relation $tagRelationModel * @return boolean */ @@ -181,24 +194,37 @@ protected function _checkLinkBetweenTagProduct($tagRelationModel) /** * Checks whether the already marked this product in this store by this tag and by this customer. - * + * * @param Mage_Tag_Model_Tag_Relation $tagRelationModel * @param Mage_Tag_Model_Tag $tagModel * @return boolean */ protected function _checkLinkBetweenTagCustomerProduct($tagRelationModel, $tagModel) { - return (count(Mage::getModel('tag/tag_relation')->loadByTagCustomer( - $tagRelationModel->getProductId(), - $tagModel->getId(), - $tagRelationModel->getCustomerId(), - $tagRelationModel->getStoreId()) - ->getProductIds()) > 0); + return (count($this->_getLinkBetweenTagCustomerProduct($tagRelationModel, $tagModel) + ->getProductIds()) > 0); + } + + /** + * Get relation model for marked product in this store by this tag and by this customer. + * + * @param Mage_Tag_Model_Tag_Relation $tagRelationModel + * @param Mage_Tag_Model_Tag $tagModel + * @return Mage_Tag_Model_Tag_Relation + */ + protected function _getLinkBetweenTagCustomerProduct($tagRelationModel, $tagModel) + { + return Mage::getModel('tag/tag_relation')->loadByTagCustomer( + $tagRelationModel->getProductId(), + $tagModel->getId(), + $tagRelationModel->getCustomerId(), + $tagRelationModel->getStoreId() + ); } /** * Fill Message Box by success and notice messages about results of user actions. - * + * * @param Varien_Object $counter * @return void */ diff --git a/app/code/core/Mage/Tax/Model/Calculation.php b/app/code/core/Mage/Tax/Model/Calculation.php index 27f3179436..c8c6234483 100644 --- a/app/code/core/Mage/Tax/Model/Calculation.php +++ b/app/code/core/Mage/Tax/Model/Calculation.php @@ -327,8 +327,12 @@ public function getRateRequest($shippingAddress = null, $billingAddress = null, } /** - * Compare data and rates for two tax rate requests. - * Return true if requests are semilar + * Compare data and rates for two tax rate requests for same products (product tax class ids). + * Returns true if requests are similar (i.e. equal taxes rates will be applied to them) + * + * Notice: + * a) productClassId MUST be identical for both requests, because we intend to check selling SAME products to DIFFERENT locations + * b) due to optimization productClassId can be array of ids, not only single id * * @param Varien_Object $first * @param Varien_Object $second @@ -337,10 +341,7 @@ public function getRateRequest($shippingAddress = null, $billingAddress = null, public function compareRequests($first, $second) { $country = $first->getCountryId() == $second->getCountryId(); - /** - * "0" support for admin dropdown with --please select-- - */ - $region = (int)$first->getRegionId() == (int)$second->getRegionId(); + $region = (int)$first->getRegionId() == (int)$second->getRegionId(); // "0" support for admin dropdown with --please select-- $postcode= $first->getPostcode() == $second->getPostcode(); $taxClass= $first->getCustomerClassId() == $second->getCustomerClassId(); @@ -355,7 +356,33 @@ public function compareRequests($first, $second) if ($firstReqRates === $secondReqRates) { return true; } - return false; + + /** + * If rates are not equal by ids then compare actual values + * All product classes must have same rates to assume requests been similar + */ + $productClassId1 = $first->getProductClassId(); // Save to set it back later + $productClassId2 = $second->getProductClassId(); // Save to set it back later + + $ids = is_array($productClassId1) ? $productClassId1 : array($productClassId1); // Ids are equal for both requests, so take any of them to process + $identical = true; + foreach ($ids as $productClassId) { + $first->setProductClassId($productClassId); + $rate1 = $this->getRate($first); + + $second->setProductClassId($productClassId); + $rate2 = $this->getRate($second); + + if ($rate1 != $rate2) { + $identical = false; + break; + } + } + + $first->setProductClassId($productClassId1); + $second->setProductClassId($productClassId2); + + return $identical; } protected function _getRates($request, $fieldName, $type) diff --git a/app/code/core/Mage/Tax/Model/Mysql4/Calculation.php b/app/code/core/Mage/Tax/Model/Mysql4/Calculation.php index 6794764e7a..c04931e2bb 100644 --- a/app/code/core/Mage/Tax/Model/Mysql4/Calculation.php +++ b/app/code/core/Mage/Tax/Model/Mysql4/Calculation.php @@ -31,6 +31,12 @@ */ class Mage_Tax_Model_Mysql4_Calculation extends Mage_Core_Model_Mysql4_Abstract { + /* + * Internal array to cache identical rate SELECTs to DB + * @var array + */ + protected $_ratesCache = array(); + protected function _construct() { $this->_setMainTable('tax/tax_calculation'); @@ -179,64 +185,86 @@ protected function _createSearchPostCodeTemplates($postcode) } /** - * Load select and return tax rates + * Returns tax rates for request - either pereforms SELECT from DB, or returns already cached result + * Notice that productClassId due to optimization can be array of ids * * @param Varien_Object $request * @return array */ protected function _getRates($request) { - + // Extract params that influence our SELECT statement and use them to create cache key $storeId = Mage::app()->getStore($request->getStore())->getId(); - - $select = $this->_getReadAdapter()->select(); - $select - ->from(array('main_table'=>$this->getMainTable())) - ->where('customer_tax_class_id = ?', $request->getCustomerClassId()); - if ($request->getProductClassId()) { - $select->where('product_tax_class_id IN (?)', $request->getProductClassId()); + $customerClassId = $request->getCustomerClassId(); + $countryId = $request->getCountryId(); + $regionId = $request->getRegionId(); + $postcode = $request->getPostcode(); + + // Process productClassId as it can be array or usual value. Form best key for cache. + $productClassId = $request->getProductClassId(); + $ids = is_array($productClassId) ? $productClassId : array($productClassId); + foreach ($ids as $key => $val) { + $ids[$key] = (int) $val; // Make it integer for equal cache keys even in case of null/false/0 values } + $ids = array_unique($ids); + sort($ids); + $productClassKey = implode(',', $ids); + + // Form cache key and either get data from cache or from DB + $cacheKey = implode('|', array($storeId, $customerClassId, $productClassKey, $countryId, $regionId, $postcode)); + + if (!isset($this->_ratesCache[$cacheKey])) { + // Make SELECT and get data + $select = $this->_getReadAdapter()->select(); + $select + ->from(array('main_table'=>$this->getMainTable())) + ->where('customer_tax_class_id = ?', $customerClassId); + if ($productClassId) { + $select->where('product_tax_class_id IN (?)', $productClassId); + } - $select->join( - array('rule'=>$this->getTable('tax/tax_calculation_rule')), - 'rule.tax_calculation_rule_id = main_table.tax_calculation_rule_id', - array('rule.priority', 'rule.position') - ); - $select->join( - array('rate'=>$this->getTable('tax/tax_calculation_rate')), - 'rate.tax_calculation_rate_id = main_table.tax_calculation_rate_id', - array('value'=>'rate.rate', 'rate.tax_country_id', 'rate.tax_region_id', 'rate.tax_postcode', 'rate.tax_calculation_rate_id', 'rate.code') - ); - - $select->joinLeft( - array('title_table'=>$this->getTable('tax/tax_calculation_rate_title')), - "rate.tax_calculation_rate_id = title_table.tax_calculation_rate_id AND title_table.store_id = '{$storeId}'", - array('title'=>'IFNULL(title_table.value, rate.code)') - ); - - $select - ->where("rate.tax_country_id = ?", $request->getCountryId()) - ->where("rate.tax_region_id in ('*', '', ?)", $request->getRegionId()); - - $selectClone = clone $select; - - $select - ->where("rate.zip_is_range IS NULL") - ->where("rate.tax_postcode in ('*', '', ?)", $this->_createSearchPostCodeTemplates($request->getPostcode())); - - $selectClone - ->where("rate.zip_is_range IS NOT NULL") - ->where("? BETWEEN rate.zip_from AND rate.zip_to", $request->getPostcode()); - - /** - * @see ZF-7592 issue http://framework.zend.com/issues/browse/ZF-7592 - */ - $select = $this->_getReadAdapter()->select()->union(array('(' . $select . ')', '(' . $selectClone . ')')); - $order = array('priority ASC', 'tax_calculation_rule_id ASC', 'tax_country_id DESC', 'tax_region_id DESC', 'tax_postcode DESC', 'value DESC'); - $select->order($order); - - return $this->_getReadAdapter()->fetchAll($select); + $select->join( + array('rule'=>$this->getTable('tax/tax_calculation_rule')), + 'rule.tax_calculation_rule_id = main_table.tax_calculation_rule_id', + array('rule.priority', 'rule.position') + ); + $select->join( + array('rate'=>$this->getTable('tax/tax_calculation_rate')), + 'rate.tax_calculation_rate_id = main_table.tax_calculation_rate_id', + array('value'=>'rate.rate', 'rate.tax_country_id', 'rate.tax_region_id', 'rate.tax_postcode', 'rate.tax_calculation_rate_id', 'rate.code') + ); + + $select->joinLeft( + array('title_table'=>$this->getTable('tax/tax_calculation_rate_title')), + "rate.tax_calculation_rate_id = title_table.tax_calculation_rate_id AND title_table.store_id = '{$storeId}'", + array('title'=>'IFNULL(title_table.value, rate.code)') + ); + + $select + ->where("rate.tax_country_id = ?", $countryId) + ->where("rate.tax_region_id in ('*', '', ?)", $regionId); + + $selectClone = clone $select; + + $select + ->where("rate.zip_is_range IS NULL") + ->where("rate.tax_postcode in ('*', '', ?)", $this->_createSearchPostCodeTemplates($postcode)); + + $selectClone + ->where("rate.zip_is_range IS NOT NULL") + ->where("? BETWEEN rate.zip_from AND rate.zip_to", $postcode); + + /** + * @see ZF-7592 issue http://framework.zend.com/issues/browse/ZF-7592 + */ + $select = $this->_getReadAdapter()->select()->union(array('(' . $select . ')', '(' . $selectClone . ')')); + $order = array('priority ASC', 'tax_calculation_rule_id ASC', 'tax_country_id DESC', 'tax_region_id DESC', 'tax_postcode DESC', 'value DESC'); + $select->order($order); + + $this->_ratesCache[$cacheKey] = $this->_getReadAdapter()->fetchAll($select); + } + return $this->_ratesCache[$cacheKey]; } protected function _calculateRate($rates) diff --git a/app/code/core/Mage/Tax/Model/Mysql4/Report/Updatedat/Collection.php b/app/code/core/Mage/Tax/Model/Mysql4/Report/Updatedat/Collection.php index 5a27cf5b56..64a65d8403 100644 --- a/app/code/core/Mage/Tax/Model/Mysql4/Report/Updatedat/Collection.php +++ b/app/code/core/Mage/Tax/Model/Mysql4/Report/Updatedat/Collection.php @@ -83,6 +83,29 @@ protected function _applyStoresFilter() return $this; } + /** + * Apply order status filter + * + * @return Mage_Tax_Model_Mysql4_Report_Updatedat_Collection + */ + protected function _applyOrderStatusFilter() + { + if (is_null($this->_orderStatus)) { + return $this; + } + $orderStatus = $this->_orderStatus; + if (!is_array($orderStatus)) { + $orderStatus = array($orderStatus); + } + $this->getSelect()->where('status IN(?)', $orderStatus); + return $this; + } + + /** + * Retrieve array of columns to select + * + * @return array + */ protected function _getSelectedColumns() { if ('month' == $this->_period) { @@ -126,17 +149,6 @@ protected function _initSelect() $columns = $this->_getSelectedColumns(); $mainTable = $this->getResource()->getMainTable(); - if (!is_null($this->_from) || !is_null($this->_to)) { - $where = (!is_null($this->_from)) ? "so.updated_at >= '{$this->_from}'" : ''; - if (!is_null($this->_to)) { - $where .= (!empty($where)) ? " AND so.updated_at <= '{$this->_to}'" : "so.updated_at <= '{$this->_to}'"; - } - - $subQuery = clone $this->getSelect(); - $subQuery->from(array('so' => $mainTable), array('DISTINCT DATE(so.updated_at)')) - ->where($where); - } - $select = $this->getSelect() ->from(array('e' => $mainTable), $columns) ->joinInner(array('tax'=> $this->getTable('tax/sales_order_tax')), 'e.entity_id = tax.order_id', array()); @@ -144,22 +156,24 @@ protected function _initSelect() $this->_applyStoresFilter(); $this->_applyOrderStatusFilter(); - if (!is_null($this->_from) || !is_null($this->_to)) { - $select->where("DATE(e.updated_at) IN(?)", new Zend_Db_Expr($subQuery)); + if ($this->_from !== null) { + $select->where('DATE(e.updated_at) >= DATE(?)', $this->_from); + } + + if ($this->_to !== null) { + $select->where('DATE(e.updated_at) <= DATE(?)', $this->_to); } if (!$this->isTotals() && !$this->isSubTotals()) { $select->group(array( $this->_periodFormat, - 'store_id', 'code' )); } if ($this->isSubTotals()) { $select->group(array( - $this->_periodFormat, - 'store_id' + $this->_periodFormat )); } diff --git a/app/code/core/Mage/Tax/Model/Observer.php b/app/code/core/Mage/Tax/Model/Observer.php index 4b0ace529d..08fe98c82c 100644 --- a/app/code/core/Mage/Tax/Model/Observer.php +++ b/app/code/core/Mage/Tax/Model/Observer.php @@ -172,5 +172,21 @@ public function aggregateSalesReportTaxData($schedule) Mage::app()->getLocale()->revert(); return $this; } -} + /** + * Reset extra tax amounts on quote addresses before recollecting totals + * + * @param Varien_Event_Observer $observer + * @return Mage_Tax_Model_Observer + */ + public function quoteCollectTotalsBefore(Varien_Event_Observer $observer) + { + /* @var $quote Mage_Sales_Model_Quote */ + $quote = $observer->getEvent()->getQuote(); + foreach ($quote->getAllAddresses() as $address) { + $address->setExtraTaxAmount(0); + $address->setBaseExtraTaxAmount(0); + } + return $this; + } +} diff --git a/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Shipping.php b/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Shipping.php index 6d74dc4311..505faeabd5 100644 --- a/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Shipping.php +++ b/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Shipping.php @@ -42,8 +42,8 @@ class Mage_Tax_Model_Sales_Total_Quote_Shipping extends Mage_Sales_Model_Quote_A protected $_config = null; /** - * Flag which is initialized when collect method is start. - * Is used for checking if store tax and customer tax requests are similar + * Flag which is initialized when collect method is started and catalog prices include tax. + * It is used for checking if store tax and customer tax requests are similar * * @var bool */ @@ -85,14 +85,19 @@ public function collect(Mage_Sales_Model_Quote_Address $address) $store ); - $storeTaxRequest->setProductClassId($this->_config->getShippingTaxClass($store)); - $addressTaxRequest->setProductClassId($this->_config->getShippingTaxClass($store)); - $this->_areTaxRequestsSimilar = $calc->compareRequests($addressTaxRequest, $storeTaxRequest); + $shippingTaxClass = $this->_config->getShippingTaxClass($store); + $storeTaxRequest->setProductClassId($shippingTaxClass); + $addressTaxRequest->setProductClassId($shippingTaxClass); + + $priceIncludesTax = $this->_config->shippingPriceIncludesTax($store); + if ($priceIncludesTax) { + $this->_areTaxRequestsSimilar = $calc->compareRequests($addressTaxRequest, $storeTaxRequest); + } $shipping = $taxShipping = $address->getShippingAmount(); $baseShipping = $baseTaxShipping = $address->getBaseShippingAmount(); $rate = $calc->getRate($addressTaxRequest); - if ($this->_config->shippingPriceIncludesTax($store)) { + if ($priceIncludesTax) { if ($this->_areTaxRequestsSimilar) { $tax = $this->_round($calc->calcTaxAmount($shipping, $rate, true, false), $rate, true); $baseTax = $this->_round($calc->calcTaxAmount($baseShipping, $rate, true, false), $rate, true, 'base'); @@ -109,7 +114,7 @@ public function collect(Mage_Sales_Model_Quote_Address $address) $baseStoreTax = $calc->calcTaxAmount($baseShipping, $storeRate, true, false); $shipping = $calc->round($shipping - $storeTax); $baseShipping = $calc->round($baseShipping - $baseStoreTax); - $tax = $this->_round($calc->calcTaxAmount($shipping, $rate, false, false), false, $rate); + $tax = $this->_round($calc->calcTaxAmount($shipping, $rate, false, false), $rate, false); $baseTax = $this->_round($calc->calcTaxAmount($baseShipping, $rate, false, false), $rate, false, 'base'); $taxShipping = $shipping + $tax; $baseTaxShipping= $baseShipping + $baseTax; @@ -118,7 +123,7 @@ public function collect(Mage_Sales_Model_Quote_Address $address) $isPriceInclTax = false; } } else { - $tax = $this->_round($calc->calcTaxAmount($shipping, $rate, false, false), false, $rate); + $tax = $this->_round($calc->calcTaxAmount($shipping, $rate, false, false), $rate, false); $baseTax = $this->_round($calc->calcTaxAmount($baseShipping, $rate, false, false), $rate, false, 'base'); $taxShipping = $shipping + $tax; $baseTaxShipping= $baseShipping + $baseTax; diff --git a/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Subtotal.php b/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Subtotal.php index 0954b50e1f..40ea620b97 100644 --- a/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Subtotal.php +++ b/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Subtotal.php @@ -50,7 +50,7 @@ class Mage_Tax_Model_Sales_Total_Quote_Subtotal extends Mage_Sales_Model_Quote_A protected $_baseSubtotal = 0; /** - * Flag which is initialized when collect method is start. + * Flag which is initialized when collect method is started and catalog prices include tax. * Is used for checking if store tax and customer tax requests are similar * * @var bool @@ -179,7 +179,8 @@ protected function _processItem($item, $taxRequest) */ protected function _unitBaseCalculation($item, $request) { - $rate = $this->_calculator->getRate($request->setProductClassId($item->getProduct()->getTaxClassId())); + $request->setProductClassId($item->getProduct()->getTaxClassId()); + $rate = $this->_calculator->getRate($request); $qty = $item->getTotalQty(); $price = $taxPrice = $item->getCalculationPrice(); @@ -195,7 +196,7 @@ protected function _unitBaseCalculation($item, $request) $item->setTaxPercent($rate); if ($this->_config->priceIncludesTax($this->_store)) { - if ($this->_areTaxRequestsSimilar) { + if ($this->_sameRateAsStore($request)) { $tax = $this->_calculator->calcTaxAmount($price, $rate, true); $baseTax = $this->_calculator->calcTaxAmount($basePrice, $rate, true); $taxPrice = $price; @@ -256,10 +257,14 @@ protected function _unitBaseCalculation($item, $request) } if ($item->hasCustomPrice()) { + /** + * Initialize item original price before declaring custom price + */ + $item->getOriginalPrice(); $item->setCustomPrice($price); $item->setBaseCustomPrice($basePrice); } else { - $item->setOriginalPrice($price); + $item->setConvertedPrice($price); } $item->setPrice($basePrice); $item->setBasePrice($basePrice); @@ -288,7 +293,8 @@ protected function _unitBaseCalculation($item, $request) */ protected function _rowBaseCalculation($item, $request) { - $rate = $this->_calculator->getRate($request->setProductClassId($item->getProduct()->getTaxClassId())); + $request->setProductClassId($item->getProduct()->getTaxClassId()); + $rate = $this->_calculator->getRate($request); $qty = $item->getTotalQty(); $price = $taxPrice = $item->getCalculationPrice(); @@ -303,7 +309,7 @@ protected function _rowBaseCalculation($item, $request) $item->setTaxPercent($rate); if ($this->_config->priceIncludesTax($this->_store)) { - if ($this->_areTaxRequestsSimilar) { + if ($this->_sameRateAsStore($request)) { $rowTax = $this->_calculator->calcTaxAmount($subtotal, $rate, true); $baseRowTax = $this->_calculator->calcTaxAmount($baseSubtotal, $rate, true); $taxPrice = $price; @@ -364,10 +370,14 @@ protected function _rowBaseCalculation($item, $request) } if ($item->hasCustomPrice()) { + /** + * Initialize item original price before declaring custom price + */ + $item->getOriginalPrice(); $item->setCustomPrice($price); $item->setBaseCustomPrice($basePrice); } else { - $item->setOriginalPrice($price); + $item->setConvertedPrice($price); } $item->setPrice($basePrice); $item->setBasePrice($basePrice); @@ -401,7 +411,8 @@ protected function _rowBaseCalculation($item, $request) protected function _totalBaseCalculation($item, $request) { $calc = $this->_calculator; - $rate = $calc->getRate($request->setProductClassId($item->getProduct()->getTaxClassId())); + $request->setProductClassId($item->getProduct()->getTaxClassId()); + $rate = $calc->getRate($request); $qty = $item->getTotalQty(); $price = $taxPrice = $item->getCalculationPrice(); @@ -415,7 +426,7 @@ protected function _totalBaseCalculation($item, $request) } $item->setTaxPercent($rate); if ($this->_config->priceIncludesTax($this->_store)) { - if ($this->_areTaxRequestsSimilar) { + if ($this->_sameRateAsStore($request)) { $rowTax = $this->_deltaRound($calc->calcTaxAmount($subtotal, $rate, true, false), $rate, true); $baseRowTax = $this->_deltaRound($calc->calcTaxAmount($baseSubtotal, $rate, true, false), $rate, true, 'base'); $taxPrice = $price; @@ -476,10 +487,14 @@ protected function _totalBaseCalculation($item, $request) } if ($item->hasCustomPrice()) { + /** + * Initialize item original price before declaring custom price + */ + $item->getOriginalPrice(); $item->setCustomPrice($price); $item->setBaseCustomPrice($basePrice); } else { - $item->setOriginalPrice($price); + $item->setConvertedPrice($price); } $item->setPrice($basePrice); $item->setBasePrice($basePrice); @@ -502,6 +517,27 @@ protected function _totalBaseCalculation($item, $request) return $this; } + /** + * Checks whether request for an item has same rate as store one + * Used only after collect() started, as far as uses optimized $_areTaxRequestsSimilar property + * Used only in case of prices including tax + * + * @param Varien_Object $request + * @return bool + */ + protected function _sameRateAsStore($request) + { + // Maybe we know that all requests for currently collected items have same rates + if ($this->_areTaxRequestsSimilar) { + return true; + } + + // Check current request individually + $rate = $this->_calculator->getRate($request); + $storeRate = $this->_calculator->getStoreRate($request, $this->_store); + return $rate == $storeRate; + } + /** * Round price based on previous rounding operation delta * @@ -541,8 +577,8 @@ protected function _recalculateParent(Mage_Sales_Model_Quote_Item_Abstract $item $rowTotalInclTax = 0; $baseRowTotalInclTax= 0; foreach ($item->getChildren() as $child) { - $price += $child->getOriginalPrice(); - $basePrice += $child->getBaseOriginalPrice(); + $price += $child->getOriginalPrice() * $child->getQty(); + $basePrice += $child->getBaseOriginalPrice() * $child->getQty(); $rowTotal += $child->getRowTotal(); $baseRowTotal += $child->getBaseRowTotal(); $priceInclTax += $child->getPriceInclTax(); @@ -550,7 +586,7 @@ protected function _recalculateParent(Mage_Sales_Model_Quote_Item_Abstract $item $rowTotalInclTax += $child->getRowTotalInclTax(); $baseRowTotalInclTax+= $child->getBaseRowTotalInclTax(); } - $item->setOriginalPrice($price); + $item->setConvertedPrice($price); $item->setPrice($basePrice); $item->setRowTotal($rowTotal); $item->setBaseRowTotal($baseRowTotal); diff --git a/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Tax.php b/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Tax.php index 49a7af6369..4be8226dec 100644 --- a/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Tax.php +++ b/app/code/core/Mage/Tax/Model/Sales/Total/Quote/Tax.php @@ -367,11 +367,14 @@ protected function _calcRowTaxAmount($item, $rate) case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL: $discountAmount = $item->getDiscountAmount(); $baseDiscountAmount = $item->getBaseDiscountAmount(); - $rowTax = $this->_calculator->calcTaxAmount($subtotal - $discountAmount, $rate, $inclTax); - $baseRowTax = $this->_calculator->calcTaxAmount($baseSubtotal - $baseDiscountAmount, $rate, $inclTax); + $rowTax = $this->_calculator->calcTaxAmount(max($subtotal - $discountAmount, 0), $rate, $inclTax); + $baseRowTax = $this->_calculator->calcTaxAmount(max($baseSubtotal - $baseDiscountAmount, 0), $rate, $inclTax); if ($inclTax && $discountAmount>0) { $hiddenTax = $subtotal - $rowTax - $item->getRowTotal(); $baseHiddenTax = $baseSubtotal - $baseRowTax - $item->getBaseRowTotal(); + } elseif ($discountAmount>$subtotal) { // case with 100% discount on price incl. tax + $hiddenTax = $discountAmount - $subtotal; + $baseHiddenTax = $baseDiscountAmount - $baseSubtotal; } break; } @@ -446,8 +449,8 @@ protected function _aggregateTaxPerRate($item, $rate, &$taxGroups) { $inclTax = $item->getIsPriceInclTax(); $rateKey = (string) $rate; - $subtotal = $item->getTaxableAmount() + $item->getExtraRowTaxableAmount(); - $baseSubtotal = $item->getBaseTaxableAmount() + $item->getBaseExtraRowTaxableAmount(); + $taxSubtotal = $subtotal = $item->getTaxableAmount() + $item->getExtraRowTaxableAmount(); + $baseTaxSubtotal= $baseSubtotal = $item->getBaseTaxableAmount() + $item->getBaseExtraRowTaxableAmount(); $item->setTaxPercent($rate); if (!isset($taxGroups[$rateKey]['totals'])) { @@ -467,18 +470,28 @@ protected function _aggregateTaxPerRate($item, $rate, &$taxGroups) case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL: $discount = $item->getDiscountAmount(); $baseDiscount = $item->getBaseDiscountAmount(); - $subtotal -= $discount; - $baseSubtotal -= $baseDiscount; - $rowTax = $this->_calculator->calcTaxAmount($subtotal, $rate, $inclTax, false); - $baseRowTax = $this->_calculator->calcTaxAmount($baseSubtotal, $rate, $inclTax, false); + $taxSubtotal = max($subtotal - $discount, 0); + $baseTaxSubtotal = max($baseSubtotal - $baseDiscount, 0); + $rowTax = $this->_calculator->calcTaxAmount($taxSubtotal, $rate, $inclTax, false); + $baseRowTax = $this->_calculator->calcTaxAmount($baseTaxSubtotal, $rate, $inclTax, false); break; } $rowTax = $this->_deltaRound($rowTax, $rateKey, $inclTax); $baseRowTax = $this->_deltaRound($baseRowTax, $rateKey, $inclTax, 'base'); if ($inclTax && !empty($discount)) { + /** + * Becouse of delta hidden tax should be calculated based on discount amount $hiddenTax = $item->getRowTotalInclTax() - $item->getRowTotal() - $rowTax; $baseHiddenTax = $item->getBaseRowTotalInclTax() - $item->getBaseRowTotal() - $baseRowTax; + */ + $hiddenTax = $this->_calculator->calcTaxAmount($discount, $rate, $inclTax, false); + $hiddenTax = $this->_deltaRound($hiddenTax, $rateKey, $inclTax, 'hidden'); + $baseHiddenTax = $this->_calculator->calcTaxAmount($baseDiscount, $rate, $inclTax, false); + $baseHiddenTax = $this->_deltaRound($baseHiddenTax, $rate, $inclTax, 'base_hidden'); + } elseif (!empty($discount) && $discount > $subtotal) { // case with 100% discount on price incl. tax + $hiddenTax = $discount - $subtotal; + $baseHiddenTax = $baseDiscount - $baseSubtotal; } $item->setTaxAmount(max(0, $rowTax)); @@ -486,8 +499,8 @@ protected function _aggregateTaxPerRate($item, $rate, &$taxGroups) $item->setHiddenTaxAmount(max(0, $hiddenTax)); $item->setBaseHiddenTaxAmount(max(0, $baseHiddenTax)); - $taxGroups[$rateKey]['totals'][] = max(0, $subtotal); - $taxGroups[$rateKey]['base_totals'][] = max(0, $baseSubtotal); + $taxGroups[$rateKey]['totals'][] = max(0, $taxSubtotal); + $taxGroups[$rateKey]['base_totals'][] = max(0, $baseTaxSubtotal); return $this; } diff --git a/app/code/core/Mage/Tax/etc/config.xml b/app/code/core/Mage/Tax/etc/config.xml index dc65ddebf4..04f489fa8a 100644 --- a/app/code/core/Mage/Tax/etc/config.xml +++ b/app/code/core/Mage/Tax/etc/config.xml @@ -124,6 +124,14 @@ + + + + tax/observer + quoteCollectTotalsBefore + + + diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract.php index a0699a1166..5a7c74fe23 100644 --- a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract.php +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Abstract.php @@ -34,6 +34,10 @@ abstract class Mage_Usa_Model_Shipping_Carrier_Abstract extends Mage_Shipping_Mo const USA_COUNTRY_ID = 'US'; const PUERTORICO_COUNTRY_ID = 'PR'; + const GUAM_COUNTRY_ID = 'GU'; + const GUAM_REGION_CODE = 'GU'; + + protected static $_quotesCache = array(); public function getTrackingInfo($tracking) { @@ -117,4 +121,47 @@ public function proccessAdditionalValidation(Mage_Shipping_Model_Rate_Request $r } return $this; } + + /** + * Returns cache key for some request to carrier quotes service + * + * @param string|array $requestParams + * @return string + */ + protected function _getQuotesCacheKey($requestParams) + { + if (is_array($requestParams)) { + $requestParams = implode(',', array_merge(array($this->getCarrierCode()), array_keys($requestParams), $requestParams)); + } + return crc32($requestParams); + } + + /** + * Checks whether some request to rates have already been done, so we have cache for it + * Used to reduce number of same requests done to carrier service during one session + * + * Returns cached response or null + * + * @param string|array $requestParams + * @return null|string + */ + protected function _getCachedQuotes($requestParams) + { + $key = $this->_getQuotesCacheKey($requestParams); + return isset(self::$_quotesCache[$key]) ? self::$_quotesCache[$key] : null; + } + + /** + * Sets received carrier quotes to cache + * + * @param string|array $requestParams + * @param string $response + * @return Mage_Usa_Model_Shipping_Carrier_Abstract + */ + protected function _setCachedQuotes($requestParams, $response) + { + $key = $this->_getQuotesCacheKey($requestParams); + self::$_quotesCache[$key] = $response; + return $this; + } } diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Dhl.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Dhl.php index 32c5fe57d1..a3807b1fb4 100644 --- a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Dhl.php +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Dhl.php @@ -383,32 +383,34 @@ protected function _getXmlQuotes() } $request = $xml->asXML(); - $debugData = array('request' => $request); - - try { - $url = $this->getConfigData('gateway_url'); - if (!$url) { - $url = $this->_defaultGatewayUrl; + $responseBody = $this->_getCachedQuotes($request); + if ($responseBody === null) { + $debugData = array('request' => $request); + try { + $url = $this->getConfigData('gateway_url'); + if (!$url) { + $url = $this->_defaultGatewayUrl; + } + $ch = curl_init(); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_POSTFIELDS, $request); + $responseBody = curl_exec($ch); + curl_close ($ch); + + $debugData['result'] = $responseBody; + $this->_setCachedQuotes($request, $responseBody); } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - curl_setopt($ch, CURLOPT_POSTFIELDS, $request); - $responseBody = curl_exec($ch); - $debugData['result'] = $responseBody; - curl_close ($ch); - } - catch (Exception $e) { - $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); - $responseBody = ''; + catch (Exception $e) { + $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); + $responseBody = ''; + } + $this->_debug($debugData); } - $this->_debug($debugData); - $res = $this->_parseXmlResponse($responseBody); - - return $res; + return $this->_parseXmlResponse($responseBody); } protected function _createShipmentXml($shipment,$shipKey) diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Fedex.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Fedex.php index 07922f06a4..44a249cb8e 100644 --- a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Fedex.php +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Fedex.php @@ -393,37 +393,42 @@ protected function _getXmlQuotes() $xml->addChild('PackageCount', '1'); $request = $xml->asXML(); - $debugData = array('request' => $request); -/* - $client = new Zend_Http_Client(); - $client->setUri($this->getConfigData('gateway_url')); - $client->setConfig(array('maxredirects'=>0, 'timeout'=>30)); - $client->setParameterPost($request); - $response = $client->request(); - $responseBody = $response->getBody(); -*/ - try { - $url = $this->getConfigData('gateway_url'); - if (!$url) { - $url = $this->_defaultGatewayUrl; + $responseBody = $this->_getCachedQuotes($request); + if ($responseBody === null) { + $debugData = array('request' => $request); + /* + $client = new Zend_Http_Client(); + $client->setUri($this->getConfigData('gateway_url')); + $client->setConfig(array('maxredirects'=>0, 'timeout'=>30)); + $client->setParameterPost($request); + $response = $client->request(); + $responseBody = $response->getBody(); + */ + + try { + $url = $this->getConfigData('gateway_url'); + if (!$url) { + $url = $this->_defaultGatewayUrl; + } + $ch = curl_init(); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_POSTFIELDS, $request); + $responseBody = curl_exec($ch); + curl_close ($ch); + + $debugData['result'] = $responseBody; + $this->_setCachedQuotes($request, $responseBody); } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - curl_setopt($ch, CURLOPT_POSTFIELDS, $request); - $responseBody = curl_exec($ch); - $debugData['result'] = $responseBody; - curl_close ($ch); - } - catch (Exception $e) { - $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); - $responseBody = ''; + catch (Exception $e) { + $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); + $responseBody = ''; + } + $this->_debug($debugData); } - - $this->_debug($debugData); return $this->_parseXmlResponse($responseBody); } diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups.php index ef5743a25e..da8111a10f 100644 --- a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups.php +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups.php @@ -138,6 +138,11 @@ public function setRequest(Mage_Shipping_Model_Rate_Request $request) $destCountry = self::PUERTORICO_COUNTRY_ID; } + // For UPS, Guam state of the USA will be represented by Guam country + if ($destCountry == self::USA_COUNTRY_ID && $request->getDestRegionCode() == self::GUAM_REGION_CODE) { + $destCountry = self::GUAM_COUNTRY_ID; + } + $r->setDestCountry(Mage::getModel('directory/country')->load($destCountry)->getIso2Code()); $r->setDestRegionCode($request->getDestRegionCode()); @@ -244,25 +249,32 @@ protected function _getCgiQuotes() 'weight_std' => strtolower($r->getUnitMeasure()), ); $params['47_rate_chart'] = $params['47_rate_chart']['label']; - $debugData = array('request' => $params); - try { - $url = $this->getConfigData('gateway_url'); - if (!$url) { - $url = $this->_defaultCgiGatewayUrl; + + $responseBody = $this->_getCachedQuotes($params); + if ($responseBody === null) { + $debugData = array('request' => $params); + try { + $url = $this->getConfigData('gateway_url'); + if (!$url) { + $url = $this->_defaultCgiGatewayUrl; + } + $client = new Zend_Http_Client(); + $client->setUri($url); + $client->setConfig(array('maxredirects'=>0, 'timeout'=>30)); + $client->setParameterGet($params); + $response = $client->request(); + $responseBody = $response->getBody(); + + $debugData['result'] = $responseBody; + $this->_setCachedQuotes($params, $responseBody); } - $client = new Zend_Http_Client(); - $client->setUri($url); - $client->setConfig(array('maxredirects'=>0, 'timeout'=>30)); - $client->setParameterGet($params); - $response = $client->request(); - $responseBody = $response->getBody(); - $debugData['result'] = $responseBody; - } - catch (Exception $e) { - $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); - $responseBody = ''; - } - $this->_debug($debugData); + catch (Exception $e) { + $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); + $responseBody = ''; + } + $this->_debug($debugData); + } + return $this->_parseCgiResponse($responseBody); } @@ -549,8 +561,14 @@ protected function _getXmlQuotes() '48_container' => $r->getContainer(), '49_residential' => $r->getDestType(), ); - $params['10_action'] = $params['10_action']=='4'? 'Shop' : 'Rate'; - $serviceCode = $r->getProduct() ? $r->getProduct() : ''; + + if ($params['10_action'] == '4') { + $params['10_action'] = 'Shop'; + $serviceCode = null; // Service code is not relevant when we're asking ALL possible services' rates + } else { + $params['10_action'] = 'Rate'; + $serviceCode = $r->getProduct() ? $r->getProduct() : ''; + } $serviceDescription = $serviceCode ? $this->getShipmentByCode($serviceCode) : ''; $xmlRequest .= <<< XMLRequest @@ -570,11 +588,16 @@ protected function _getXmlQuotes() +XMLRequest; - - {$serviceCode} - {$serviceDescription} - + if ($serviceCode !== null) { + $xmlRequest .= "" . + "{$serviceCode}" . + "{$serviceDescription}" . + ""; + } + + $xmlRequest .= <<< XMLRequest XMLRequest; @@ -631,25 +654,30 @@ protected function _getXmlQuotes() XMLRequest; - $debugData = array('request' => $xmlRequest); - try { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest); - curl_setopt($ch, CURLOPT_TIMEOUT, 30); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (boolean)$this->getConfigFlag('mode_xml')); - $xmlResponse = curl_exec ($ch); - $debugData['result'] = $xmlResponse; - } - catch (Exception $e) { - $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); - $xmlResponse = ''; + $xmlResponse = $this->_getCachedQuotes($xmlRequest); + if ($xmlResponse === null) { + $debugData = array('request' => $xmlRequest); + try { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (boolean)$this->getConfigFlag('mode_xml')); + $xmlResponse = curl_exec ($ch); + + $debugData['result'] = $xmlResponse; + $this->_setCachedQuotes($xmlRequest, $xmlResponse); + } + catch (Exception $e) { + $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); + $xmlResponse = ''; + } + $this->_debug($debugData); } - $this->_debug($debugData); return $this->_parseXmlResponse($xmlResponse); } @@ -962,12 +990,12 @@ public function getResponse() */ public function getAllowedMethods() { - $allowed = explode(',', $this->getConfigData('allowed_methods')); - $arr = array(); - foreach ($allowed as $k) { - $arr[$k] = $this->getCode('method', $k); - } - return $arr; + $allowed = explode(',', $this->getConfigData('allowed_methods')); + $arr = array(); + $isByCode = $this->getConfigData('type') == 'UPS_XML'; + foreach ($allowed as $k) { + $arr[$k] = $isByCode ? $this->getShipmentByCode($k) : $this->getCode('method', $k); + } + return $arr; } - } diff --git a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Usps.php b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Usps.php index 583e843b4d..26c252225f 100644 --- a/app/code/core/Mage/Usa/Model/Shipping/Carrier/Usps.php +++ b/app/code/core/Mage/Usa/Model/Shipping/Carrier/Usps.php @@ -37,6 +37,12 @@ class Mage_Usa_Model_Shipping_Carrier_Usps extends Mage_Usa_Model_Shipping_Carrier_Abstract implements Mage_Shipping_Model_Carrier_Interface { + /** + * Destination Zip Code required flag + * + * @var boolean + */ + protected $_isZipCodeRequired; protected $_code = 'usps'; @@ -46,6 +52,34 @@ class Mage_Usa_Model_Shipping_Carrier_Usps protected $_defaultGatewayUrl = 'http://production.shippingapis.com/ShippingAPI.dll'; + /** + * Check is Zip Code Required + * + * @return boolean + */ + public function isZipCodeRequired() + { + if (!is_null($this->_isZipCodeRequired)) { + return $this->_isZipCodeRequired; + } + + return parent::isZipCodeRequired(); + } + + /** + * Processing additional validation to check is carrier applicable. + * + * @param Mage_Shipping_Model_Rate_Request $request + * @return Mage_Shipping_Model_Carrier_Abstract|Mage_Shipping_Model_Rate_Result_Error|boolean + */ + public function proccessAdditionalValidation(Mage_Shipping_Model_Rate_Request $request) + { + // zip code required for US + $this->_isZipCodeRequired = $this->_isUSCountry($request->getDestCountryId()); + + return parent::proccessAdditionalValidation($request); + } + public function collectRates(Mage_Shipping_Model_Rate_Request $request) { if (!$this->getConfigFlag('active')) { @@ -115,20 +149,9 @@ public function setRequest(Mage_Shipping_Model_Rate_Request $request) $r->setDestCountryId($destCountry); - /* - for GB, we cannot use United Kingdom - */ - if ($destCountry=='GB') { - $countryName = 'Great Britain and Northern Ireland'; - } else { - $countries = Mage::getResourceModel('directory/country_collection') - ->addCountryIdFilter($destCountry) - ->load() - ->getItems(); - $country = array_shift($countries); - $countryName = $country->getName(); + if (!$this->_isUSCountry($destCountry)) { + $r->setDestCountryName($this->_getCountryName($destCountry)); } - $r->setDestCountryName($countryName); if ($request->getDestPostcode()) { $r->setDestPostal($request->getDestPostcode()); @@ -172,7 +195,7 @@ protected function _setFreeMethodRequest($freeMethod) protected function _getXmlQuotes() { $r = $this->_rawRequest; - if ($r->getDestCountryId() == self::USA_COUNTRY_ID || $r->getDestCountryId() == self::PUERTORICO_COUNTRY_ID) { + if ($this->_isUSCountry($r->getDestCountryId())) { $xml = new SimpleXMLElement(''); $xml->addAttribute('USERID', $r->getUserId()); @@ -225,28 +248,31 @@ protected function _getXmlQuotes() $request = $xml->asXML(); } - $debugData = array('request' => $request); + $responseBody = $this->_getCachedQuotes($request); + if ($responseBody === null) { + $debugData = array('request' => $request); + try { + $url = $this->getConfigData('gateway_url'); + if (!$url) { + $url = $this->_defaultGatewayUrl; + } + $client = new Zend_Http_Client(); + $client->setUri($url); + $client->setConfig(array('maxredirects'=>0, 'timeout'=>30)); + $client->setParameterGet('API', $api); + $client->setParameterGet('XML', $request); + $response = $client->request(); + $responseBody = $response->getBody(); - try { - $url = $this->getConfigData('gateway_url'); - if (!$url) { - $url = $this->_defaultGatewayUrl; + $debugData['result'] = $responseBody; + $this->_setCachedQuotes($request, $responseBody); } - $client = new Zend_Http_Client(); - $client->setUri($url); - $client->setConfig(array('maxredirects'=>0, 'timeout'=>30)); - $client->setParameterGet('API', $api); - $client->setParameterGet('XML', $request); - $response = $client->request(); - $responseBody = $response->getBody(); - $debugData['result'] = $responseBody; - } - catch (Exception $e) { - $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); - $responseBody = ''; + catch (Exception $e) { + $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode()); + $responseBody = ''; + } + $this->_debug($debugData); } - - $this->_debug($debugData); return $this->_parseXmlResponse($responseBody);; } @@ -274,7 +300,7 @@ protected function _parseXmlResponse($response) $allowedMethods = explode(",", $this->getConfigData('allowed_methods')); $allMethods = $this->getCode('method'); $newMethod = false; - if ($r->getDestCountryId() == self::USA_COUNTRY_ID || $r->getDestCountryId() == self::PUERTORICO_COUNTRY_ID) { + if ($this->_isUSCountry($r->getDestCountryId())) { if (is_object($xml->Package) && is_object($xml->Package->Postage)) { foreach ($xml->Package->Postage as $postage) { // if (in_array($this->getCode('service_to_code', (string)$postage->MailService), $allowedMethods) && $this->getCode('service', $this->getCode('service_to_code', (string)$postage->MailService))) { @@ -615,4 +641,265 @@ public function getAllowedMethods() return $arr; } + /** + * Check is Сoutry U.S. Possessions and Trust Territories + * + * @param string $countyId + * @return boolean + */ + protected function _isUSCountry($countyId) + { + switch ($countyId) { + case 'AS': // Samoa American + case 'GU': // Guam + case 'MP': // Northern Mariana Islands + case 'PW': // Palau + case 'PR': // Puerto Rico + case 'VI': // Virgin Islands US + case 'US'; // United States + return true; + } + + return false; + } + + /** + * Return USPS county name by country ISO 3166-1-alpha-2 code + * Return false for unknown countries + * + * @param string $countryId + * @return string|false + */ + protected function _getCountryName($countryId) + { + $countries = array ( + 'AD' => 'Andorra', + 'AE' => 'United Arab Emirates', + 'AF' => 'Afghanistan', + 'AG' => 'Antigua and Barbuda', + 'AI' => 'Anguilla', + 'AL' => 'Albania', + 'AM' => 'Armenia', + 'AN' => 'Netherlands Antilles', + 'AO' => 'Angola', + 'AR' => 'Argentina', + 'AT' => 'Austria', + 'AU' => 'Australia', + 'AW' => 'Aruba', + 'AX' => 'Aland Island (Finland)', + 'AZ' => 'Azerbaijan', + 'BA' => 'Bosnia-Herzegovina', + 'BB' => 'Barbados', + 'BD' => 'Bangladesh', + 'BE' => 'Belgium', + 'BF' => 'Burkina Faso', + 'BG' => 'Bulgaria', + 'BH' => 'Bahrain', + 'BI' => 'Burundi', + 'BJ' => 'Benin', + 'BM' => 'Bermuda', + 'BN' => 'Brunei Darussalam', + 'BO' => 'Bolivia', + 'BR' => 'Brazil', + 'BS' => 'Bahamas', + 'BT' => 'Bhutan', + 'BW' => 'Botswana', + 'BY' => 'Belarus', + 'BZ' => 'Belize', + 'CA' => 'Canada', + 'CC' => 'Cocos Island (Australia)', + 'CD' => 'Congo, Democratic Republic of the', + 'CF' => 'Central African Republic', + 'CG' => 'Congo, Republic of the', + 'CH' => 'Switzerland', + 'CI' => 'Cote d Ivoire (Ivory Coast)', + 'CK' => 'Cook Islands (New Zealand)', + 'CL' => 'Chile', + 'CM' => 'Cameroon', + 'CN' => 'China', + 'CO' => 'Colombia', + 'CR' => 'Costa Rica', + 'CU' => 'Cuba', + 'CV' => 'Cape Verde', + 'CX' => 'Christmas Island (Australia)', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'DE' => 'Germany', + 'DJ' => 'Djibouti', + 'DK' => 'Denmark', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'DZ' => 'Algeria', + 'EC' => 'Ecuador', + 'EE' => 'Estonia', + 'EG' => 'Egypt', + 'ER' => 'Eritrea', + 'ES' => 'Spain', + 'ET' => 'Ethiopia', + 'FI' => 'Finland', + 'FJ' => 'Fiji', + 'FK' => 'Falkland Islands', + 'FM' => 'Micronesia, Federated States of', + 'FO' => 'Faroe Islands', + 'FR' => 'France', + 'GA' => 'Gabon', + 'GB' => 'Great Britain and Northern Ireland', + 'GD' => 'Grenada', + 'GE' => 'Georgia, Republic of', + 'GF' => 'French Guiana', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GL' => 'Greenland', + 'GM' => 'Gambia', + 'GN' => 'Guinea', + 'GP' => 'Guadeloupe', + 'GQ' => 'Equatorial Guinea', + 'GR' => 'Greece', + 'GS' => 'South Georgia (Falkland Islands)', + 'GT' => 'Guatemala', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HK' => 'Hong Kong', + 'HN' => 'Honduras', + 'HR' => 'Croatia', + 'HT' => 'Haiti', + 'HU' => 'Hungary', + 'ID' => 'Indonesia', + 'IE' => 'Ireland', + 'IL' => 'Israel', + 'IN' => 'India', + 'IQ' => 'Iraq', + 'IR' => 'Iran', + 'IS' => 'Iceland', + 'IT' => 'Italy', + 'JM' => 'Jamaica', + 'JO' => 'Jordan', + 'JP' => 'Japan', + 'KE' => 'Kenya', + 'KG' => 'Kyrgyzstan', + 'KH' => 'Cambodia', + 'KI' => 'Kiribati', + 'KM' => 'Comoros', + 'KN' => 'Saint Kitts (St. Christopher and Nevis)', + 'KP' => 'North Korea (Korea, Democratic People\'s Republic of)', + 'KR' => 'South Korea (Korea, Republic of)', + 'KW' => 'Kuwait', + 'KY' => 'Cayman Islands', + 'KZ' => 'Kazakhstan', + 'LA' => 'Laos', + 'LB' => 'Lebanon', + 'LC' => 'Saint Lucia', + 'LI' => 'Liechtenstein', + 'LK' => 'Sri Lanka', + 'LR' => 'Liberia', + 'LS' => 'Lesotho', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'LV' => 'Latvia', + 'LY' => 'Libya', + 'MA' => 'Morocco', + 'MC' => 'Monaco (France)', + 'MD' => 'Moldova', + 'MG' => 'Madagascar', + 'MK' => 'Macedonia, Republic of', + 'ML' => 'Mali', + 'MM' => 'Burma', + 'MN' => 'Mongolia', + 'MO' => 'Macao', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MS' => 'Montserrat', + 'MT' => 'Malta', + 'MU' => 'Mauritius', + 'MV' => 'Maldives', + 'MW' => 'Malawi', + 'MX' => 'Mexico', + 'MY' => 'Malaysia', + 'MZ' => 'Mozambique', + 'NA' => 'Namibia', + 'NC' => 'New Caledonia', + 'NE' => 'Niger', + 'NG' => 'Nigeria', + 'NI' => 'Nicaragua', + 'NL' => 'Netherlands', + 'NO' => 'Norway', + 'NP' => 'Nepal', + 'NR' => 'Nauru', + 'NZ' => 'New Zealand', + 'OM' => 'Oman', + 'PA' => 'Panama', + 'PE' => 'Peru', + 'PF' => 'French Polynesia', + 'PG' => 'Papua New Guinea', + 'PH' => 'Philippines', + 'PK' => 'Pakistan', + 'PL' => 'Poland', + 'PM' => 'Saint Pierre and Miquelon', + 'PN' => 'Pitcairn Island', + 'PT' => 'Portugal', + 'PY' => 'Paraguay', + 'QA' => 'Qatar', + 'RE' => 'Reunion', + 'RO' => 'Romania', + 'RS' => 'Serbia', + 'RU' => 'Russia', + 'RW' => 'Rwanda', + 'SA' => 'Saudi Arabia', + 'SB' => 'Solomon Islands', + 'SC' => 'Seychelles', + 'SD' => 'Sudan', + 'SE' => 'Sweden', + 'SG' => 'Singapore', + 'SH' => 'Saint Helena', + 'SI' => 'Slovenia', + 'SK' => 'Slovak Republic', + 'SL' => 'Sierra Leone', + 'SM' => 'San Marino', + 'SN' => 'Senegal', + 'SO' => 'Somalia', + 'SR' => 'Suriname', + 'ST' => 'Sao Tome and Principe', + 'SV' => 'El Salvador', + 'SY' => 'Syrian Arab Republic', + 'SZ' => 'Swaziland', + 'TC' => 'Turks and Caicos Islands', + 'TD' => 'Chad', + 'TG' => 'Togo', + 'TH' => 'Thailand', + 'TJ' => 'Tajikistan', + 'TK' => 'Tokelau (Union) Group (Western Samoa)', + 'TL' => 'East Timor (Indonesia)', + 'TM' => 'Turkmenistan', + 'TN' => 'Tunisia', + 'TO' => 'Tonga', + 'TR' => 'Turkey', + 'TT' => 'Trinidad and Tobago', + 'TV' => 'Tuvalu', + 'TW' => 'Taiwan', + 'TZ' => 'Tanzania', + 'UA' => 'Ukraine', + 'UG' => 'Uganda', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VA' => 'Vatican City', + 'VC' => 'Saint Vincent and the Grenadines', + 'VE' => 'Venezuela', + 'VG' => 'British Virgin Islands', + 'VN' => 'Vietnam', + 'VU' => 'Vanuatu', + 'WF' => 'Wallis and Futuna Islands', + 'WS' => 'Western Samoa', + 'YE' => 'Yemen', + 'YT' => 'Mayotte (France)', + 'ZA' => 'South Africa', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', + ); + + if (isset($countries[$countryId])) { + return $countries[$countryId]; + } + + return false; + } } diff --git a/app/code/core/Mage/Weee/Model/Total/Invoice/Weee.php b/app/code/core/Mage/Weee/Model/Total/Invoice/Weee.php index 4042f653ee..e11f12699f 100644 --- a/app/code/core/Mage/Weee/Model/Total/Invoice/Weee.php +++ b/app/code/core/Mage/Weee/Model/Total/Invoice/Weee.php @@ -67,10 +67,30 @@ public function collect(Mage_Sales_Model_Order_Invoice $invoice) $baseTotalTax += $baseWeeeTaxAmount; } } + + /* + * Add FPT to totals + * Notice that we check restriction on allowed tax, because + * a) for last invoice we don't need to collect FPT - it is automatically collected by subtotal/tax collector, + * that adds whole remaining (not invoiced) subtotal/tax value, so fpt is automatically included into it + * b) FPT tax is included into order subtotal/tax value, so after multiple invoices with partial item quantities + * it can happen that other collector will take some FPT value from shared subtotal/tax order value + */ + $order = $invoice->getOrder(); if (Mage::helper('weee')->includeInSubtotal($store)) { + $allowedSubtotal = $order->getSubtotal() - $order->getSubtotalInvoiced() - $invoice->getSubtotal(); + $allowedBaseSubtotal = $order->getBaseSubtotal() -$order->getBaseSubtotalInvoiced() - $invoice->getBaseSubtotal(); + $totalTax = min($allowedSubtotal, $totalTax); + $baseTotalTax = min($allowedBaseSubtotal, $baseTotalTax); + $invoice->setSubtotal($invoice->getSubtotal() + $totalTax); $invoice->setBaseSubtotal($invoice->getBaseSubtotal() + $baseTotalTax); } else { + $allowedTax = $order->getTaxAmount() - $order->getTaxInvoiced() - $invoice->getTaxAmount(); + $allowedBaseTax = $order->getBaseTaxAmount() - $order->getBaseTaxInvoiced() - $invoice->getBaseTaxAmount(); + $totalTax = min($allowedTax, $totalTax); + $baseTotalTax = min($allowedBaseTax, $baseTotalTax); + $invoice->setTaxAmount($invoice->getTaxAmount() + $totalTax); $invoice->setBaseTaxAmount($invoice->getBaseTaxAmount() + $baseTotalTax); } diff --git a/app/code/core/Mage/Widget/Block/Adminhtml/Widget/Chooser.php b/app/code/core/Mage/Widget/Block/Adminhtml/Widget/Chooser.php index a2b3884744..a510664aba 100644 --- a/app/code/core/Mage/Widget/Block/Adminhtml/Widget/Chooser.php +++ b/app/code/core/Mage/Widget/Block/Adminhtml/Widget/Chooser.php @@ -157,6 +157,9 @@ protected function _toHtml() if ($this->getHiddenEnabled()) { $hidden = new Varien_Data_Form_Element_Hidden($element->getData()); $hidden->setId("{$chooserId}value")->setForm($element->getForm()); + if ($element->getRequired()) { + $hidden->addClass('required-entry'); + } $hiddenHtml = $hidden->getElementHtml(); $element->setValue(''); } @@ -173,10 +176,12 @@ protected function _toHtml() // render label and chooser scripts $configJson = Mage::helper('core')->jsonEncode($config->getData()); return ' + + - '; } } diff --git a/app/code/core/Mage/Wishlist/Block/Links.php b/app/code/core/Mage/Wishlist/Block/Links.php index 72fece71d8..bd4373e728 100644 --- a/app/code/core/Mage/Wishlist/Block/Links.php +++ b/app/code/core/Mage/Wishlist/Block/Links.php @@ -32,17 +32,27 @@ * @package Mage_Wishlist * @author Magento Core Team */ -class Mage_Wishlist_Block_Links extends Mage_Core_Block_Template +class Mage_Wishlist_Block_Links extends Mage_Page_Block_Template_Links_Block { /** - * Add link on wishlist page in parent block + * Message after link text * - * @return Mage_Wishlist_Block_Links + * @var string */ - public function addWishlistLink() + protected $_afterText = 'class="top-link-wishlist"'; + + /** + * Position in link list + * @var int + */ + protected $_position = 30; + + /** + * Set link title, label and url + */ + public function __construct() { - $parentBlock = $this->getParentBlock(); - if ($parentBlock && $this->helper('wishlist')->isAllow()) { + if ($this->helper('wishlist')->isAllow()) { $count = $this->helper('wishlist')->getItemCount(); if ($count > 1) { $text = $this->__('My Wishlist (%d items)', $count); @@ -53,8 +63,11 @@ public function addWishlistLink() else { $text = $this->__('My Wishlist'); } - $parentBlock->addLink($text, 'wishlist', $text, true, array(), 30, null, 'class="top-link-wishlist"'); + $this->_label = $text; + $this->_title = $text; + $this->_url = $this->getUrl('wishlist'); + + parent::__construct(); } - return $this; } } diff --git a/app/design/adminhtml/default/default/layout/catalog.xml b/app/design/adminhtml/default/default/layout/catalog.xml index 231878ce84..62845d3cd2 100644 --- a/app/design/adminhtml/default/default/layout/catalog.xml +++ b/app/design/adminhtml/default/default/layout/catalog.xml @@ -67,7 +67,7 @@ - + @@ -86,13 +86,13 @@ - + - + @@ -111,13 +111,13 @@ - + - + @@ -136,7 +136,7 @@ - + @@ -156,7 +156,7 @@ Layout handle for grouped products - + @@ -214,6 +214,18 @@ Layout handle for configurable products + + + + + + + + + + + + diff --git a/app/design/frontend/default/iphone/layout/poll.xml b/app/design/adminhtml/default/default/layout/dataflow.xml similarity index 50% rename from app/design/frontend/default/iphone/layout/poll.xml rename to app/design/adminhtml/default/default/layout/dataflow.xml index dcad071c36..004c22e6aa 100644 --- a/app/design/frontend/default/iphone/layout/poll.xml +++ b/app/design/adminhtml/default/default/layout/dataflow.xml @@ -20,38 +20,27 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category design - * @package default_iphone + * @package default_default * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - ---> - - - - - - - - - - - - - - - right.poll - - + + + + diff --git a/app/design/adminhtml/default/default/layout/main.xml b/app/design/adminhtml/default/default/layout/main.xml index 68bcecc850..afc1207a07 100644 --- a/app/design/adminhtml/default/default/layout/main.xml +++ b/app/design/adminhtml/default/default/layout/main.xml @@ -36,11 +36,17 @@ Supported layout update handles (special): - admin_denied - preview - systemPreview - --> + + + + + @@ -75,6 +81,7 @@ Default layout, loads most of the pages reset.css boxes.css + custom.css skin_cssiestyles.csslt IE 8 skin_cssbelow_ie7.csslt IE 7 @@ -110,10 +117,12 @@ Default layout, loads most of the pages + - + + @@ -200,6 +209,25 @@ Base preview layout (?) + + + + + + + + + + + + + + + + + + + diff --git a/app/design/adminhtml/default/default/layout/newsletter.xml b/app/design/adminhtml/default/default/layout/newsletter.xml index 3fdaa7cf80..b85db7ffc0 100644 --- a/app/design/adminhtml/default/default/layout/newsletter.xml +++ b/app/design/adminhtml/default/default/layout/newsletter.xml @@ -30,11 +30,28 @@ - + + + + + + + + + + + + + + + + + + diff --git a/app/design/adminhtml/default/default/layout/sales.xml b/app/design/adminhtml/default/default/layout/sales.xml index f6f871103a..04612f924e 100644 --- a/app/design/adminhtml/default/default/layout/sales.xml +++ b/app/design/adminhtml/default/default/layout/sales.xml @@ -28,6 +28,7 @@ + @@ -1012,6 +1013,7 @@ customer_edit_tab_agreementssales/adminhtml_customer_edit_tab_agreement + customer_edit_tab_recurring_profilesales/adminhtml_customer_edit_tab_recurring_profile diff --git a/app/design/frontend/default/iphone/layout/googleanalytics.xml b/app/design/adminhtml/default/default/layout/search.xml similarity index 76% rename from app/design/frontend/default/iphone/layout/googleanalytics.xml rename to app/design/adminhtml/default/default/layout/search.xml index 2d8b62f6c0..0d20377043 100644 --- a/app/design/frontend/default/iphone/layout/googleanalytics.xml +++ b/app/design/adminhtml/default/default/layout/search.xml @@ -20,22 +20,16 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category design - * @package default_iphone + * @package default_default * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - ---> - - - - - - - + + + + - + diff --git a/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml b/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml index b735c2ebdf..3f25421882 100644 --- a/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml +++ b/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option.phtml @@ -42,7 +42,7 @@ optionTemplate = '
    __('Store View Title') ?> *' + '__('Input Type') ?>' + - '__('Is Required') ?>' + + 'jsQuoteEscape(Mage::helper('bundle')->__('Is Required')) ?>' + '__('Position') ?>' + ' ' + '' + diff --git a/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option/selection.phtml b/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option/selection.phtml index b0e7834c96..179b92d2a8 100644 --- a/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option/selection.phtml +++ b/app/design/adminhtml/default/default/template/bundle/product/edit/bundle/option/selection.phtml @@ -34,8 +34,8 @@ var bundleTemplateBox = '' ' ' + ' ' + ' ' + - ' ' + - ' ' + + ' ' + + ' ' + ' ' + ' ' + ' ' + @@ -54,8 +54,8 @@ var bundleTemplateRow ='' + - '' + - '' + + '' + + '' + '' + '' + '' + @@ -65,6 +65,7 @@ var bundleTemplateRow =' - diff --git a/app/design/adminhtml/default/default/template/customer/tab/addresses.phtml b/app/design/adminhtml/default/default/template/customer/tab/addresses.phtml index 784e12ea22..33d14cb36e 100644 --- a/app/design/adminhtml/default/default/template/customer/tab/addresses.phtml +++ b/app/design/adminhtml/default/default/template/customer/tab/addresses.phtml @@ -71,7 +71,7 @@
    __('Price') ?>__('Price Type') ?>__('Default Qty') ?>__('User Defined Qty') ?>__('Position') ?>jsQuoteEscape(Mage::helper('bundle')->__('User Defined Qty')) ?>__('Position') ?>__('Default') ?> 
    ' + ' helper('sales')->__('SKU') ?>: {{sku}}' + ' ' + 'getPriceTypeSelectHtml() ?>getPriceTypeSelectHtml() ?>
    getCheckboxScopeHtml() ?>
    getQtyTypeSelectHtml() ?>' + Bundle.Selection = Class.create(); Bundle.Selection.prototype = { idLabel : 'getFieldId() ?>', + scopePrice : isUsedWebsitePrice() ?>, templateSyntax : /(^|.|\r|\n)({{(\w+)}})/, templateBox : '', templateRow : '', @@ -152,6 +153,18 @@ Bundle.Selection.prototype = { }); } + var checkbox = $(this.idLabel + '_'+data.index+'_price_scope'); + if (checkbox && this.scopePrice) { + if (data.price_scope === undefined) { + checkbox.up().hide(); + } else if(!data.price_scope) { + checkbox.checked = true; + this.addScope(null, checkbox); + } + } + + this.bindScopeCheckbox(); + if (option_type.value == 'multi' || option_type.value == 'checkbox') { /** * Hide not needed elements (user defined qty select box) @@ -177,6 +190,32 @@ Bundle.Selection.prototype = { } }, + bindScopeCheckbox : function(){ + var checkboxes = $$('.bundle-option-price-scope-checkbox'); + for (var i=0;i__('Are you sure you want to delete this category?') ?>')){ - if(useAjax){ - tree.nodeForDelete = tree.currentNodeId; + + /** + * Delete some category + * This routine get categoryId explicitly, so even if currently selected tree node is out of sync + * with this form, we surely delete same category in the tree and at backend + */ + function categoryDelete(url, useAjax, categoryId) { + if (confirm('__('Are you sure you want to delete this category?') ?>')){ + if (useAjax){ + tree.nodeForDelete = categoryId; updateContent(url, {}, true); - }else{ + } else { location.href = url; } } - } /** @@ -67,17 +72,30 @@ params.form_key = FORM_KEY; } + toolbarToggle.stop(); + /*if(params.node_name) { var currentNode = tree.getNodeById(tree.currentNodeId); currentNode.setText(params.node_name); }*/ + var categoryContainer = $('category-edit-container'); var messagesContainer = $('messages'); + var thisObj = this; new Ajax.Request(url + (url.match(new RegExp('\\?')) ? '&isAjax=true' : '?isAjax=true' ), { parameters: params, evalScripts: true, - onComplete: refreshTree ? refreshTreeArea.bind(this) : false, + onComplete: function () { + try { + if (refreshTree) { + thisObj.refreshTreeArea(); + } + toolbarToggle.start(); + } catch (e) { + alert(e.message); + }; + }, onSuccess: function(transport) { try { if (transport.responseText.isJSON()) { @@ -108,12 +126,6 @@ } } }); - var headers = $$('div.content-header-floating'); - for(var i=0; i; - -updateTopButtonToolbarToggle(); - //]]> diff --git a/app/design/adminhtml/default/default/template/catalog/category/tree.phtml b/app/design/adminhtml/default/default/template/catalog/category/tree.phtml index 8271839118..0b5da90ff7 100644 --- a/app/design/adminhtml/default/default/template/catalog/category/tree.phtml +++ b/app/design/adminhtml/default/default/template/catalog/category/tree.phtml @@ -176,7 +176,6 @@ Ext.extend(Ext.tree.TreePanel.Enhanced, Ext.tree.TreePanel, { var url = parseSidUrl(baseUrl, urlExt); this.currentNodeId = node.id; - this.addNodeTo = false; if (!this.useAjax) { setLocation(url); return; @@ -368,8 +367,7 @@ Ext.onReady(function() useAjax : getUseAjax() ?>, switchTreeUrl : 'getSwitchTreeUrl() ?>', editUrl : 'getEditUrl() ?>', - currentNodeId : getCategoryId() ?>, - addNodeTo : false//, + currentNodeId : getCategoryId() ?> }; defaultLoadTreeParams = { @@ -393,7 +391,6 @@ function addNew(url, isRoot) if (isRoot) { tree.currentNodeId = tree.root.id; } - tree.addNodeTo = tree.currentNodeId; if (/store\/\d+/.test(url)) { url = url.replace(/store\/\d+/, "store/" + tree.storeId); diff --git a/app/design/adminhtml/default/default/template/catalog/product/attribute/js.phtml b/app/design/adminhtml/default/default/template/catalog/product/attribute/js.phtml index 38b461a01d..21f3f85e4f 100644 --- a/app/design/adminhtml/default/default/template/catalog/product/attribute/js.phtml +++ b/app/design/adminhtml/default/default/template/catalog/product/attribute/js.phtml @@ -27,16 +27,24 @@ __('[GLOBAL]') ?>
    @@ -114,7 +116,9 @@ function toggleCal(id) { - + @@ -90,6 +90,7 @@ Event.observe(window, 'load', function() { ['ec','wps','ecpe'].each(function(m) { pConfig.trackMethod(m); }); + pConfig.trackPayflowpro(); pConfig.fastMode = false; pConfig.destruct(); }); @@ -295,7 +296,8 @@ PaypalConfig.prototype = { trackBusinessAccount: function() { - if (!$('paypal_account_business_account').value) { + var elem = $('paypal_account_business_account'); + if (!Validation.validate(elem) || !elem.value) { this.disableMethod('wps', true); this.disableMethod('ec', true); this.disabledMethods.push('wps','ec'); @@ -309,13 +311,18 @@ PaypalConfig.prototype = { trackWpp: function() { var enabled = this.getMethodSwitcher('wpp').checked; + var wpppeEnabled = this.getMethodSwitcher('wpppe').checked; if (enabled) { this.enableMethod('wpp',false); - this.enableMethod('ec',true); + if (!wpppeEnabled) { + this.enableMethod('ec',true); + } } else { this.disableMethod('wpp',false); - this.markMethodAsReadonly('ec',false); + if (!wpppeEnabled) { + this.markMethodAsReadonly('ec',false); + } } this.trackWps(); }, @@ -338,7 +345,14 @@ PaypalConfig.prototype = { var wpppeEnabled = this.getMethodSwitcher('wpppe').checked; if (wpppeEnabled) { this.enableMethod('ecpe',true); + this.disableMethod('ec',true); return; + } else { + if (!this.getMethodSwitcher('wpp').checked) { + this.markMethodAsReadonly('ec', false); + } else { + this.enableMethod('ec',true); + } } var disabled = !wpppeEnabled && !this.getMethodSwitcher('payflowpro').checked; if (disabled) { @@ -381,7 +395,7 @@ PaypalConfig.prototype = { isHidden ? fieldset.hide() : fieldset.show(); var heading = fieldset.previous('div'); var headingLink = heading.down('a'); - isHidden ? heading.addClassName('disabled') : heading.removeClassName('disabled'); + isHidden ? heading.addClassName('disabled').addClassName('no-display') : heading.removeClassName('disabled').removeClassName('no-display'); if (isHidden) { headingLink.oldHref = headingLink.href; headingLink.oldOnclick = headingLink.onclick; diff --git a/app/design/adminhtml/default/default/template/report/grid.phtml b/app/design/adminhtml/default/default/template/report/grid.phtml index 0d317c3d65..c94dd1966b 100644 --- a/app/design/adminhtml/default/default/template/report/grid.phtml +++ b/app/design/adminhtml/default/default/template/report/grid.phtml @@ -168,7 +168,7 @@ $numColumns = sizeof($this->getColumns()); getEmptyText()): ?> - + diff --git a/app/design/adminhtml/default/default/template/sales/order/comments/view.phtml b/app/design/adminhtml/default/default/template/sales/order/comments/view.phtml index 4bc2a27edb..1d065acaa0 100644 --- a/app/design/adminhtml/default/default/template/sales/order/comments/view.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/comments/view.phtml @@ -30,12 +30,13 @@ - canSendCommentEmail()): ?>
    - - + canSendCommentEmail()): ?> + +
    + +
    -
    getChildHtml('submit_button') ?>
    diff --git a/app/design/adminhtml/default/default/template/sales/order/create/coupons/form.phtml b/app/design/adminhtml/default/default/template/sales/order/create/coupons/form.phtml index f290389794..9f9808823c 100644 --- a/app/design/adminhtml/default/default/template/sales/order/create/coupons/form.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/create/coupons/form.phtml @@ -40,6 +40,10 @@ getCouponCode()): ?>

    getCouponCode() ?> [__('Remove') ?>]

    + diff --git a/app/design/adminhtml/default/default/template/sales/order/create/form.phtml b/app/design/adminhtml/default/default/template/sales/order/create/form.phtml index 95fed2a751..42d5c33ac7 100644 --- a/app/design/adminhtml/default/default/template/sales/order/create/form.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/create/form.phtml @@ -30,7 +30,7 @@ var payment = {}; payment.switchMethod = order.switchPaymentMethod.bind(order); - +getBlockHtml('formkey')?>
    getChildHtml('message') ?> diff --git a/app/design/adminhtml/default/default/template/sales/order/create/form/address.phtml b/app/design/adminhtml/default/default/template/sales/order/create/form/address.phtml index 2a8d4ab621..319b79dd07 100644 --- a/app/design/adminhtml/default/default/template/sales/order/create/form/address.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/create/form/address.phtml @@ -25,6 +25,7 @@ */ if($this->getIsShipping()): $_fieldsContainerId = 'order-shipping_address_fields'; + $_addressChoiceContainerId = 'order-shipping_address_choice'; ?> diff --git a/app/design/adminhtml/default/default/template/sales/order/create/totals.phtml b/app/design/adminhtml/default/default/template/sales/order/create/totals.phtml index e0c7af662a..b8e16d621a 100644 --- a/app/design/adminhtml/default/default/template/sales/order/create/totals.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/create/totals.phtml @@ -44,3 +44,21 @@

    getButtonHtml(Mage::helper('sales')->__('Submit Order'),'order.submit()','save'); ?>

    + + diff --git a/app/design/adminhtml/default/default/template/sales/order/creditmemo/create/form.phtml b/app/design/adminhtml/default/default/template/sales/order/creditmemo/create/form.phtml index f4fb293b2a..faa8a9f0d9 100644 --- a/app/design/adminhtml/default/default/template/sales/order/creditmemo/create/form.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/creditmemo/create/form.phtml @@ -60,7 +60,7 @@ getShippingDescription() ?>helper('sales')->__('Total Shipping Charges'); ?>: - helper('tax')->displayShippingPriceIncludingTax()): ?> + helper('tax')->displaySalesPriceInclTax($this->getSource()->getStoreId())): ?> displayShippingPriceInclTax($_order); ?> displayPriceAttribute('shipping_amount', false, ' '); ?> @@ -68,7 +68,7 @@ displayShippingPriceInclTax($_order); ?> - helper('tax')->displayShippingBothPrices() && $_incl != $_excl): ?> + helper('tax')->displaySalesBothPrices($this->getSource()->getStoreId()) && $_incl != $_excl): ?> (__('Incl. Tax'); ?> ) diff --git a/app/design/adminhtml/default/default/template/sales/order/shipment/create/form.phtml b/app/design/adminhtml/default/default/template/sales/order/shipment/create/form.phtml index bdbff321ac..b414e71e90 100644 --- a/app/design/adminhtml/default/default/template/sales/order/shipment/create/form.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/shipment/create/form.phtml @@ -80,3 +80,6 @@ getItemsHtml() ?> + diff --git a/app/design/adminhtml/default/default/template/sales/order/shipment/create/tracking.phtml b/app/design/adminhtml/default/default/template/sales/order/shipment/create/tracking.phtml index 6b198d28b6..b5533ca6b8 100644 --- a/app/design/adminhtml/default/default/template/sales/order/shipment/create/tracking.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/shipment/create/tracking.phtml @@ -80,7 +80,7 @@ trackingControl = { - + @@ -99,7 +99,7 @@ trackingControl = { - + diff --git a/app/design/adminhtml/default/default/template/sales/order/view/info.phtml b/app/design/adminhtml/default/default/template/sales/order/view/info.phtml index 8b3f33aa12..3346f25201 100644 --- a/app/design/adminhtml/default/default/template/sales/order/view/info.phtml +++ b/app/design/adminhtml/default/default/template/sales/order/view/info.phtml @@ -49,26 +49,26 @@ $orderStoreDate = $this->formatDate($_order->getCreatedAtStoreDate(), 'medium',
    getChildHtml('diagrams') ?> + getChild('diagrams')->getTabsIds())) : ?>
    +
    getChildHtml('totals') ?>
    diff --git a/app/design/adminhtml/default/default/template/login.phtml b/app/design/adminhtml/default/default/template/login.phtml index c9ca21ec81..c6e6909537 100644 --- a/app/design/adminhtml/default/default/template/login.phtml +++ b/app/design/adminhtml/default/default/template/login.phtml @@ -34,7 +34,6 @@ - diff --git a/app/design/adminhtml/default/default/template/newsletter/queue/edit.phtml b/app/design/adminhtml/default/default/template/newsletter/queue/edit.phtml index c1307887f0..91d0571602 100644 --- a/app/design/adminhtml/default/default/template/newsletter/queue/edit.phtml +++ b/app/design/adminhtml/default/default/template/newsletter/queue/edit.phtml @@ -23,6 +23,7 @@ * @copyright Copyright (c) 2010 Magento 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_Newsletter_Queue_Edit */ ?>
    @@ -32,8 +33,6 @@ getBackButtonHtml() ?> getIsPreview()): ?> getResetButtonHtml() ?> - getIsTextType()): ?> - getSaveButtonHtml() ?> getCanResume()): ?> @@ -43,6 +42,9 @@
    +isSingleStoreMode() ): ?> +getChildHtml('store_switcher');?> +
    getBlockHtml('formkey')?>
    @@ -50,15 +52,57 @@
    getChildHtml('form') ?>
    +
    + getBlockHtml('formkey')?> +
    + + + +isSingleStoreMode()): ?> + + +
    +
    + + diff --git a/app/design/adminhtml/default/default/template/newsletter/template/preview/store.phtml b/app/design/adminhtml/default/default/template/newsletter/template/preview/store.phtml new file mode 100644 index 0000000000..ac363f8206 --- /dev/null +++ b/app/design/adminhtml/default/default/template/newsletter/template/preview/store.phtml @@ -0,0 +1,60 @@ + + +getWebsites()): ?> + + + + diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/description.phtml b/app/design/adminhtml/default/default/template/notification/security.phtml similarity index 72% rename from app/design/frontend/default/iphone/template/catalog/product/view/description.phtml rename to app/design/adminhtml/default/default/template/notification/security.phtml index 7044f142eb..2bb374543f 100644 --- a/app/design/frontend/default/iphone/template/catalog/product/view/description.phtml +++ b/app/design/adminhtml/default/default/template/notification/security.phtml @@ -19,17 +19,14 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category design - * @package default_iphone + * @package default_default * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - /** - * Product description template - * - * @see Mage_Catalog_Block_Product_View_Description + * @see Mage_Adminhtml_Block_Notification_Baseurl */ ?> -
    - helper('catalog/output')->productAttribute($this->getProduct(), $this->getProduct()->getDescription(), 'description') ?> +
    + helper('adminhtml')->__('Your web server is configured incorrectly. As a result, configuration files with sensitive information are accessible from the outside. Please contact your hosting provider.')?>
    diff --git a/app/design/adminhtml/default/default/template/payment/form/cc.phtml b/app/design/adminhtml/default/default/template/payment/form/cc.phtml index 5b40dabe28..1bd889c5a3 100644 --- a/app/design/adminhtml/default/default/template/payment/form/cc.phtml +++ b/app/design/adminhtml/default/default/template/payment/form/cc.phtml @@ -69,4 +69,49 @@
    + + hasSsCardType()): ?> +
  • +
      +
    • +
    • + + + + +
    • + +
    • + +
      + + +
      +
    • +
    •  
    • +
    + +
  • + diff --git a/app/design/adminhtml/default/default/template/payment/form/ccsave.phtml b/app/design/adminhtml/default/default/template/payment/form/ccsave.phtml index 5a2dcf9245..a281bae15f 100644 --- a/app/design/adminhtml/default/default/template/payment/form/ccsave.phtml +++ b/app/design/adminhtml/default/default/template/payment/form/ccsave.phtml @@ -75,4 +75,48 @@
    + hasSsCardType()): ?> +
  • +
      +
    • +
    • + + + + +
    • + +
    • + +
      + + +
      +
    • +
    •  
    • +
    + +
  • + diff --git a/app/design/adminhtml/default/default/template/paypal/system/config/api_wizard.phtml b/app/design/adminhtml/default/default/template/paypal/system/config/api_wizard.phtml index 9881a9488d..83a18d30e2 100644 --- a/app/design/adminhtml/default/default/template/paypal/system/config/api_wizard.phtml +++ b/app/design/adminhtml/default/default/template/paypal/system/config/api_wizard.phtml @@ -29,6 +29,17 @@ * @see Mage_Paypal_Block_Adminhtml_System_Config_ApiWizard */ ?> - + + + + + +
    + + + +
    diff --git a/app/design/adminhtml/default/default/template/paypal/system/config/fieldset/global.phtml b/app/design/adminhtml/default/default/template/paypal/system/config/fieldset/global.phtml index 8659967cd4..d5c4ae6e4d 100644 --- a/app/design/adminhtml/default/default/template/paypal/system/config/fieldset/global.phtml +++ b/app/design/adminhtml/default/default/template/paypal/system/config/fieldset/global.phtml @@ -34,8 +34,8 @@
    escapeHtml($this->getFieldsetLabel()) ?> - __('Help')?> + escapeHtml($this->getFieldsetLabel()) ?>__('Help')?>
    getEmptyText() ?>getEmptyText() ?>
    __('Carrier') ?> __('Title') ?>__('Number') ?>__('Number') ?> * __('Action') ?>
    __('Delete') ?>
    - + - + - + - + getRelationChildId()): ?> - @@ -76,7 +76,7 @@ $orderStoreDate = $this->formatDate($_order->getCreatedAtStoreDate(), 'medium', getRelationParentId()): ?> - @@ -84,19 +84,19 @@ $orderStoreDate = $this->formatDate($_order->getCreatedAtStoreDate(), 'medium', getRemoteIp()): ?> - + getGlobalCurrencyCode() != $_order->getBaseCurrencyCode()): ?> - + getBaseCurrencyCode() != $_order->getOrderCurrencyCode()): ?> - +
    getStatusLabel() ?>getStatusLabel() ?>
    getOrderStoreName() ?>getOrderStoreName() ?>
    + getRelationChildRealId() ?>
    + getRelationParentRealId() ?>
    getRemoteIp(); echo ($_order->getXForwardedFor())?' (' . $_order->getXForwardedFor() . ')':''; ?>getRemoteIp(); echo ($_order->getXForwardedFor())?' (' . $_order->getXForwardedFor() . ')':''; ?>
    getBaseToGlobalRate() ?>getBaseToGlobalRate() ?>
    getBaseToOrderRate() ?>getBaseToOrderRate() ?>
    @@ -114,7 +114,7 @@ $orderStoreDate = $this->formatDate($_order->getCreatedAtStoreDate(), 'medium', - - + - getCustomerGroupName()) : ?> + getCustomerGroupName()) : ?> - + - getOrder()->getCustomerDob()) : ?> + getCustomerAccountData() as $data):?> - - + + - - getCustomerTaxvat()):?> - - - - - +
    + getCustomerViewUrl()) : ?> htmlEscape($_order->getCustomerName()) ?> @@ -124,26 +124,20 @@ $orderStoreDate = $this->formatDate($_order->getCreatedAtStoreDate(), 'medium',
    getCustomerEmail() ?>getCustomerEmail() ?>
    formatDate($_dob, 'medium') ?>
    htmlEscape($_taxvat)?>
    diff --git a/app/design/adminhtml/default/default/template/sales/recurring/profile/view/info.phtml b/app/design/adminhtml/default/default/template/sales/recurring/profile/view/info.phtml index c3133a8216..8d00e7515e 100644 --- a/app/design/adminhtml/default/default/template/sales/recurring/profile/view/info.phtml +++ b/app/design/adminhtml/default/default/template/sales/recurring/profile/view/info.phtml @@ -36,12 +36,11 @@ getRenderedInfo() as $row):?> -getObjectData($row, 'value');?> getObjectData($row, 'is_amount');?> > -escapeHtml(implode("\n", $value))) : $this->escapeHtml($value)) ?> + renderRowValue($row) ?> diff --git a/app/design/adminhtml/default/default/template/system/convert/profile/process.phtml b/app/design/adminhtml/default/default/template/system/convert/profile/process.phtml new file mode 100644 index 0000000000..fa32971e2f --- /dev/null +++ b/app/design/adminhtml/default/default/template/system/convert/profile/process.phtml @@ -0,0 +1,205 @@ + + + +
      +
    • + getProfile()->getId()):?> + + __("Starting profile execution, please wait...");?> +
    • +
    • + + __("Warning: Please do not close the window during importing/exporting data");?> + + + __("No profile loaded...");?> + +
    • +
    + + getProfile()->getId()):?> +
      + getExceptions() as $exceptionInfo):?> +
    • + + + + () + +
    • + + getProfile()->getEntityType() == 'product' && $this->getProfile()->getDirection() == 'import'):?> + + + +
    + getBatchModel()->getId()):?> + getBatchModelHasAdapter()):?> + + + getImportData();?> + + + + getShowFinished()):?> + + + diff --git a/app/design/adminhtml/default/default/template/widget/grid.phtml b/app/design/adminhtml/default/default/template/widget/grid.phtml index c603cc55d4..7ad1af5725 100644 --- a/app/design/adminhtml/default/default/template/widget/grid.phtml +++ b/app/design/adminhtml/default/default/template/widget/grid.phtml @@ -120,9 +120,6 @@ $numColumns = sizeof($this->getColumns());
    getColumns() as $_column): ?> getHtmlProperty() ?> /> - getEditable() && !$_column->getEditOnly()) : ?> - getHtmlProperty() ?> /> - getHeadersVisibility() || $this->getFilterVisibility()): ?> @@ -197,7 +194,7 @@ $numColumns = sizeof($this->getColumns()); getEmptyText()): ?> - + diff --git a/app/design/adminhtml/default/default/template/widget/grid/serializer.phtml b/app/design/adminhtml/default/default/template/widget/grid/serializer.phtml index 1404389373..3994a036c2 100644 --- a/app/design/adminhtml/default/default/template/widget/grid/serializer.phtml +++ b/app/design/adminhtml/default/default/template/widget/grid/serializer.phtml @@ -30,7 +30,26 @@ */ ?> +getFormId()?> + + + + + diff --git a/app/design/frontend/default/iphone/layout/sendfriend.xml b/app/design/adminhtml/default/find/layout/feed.xml similarity index 57% rename from app/design/frontend/default/iphone/layout/sendfriend.xml rename to app/design/adminhtml/default/find/layout/feed.xml index bb87bd545a..a70f678ec6 100644 --- a/app/design/frontend/default/iphone/layout/sendfriend.xml +++ b/app/design/adminhtml/default/find/layout/feed.xml @@ -20,21 +20,27 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category design - * @package default_iphone + * @package default_find * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ --> - - - - - + + + - + jsprototype/window.js + js_cssprototype/windows/themes/default.css + js_cssprototype/windows/themes/magento.css + + + + + + - + - - + + diff --git a/app/design/adminhtml/default/find/template/head/window.phtml b/app/design/adminhtml/default/find/template/head/window.phtml new file mode 100644 index 0000000000..2883f1ca6d --- /dev/null +++ b/app/design/adminhtml/default/find/template/head/window.phtml @@ -0,0 +1,42 @@ + diff --git a/app/design/frontend/base/default/layout/bundle.xml b/app/design/frontend/base/default/layout/bundle.xml index 26ee31e34e..4d22f27379 100644 --- a/app/design/frontend/base/default/layout/bundle.xml +++ b/app/design/frontend/base/default/layout/bundle.xml @@ -92,18 +92,6 @@ Adding custom product price block - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - bundlebundle/catalog_product_price diff --git a/app/design/frontend/base/default/layout/catalog.xml b/app/design/frontend/base/default/layout/catalog.xml index 6f5e580fe8..3d6245d4f5 100644 --- a/app/design/frontend/base/default/layout/catalog.xml +++ b/app/design/frontend/base/default/layout/catalog.xml @@ -274,16 +274,20 @@ Additional block dependant on product type - - + + + + - - + + + + @@ -294,15 +298,19 @@ Additional block dependant on product type - + + + - - + + + + diff --git a/app/design/frontend/base/default/layout/checkout.xml b/app/design/frontend/base/default/layout/checkout.xml index 94a7504fc7..cf48556e14 100644 --- a/app/design/frontend/base/default/layout/checkout.xml +++ b/app/design/frontend/base/default/layout/checkout.xml @@ -46,7 +46,9 @@ Default layout, loads most of the pages simplecheckout/cart_item_renderer groupedcheckout/cart_item_renderer_grouped configurablecheckout/cart_item_renderer_configurable - + + + @@ -90,6 +92,9 @@ Default layout, loads most of the pages + + + - + + @@ -387,7 +397,9 @@ One page checkout order review block groupedcheckout/cart_item_renderer_grouped configurablecheckout/cart_item_renderer_configurable - + + + @@ -409,4 +421,5 @@ One page checkout order review block + diff --git a/app/design/frontend/base/default/layout/cms.xml b/app/design/frontend/base/default/layout/cms.xml index 70c1190f33..9176e45f88 100644 --- a/app/design/frontend/base/default/layout/cms.xml +++ b/app/design/frontend/base/default/layout/cms.xml @@ -46,7 +46,8 @@ Default layout, loads most of the pages - + + std diff --git a/app/design/frontend/base/default/layout/customer.xml b/app/design/frontend/base/default/layout/customer.xml index 1e6bfc9ecc..ce903e939e 100644 --- a/app/design/frontend/base/default/layout/customer.xml +++ b/app/design/frontend/base/default/layout/customer.xml @@ -129,7 +129,9 @@ New customer registration - + + + @@ -191,7 +193,8 @@ Customer account pages, rendered for all tabs in dashboard - + + my-account diff --git a/app/design/frontend/base/default/layout/googlecheckout.xml b/app/design/frontend/base/default/layout/googlecheckout.xml index 73f8bc50ab..a9f643dded 100644 --- a/app/design/frontend/base/default/layout/googlecheckout.xml +++ b/app/design/frontend/base/default/layout/googlecheckout.xml @@ -36,10 +36,6 @@ - - - true - diff --git a/app/design/frontend/base/default/layout/newsletter.xml b/app/design/frontend/base/default/layout/newsletter.xml index 2fd687cd69..36e46e43c5 100644 --- a/app/design/frontend/base/default/layout/newsletter.xml +++ b/app/design/frontend/base/default/layout/newsletter.xml @@ -58,7 +58,8 @@ Customer account pages, rendered for all tabs in dashboard - + + 1 diff --git a/app/design/frontend/base/default/layout/page.xml b/app/design/frontend/base/default/layout/page.xml index 6184aebcb6..d68f4308d9 100644 --- a/app/design/frontend/base/default/layout/page.xml +++ b/app/design/frontend/base/default/layout/page.xml @@ -59,14 +59,18 @@ Default layout, loads most of the pages skin_jsjs/ie6.jslt IE 7 - + + + - + + + top-container @@ -99,7 +103,9 @@ Default layout, loads most of the pages - + + + diff --git a/app/design/frontend/base/default/layout/paypal.xml b/app/design/frontend/base/default/layout/paypal.xml index d397b86048..c7c3c3eb3c 100644 --- a/app/design/frontend/base/default/layout/paypal.xml +++ b/app/design/frontend/base/default/layout/paypal.xml @@ -86,9 +86,8 @@ Available logo types can be assigned with action="setLogoType": --> - - p - paypal-logo + + 1 diff --git a/app/design/frontend/base/default/layout/paypaluk.xml b/app/design/frontend/base/default/layout/paypaluk.xml index bd46bbc28b..4d352d022b 100644 --- a/app/design/frontend/base/default/layout/paypaluk.xml +++ b/app/design/frontend/base/default/layout/paypaluk.xml @@ -75,7 +75,8 @@ - + + p paypal-logo diff --git a/app/design/frontend/base/default/layout/productalert.xml b/app/design/frontend/base/default/layout/productalert.xml index 7116a0f963..8eb1987ddb 100644 --- a/app/design/frontend/base/default/layout/productalert.xml +++ b/app/design/frontend/base/default/layout/productalert.xml @@ -24,15 +24,22 @@ * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - --> - - + + + alert-price link-price-alert + Sign up for price alert + + + + alert-stock link-stock-alert + Sign up to get notified when this product is back in stock + diff --git a/app/design/frontend/base/default/layout/review.xml b/app/design/frontend/base/default/layout/review.xml index ba3d1de0ce..82e57d7647 100644 --- a/app/design/frontend/base/default/layout/review.xml +++ b/app/design/frontend/base/default/layout/review.xml @@ -86,7 +86,8 @@ Product reviews page - + + 1 diff --git a/app/design/frontend/base/default/layout/sales.xml b/app/design/frontend/base/default/layout/sales.xml index 89d1b7eeaa..837e1b1f9a 100644 --- a/app/design/frontend/base/default/layout/sales.xml +++ b/app/design/frontend/base/default/layout/sales.xml @@ -73,7 +73,9 @@ Customer account home dashboard layout - + + + @@ -119,6 +121,7 @@ Customer account home dashboard layout class="last a-right" + @@ -138,6 +141,7 @@ Customer account home dashboard layout defaultsales/order_item_renderer_default + @@ -163,6 +167,7 @@ Customer account home dashboard layout class="a-right" + diff --git a/app/design/frontend/base/default/layout/sales/recurring_profile.xml b/app/design/frontend/base/default/layout/sales/recurring_profile.xml index 717f690c1a..abf1cbaa0d 100644 --- a/app/design/frontend/base/default/layout/sales/recurring_profile.xml +++ b/app/design/frontend/base/default/layout/sales/recurring_profile.xml @@ -43,6 +43,7 @@ There are no recurring profiles yet. + recurring_profile_list_view diff --git a/app/design/frontend/base/default/layout/tag.xml b/app/design/frontend/base/default/layout/tag.xml index 590a47dcbd..e61633dbb9 100644 --- a/app/design/frontend/base/default/layout/tag.xml +++ b/app/design/frontend/base/default/layout/tag.xml @@ -63,11 +63,13 @@ Customer account home dashboard layout - + + - + + 1 @@ -94,7 +96,12 @@ All tags page - + + + + + product_list_toolbar + diff --git a/app/design/frontend/base/default/layout/wishlist.xml b/app/design/frontend/base/default/layout/wishlist.xml index e5c75767b7..14728a5e61 100644 --- a/app/design/frontend/base/default/layout/wishlist.xml +++ b/app/design/frontend/base/default/layout/wishlist.xml @@ -35,9 +35,8 @@ Default layout, loads most of the pages - - - + + wishlist_link diff --git a/app/design/frontend/base/default/template/bundle/catalog/product/view/tierprices.phtml b/app/design/frontend/base/default/template/bundle/catalog/product/view/tierprices.phtml index 4a97ecc7d4..f6430cbd76 100644 --- a/app/design/frontend/base/default/template/bundle/catalog/product/view/tierprices.phtml +++ b/app/design/frontend/base/default/template/bundle/catalog/product/view/tierprices.phtml @@ -33,7 +33,7 @@ $_product = $this->getProduct(); $_tierPrices = $this->getTierPrices(); ?> 0): ?> -
      +
      • __('Buy %1$s with %2$s discount each', $_price['price_qty'], ''.($_price['price']*1).'%') ?>
      • diff --git a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle.phtml b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle.phtml index 7f96f68cd1..4bf21bf046 100644 --- a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle.phtml +++ b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle.phtml @@ -33,6 +33,8 @@ var bundle = new Product.Bundle(getJsonConfig() ?>); //]]> + +isAvailable()): ?>

        helper('catalog')->__('Availability:') ?> helper('catalog')->__('In stock') ?>

        helper('catalog')->__('Availability:') ?> helper('catalog')->__('Out of stock') ?>

        diff --git a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/checkbox.phtml b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/checkbox.phtml index 56cf006d8d..6dfa2b920e 100644 --- a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/checkbox.phtml +++ b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/checkbox.phtml @@ -27,22 +27,24 @@ ?> getOption() ?> getSelections() ?> -
        +
        getRequired()) echo ' class="required"' ?>>getRequired()) echo '*' ?>htmlEscape($_option->getTitle()) ?>
        decoratedIsLast){?> class="last"> -getRequired()): ?> - getSelectionQtyTitlePrice($_selections[0]) ?> - - -
          +
          + getRequired()): ?> + getSelectionQtyTitlePrice($_selections[0]) ?> + + +
            -
          • getIsDefault() && $_selection->isSaleable())?' checked="checked" ':'' ?>isSaleable()?' disabled="disabled" ':'' ?> value="getSelectionId() ?>" /> - - getRequired()): ?> - setValidationContainer('bundle-option-'.$_option->getId().'-'.$_selection->getSelectionId(), 'bundle-option-'.$_option->getId().'-container') ?> - -
          • - -
          - - +
        • getIsDefault() && $_selection->isSaleable())?' checked="checked" ':'' ?>isSaleable()?' disabled="disabled" ':'' ?> value="getSelectionId() ?>" /> + + getRequired()): ?> + setValidationContainer('bundle-option-'.$_option->getId().'-'.$_selection->getSelectionId(), 'bundle-option-'.$_option->getId().'-container') ?> + +
        • + +
        +
        + + diff --git a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/multi.phtml b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/multi.phtml index c9538afa72..7edf6301ba 100644 --- a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/multi.phtml +++ b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/multi.phtml @@ -28,19 +28,21 @@ getOption() ?> getSelections() ?> -
        +
        getRequired()) echo ' class="required"' ?>>getRequired()) echo '*' ?>htmlEscape($_option->getTitle()) ?>
        decoratedIsLast){?> class="last"> +
        getRequired()): ?> getSelectionQtyTitlePrice($_selections[0]) ?> - + getRequired()): ?> - - - - + + + + +
        diff --git a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/radio.phtml b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/radio.phtml index 386140ea74..0d155e2c3f 100644 --- a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/radio.phtml +++ b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/radio.phtml @@ -45,9 +45,10 @@ id="bundle-option-getId() ?>-qty-input" class="input-text qty" type="text" name="bundle_option_qty[getId() ?>]" value="" /> - + getRequired()) echo ' class="required"' ?>>getRequired()) echo '*' ?>htmlEscape($_option->getTitle()) ?> decoratedIsLast){?> class="last"> +
        getRequired()): ?> getSelectionTitlePrice($_selections[0]) ?> @@ -59,7 +60,7 @@ -
      • getIsDefault() && $_selection->isSaleable())?' checked="checked" ':'' ?>isSaleable()?' disabled="disabled" ':'' ?>value="getSelectionId() ?>" /> +
      • getIsDefault() && $_selection->isSaleable())?' checked="checked" ':'' ?>isSaleable()?' disabled="disabled" ':'' ?>value="getSelectionId() ?>" /> getRequired()): ?> setValidationContainer('bundle-option-'.$_option->getId().'-'.$_selection->getSelectionId(), 'bundle-option-'.$_option->getId().'-container') ?> @@ -67,6 +68,7 @@
      - +
      + diff --git a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/select.phtml b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/select.phtml index 9c339eaf45..871480e257 100644 --- a/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/select.phtml +++ b/app/design/frontend/base/default/template/bundle/catalog/product/view/type/bundle/option/select.phtml @@ -44,18 +44,20 @@ id="bundle-option-getId() ?>-qty-input" class="input-text qty" type="text" name="bundle_option_qty[getId() ?>]" value="" /> - + getRequired()) echo ' class="required"' ?>>getRequired()) echo '*' ?>htmlEscape($_option->getTitle()) ?> decoratedIsLast){?> class="last"> +
      getSelectionTitlePrice($_selections[0]) ?> - - - - + + + +
      diff --git a/app/design/frontend/base/default/template/catalog/layer/state.phtml b/app/design/frontend/base/default/template/catalog/layer/state.phtml index edb1b3882d..55074d3a07 100644 --- a/app/design/frontend/base/default/template/catalog/layer/state.phtml +++ b/app/design/frontend/base/default/template/catalog/layer/state.phtml @@ -24,23 +24,25 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> - getActiveFilters() ?> -

      __('Currently Shopping By') ?>

      -
        +
        +

        __('Currently Shopping by:') ?>

        +
        1. __('Remove This Item') ?> - __($_filter->getName()) ?>: getLabel() ?> + __($_filter->getName()) ?>: stripTags($_filter->getLabel()) ?>
        +
        diff --git a/app/design/frontend/base/default/template/catalog/product/compare/sidebar.phtml b/app/design/frontend/base/default/template/catalog/product/compare/sidebar.phtml index de84d6daa5..9dfcb550dd 100644 --- a/app/design/frontend/base/default/template/catalog/product/compare/sidebar.phtml +++ b/app/design/frontend/base/default/template/catalog/product/compare/sidebar.phtml @@ -25,7 +25,7 @@ */ /* @var $this Mage_Catalog_Block_Product_Compare_Sidebar */ ?> -
        +
        __('Compare Products') ?> helper('catalog/product_compare')->getItemCount()>0): ?> @@ -39,7 +39,7 @@ helper('catalog/product_compare')->getItemCollection() as $_index=>$_item): ?>
      1. - __('Remove This Item') ?> + __('Remove This Item') ?>

        helper('catalog/output')->productAttribute($_item, $_item->getName(), 'name') ?>

      2. diff --git a/app/design/frontend/base/default/template/catalog/product/gallery.phtml b/app/design/frontend/base/default/template/catalog/product/gallery.phtml index 6241260d3e..b2f152534e 100644 --- a/app/design/frontend/base/default/template/catalog/product/gallery.phtml +++ b/app/design/frontend/base/default/template/catalog/product/gallery.phtml @@ -26,14 +26,14 @@ ?> getImageWidth() ?>
        -

        __('Close Window') ?>

        + getPreviusImageUrl() || $this->getNextImageUrl()): ?> @@ -41,22 +41,25 @@

        width="" alt="htmlEscape($this->getCurrentImage()->getLabel()) ?>" title="htmlEscape($this->getCurrentImage()->getLabel()) ?>" id="product-gallery-image" class="image" /> + getPreviusImageUrl() || $this->getNextImageUrl()): ?> -

        __('Close Window') ?>

        diff --git a/app/design/frontend/base/default/template/catalog/product/view/addtocart.phtml b/app/design/frontend/base/default/template/catalog/product/view/addtocart.phtml index 57b285a0c4..a832fa6cad 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/addtocart.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/addtocart.phtml @@ -33,7 +33,7 @@ - + getChildHtml('', true, true) ?>
        diff --git a/app/design/frontend/base/default/template/catalog/product/view/options/type/date.phtml b/app/design/frontend/base/default/template/catalog/product/view/options/type/date.phtml index 67bea8ab53..062d3d2577 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/options/type/date.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/options/type/date.phtml @@ -26,7 +26,7 @@ ?> getOption() ?> getId() ?> -
        +
        getIsRequire()) echo ' class="required"' ?>>getIsRequire()) echo '*' ?>htmlEscape($_option->getTitle()) ?> getFormatedPrice() ?>
        decoratedIsLast){?> class="last"> diff --git a/app/design/frontend/base/default/template/catalog/product/view/options/type/file.phtml b/app/design/frontend/base/default/template/catalog/product/view/options/type/file.phtml index aa90a9904d..dedcae2466 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/options/type/file.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/options/type/file.phtml @@ -25,17 +25,19 @@ */ ?> getOption() ?> -
        +
        getIsRequire()) echo ' class="required"' ?>>getIsRequire()) echo '*' ?>htmlEscape($_option->getTitle()) ?> getFormatedPrice() ?>
        decoratedIsLast){?> class="last"> - -getFileExtension()): ?> -

        __('Allowed file extensions to upload')?>: getFileExtension() ?>

        - -getImageSizeX() > 0): ?> -

        __('Maximum image width')?>: getImageSizeX() ?> __('px.')?>

        - -getImageSizeY() > 0): ?> -

        __('Maximum image height')?>: getImageSizeY() ?> __('px.')?>

        - +
        + + getFileExtension()): ?> +

        __('Allowed file extensions to upload')?>: getFileExtension() ?>

        + + getImageSizeX() > 0): ?> +

        __('Maximum image width')?>: getImageSizeX() ?> __('px.')?>

        + + getImageSizeY() > 0): ?> +

        __('Maximum image height')?>: getImageSizeY() ?> __('px.')?>

        + +
        diff --git a/app/design/frontend/base/default/template/catalog/product/view/options/type/select.phtml b/app/design/frontend/base/default/template/catalog/product/view/options/type/select.phtml index 1e2d27368b..7eb6b808f5 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/options/type/select.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/options/type/select.phtml @@ -26,12 +26,14 @@ ?> getOption() ?> -
        +
        getIsRequire()) echo ' class="required"' ?>>getIsRequire()) echo '*' ?>htmlEscape($_option->getTitle()) ?>
        decoratedIsLast){?> class="last"> - getValuesHtml() ?> - getIsRequire()): ?> - getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_RADIO || $_option->getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_CHECKBOX): ?> - - - +
        + getValuesHtml() ?> + getIsRequire()): ?> + getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_RADIO || $_option->getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_CHECKBOX): ?> + + + +
        diff --git a/app/design/frontend/base/default/template/catalog/product/view/options/type/text.phtml b/app/design/frontend/base/default/template/catalog/product/view/options/type/text.phtml index 76da41af43..85f42a1ece 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/options/type/text.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/options/type/text.phtml @@ -25,15 +25,17 @@ */ ?> getOption() ?> -
        +
        getIsRequire()) echo ' class="required"' ?>>getIsRequire()) echo '*' ?>htmlEscape($_option->getTitle()) ?> getFormatedPrice() ?>
        decoratedIsLast){?> class="last"> -getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_FIELD): ?> +
        + getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_FIELD): ?> -getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_AREA): ?> + getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_AREA): ?> - -getMaxCharacters()): ?> -

        __('Maximum number of characters:')?> getMaxCharacters() ?>

        - + + getMaxCharacters()): ?> +

        __('Maximum number of characters:')?> getMaxCharacters() ?>

        + +
        diff --git a/app/design/frontend/base/default/template/catalog/product/view/tierprices.phtml b/app/design/frontend/base/default/template/catalog/product/view/tierprices.phtml index 642330b70c..1303f3bea8 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/tierprices.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/tierprices.phtml @@ -40,7 +40,7 @@ if (Mage::helper('weee')->typeOfDisplay($_product, array(1,2,4))) { ?> 0): ?> -
          +
            getInGrouped()): ?> getTierPrices($_product); ?> diff --git a/app/design/frontend/base/default/template/catalog/product/view/type/configurable.phtml b/app/design/frontend/base/default/template/catalog/product/view/type/configurable.phtml index 073f2eccd8..951fc54493 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/type/configurable.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/type/configurable.phtml @@ -23,18 +23,9 @@ * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - +?> + -getProduct() ?> -isSaleable()): ?> -

            __('Availability:') ?> __('In stock') ?>

            - -

            __('Availability:') ?> __('Out of stock') ?>

            - -getChildHtml('product_type_data_extra') ?> -getPriceHtml($_product) ?> diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/type/virtual.phtml b/app/design/frontend/base/default/template/catalog/product/view/type/default.phtml similarity index 73% rename from app/design/frontend/default/iphone/template/catalog/product/view/type/virtual.phtml rename to app/design/frontend/base/default/template/catalog/product/view/type/default.phtml index ca53a58f34..0c4ecf36ad 100644 --- a/app/design/frontend/default/iphone/template/catalog/product/view/type/virtual.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/type/default.phtml @@ -19,22 +19,18 @@ * needs please refer to http://www.magentocommerce.com for more information. * * @category design - * @package default_iphone + * @package base_default * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - -/** - * Simple product deatle template - * - * @see Mage_Catalog_Block_Product_View_Type_Simple - */ ?> + getProduct() ?> -isSaleable()): ?> -

            __('Availability: In stock.') ?>

            + +isAvailable()): ?> +

            __('Availability:') ?> __('In stock') ?>

            -

            __('Availability: Out of stock.') ?>

            +

            __('Availability:') ?> __('Out of stock') ?>

            getChildHtml('product_type_data_extra') ?> getPriceHtml($_product) ?> diff --git a/app/design/frontend/base/default/template/catalog/product/view/type/grouped.phtml b/app/design/frontend/base/default/template/catalog/product/view/type/grouped.phtml index 07ee985d58..a38717a42b 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/type/grouped.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/type/grouped.phtml @@ -31,9 +31,12 @@ * @see Mage_Catalog_Block_Product_View_Type_Grouped */ ?> -getProduct() ?> -getAssociatedProducts() ?> -isSaleable() && count($_associatedProducts)): ?> +getProduct(); +$_associatedProducts = $this->getAssociatedProducts(); +$_hasAssociatedProducts = count($_associatedProducts) > 0; +?> +isAvailable() && $_hasAssociatedProducts): ?>

            __('Availability:') ?> __('In stock') ?>

            __('Availability:') ?> __('Out of stock') ?>

            @@ -46,22 +49,28 @@
    + getCanShowProductPrice($_product)): ?> + isSaleable()): ?> - + helper('tax')->getPrice($_item, $_item->getFinalPrice(), true) ?> + getCanShowProductPrice($_product)): ?> + isSaleable()): ?> +
    getEmptyText() ?>getEmptyText() ?>
    __('Product Name') ?>__('Price') ?>__('Qty') ?>
    htmlEscape($_item->getName()) ?> + getCanShowProductPrice($_item)): ?> getPriceHtml($_item, true) ?> getTierPriceHtml($_item) ?> + isSaleable()) : ?> diff --git a/app/design/frontend/base/default/template/catalog/product/view/type/options/configurable.phtml b/app/design/frontend/base/default/template/catalog/product/view/type/options/configurable.phtml index ce6ba41125..384fcb7d83 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/type/options/configurable.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/type/options/configurable.phtml @@ -32,11 +32,13 @@ $_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes()); isSaleable() && count($_attributes)):?>
    -
    +
    decoratedIsLast){?> class="last"> - +
    + +
    diff --git a/app/design/frontend/base/default/template/catalog/product/view/type/simple.phtml b/app/design/frontend/base/default/template/catalog/product/view/type/simple.phtml index 68a460068e..951fc54493 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/type/simple.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/type/simple.phtml @@ -23,19 +23,9 @@ * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - +?> + -getProduct() ?> - -isSaleable()): ?> -

    __('Availability:') ?> __('In stock') ?>

    - -

    __('Availability:') ?> __('Out of stock') ?>

    - -getChildHtml('product_type_data_extra') ?> -getPriceHtml($_product) ?> diff --git a/app/design/frontend/base/default/template/catalog/product/view/type/virtual.phtml b/app/design/frontend/base/default/template/catalog/product/view/type/virtual.phtml index 68a460068e..951fc54493 100644 --- a/app/design/frontend/base/default/template/catalog/product/view/type/virtual.phtml +++ b/app/design/frontend/base/default/template/catalog/product/view/type/virtual.phtml @@ -23,19 +23,9 @@ * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ - +?> + -getProduct() ?> - -isSaleable()): ?> -

    __('Availability:') ?> __('In stock') ?>

    - -

    __('Availability:') ?> __('Out of stock') ?>

    - -getChildHtml('product_type_data_extra') ?> -getPriceHtml($_product) ?> diff --git a/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_default_list.phtml b/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_default_list.phtml index fcba57306e..a254b88f4d 100644 --- a/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_default_list.phtml +++ b/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_default_list.phtml @@ -26,7 +26,7 @@ ?> getProductCollection()) && $_products->getSize()): ?>
    -
    +
    __('New Products') ?>
    diff --git a/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_images_list.phtml b/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_images_list.phtml index 9d15f604a4..4adb8138a6 100644 --- a/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_images_list.phtml +++ b/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_images_list.phtml @@ -26,7 +26,7 @@ ?> getProductCollection()) && $_products->getSize()): ?>
    -
    +
    __('New Products') ?>
    diff --git a/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_names_list.phtml b/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_names_list.phtml index be0d28c031..c157137918 100644 --- a/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_names_list.phtml +++ b/app/design/frontend/base/default/template/catalog/product/widget/new/column/new_names_list.phtml @@ -26,7 +26,7 @@ ?> getProductCollection()) && $_products->getSize()): ?>
    -
    +
    __('New Products') ?>
    @@ -35,7 +35,7 @@
      getItems() as $_product): ?>
    1. -

      helper('catalog/output')->productAttribute($_product, $_product->getName() , 'name') ?>

      +

      helper('catalog/output')->productAttribute($_product, $_product->getName() , 'name') ?>

    diff --git a/app/design/frontend/base/default/template/checkout/cart.phtml b/app/design/frontend/base/default/template/checkout/cart.phtml index 04728ea83c..39c8f0f6e0 100644 --- a/app/design/frontend/base/default/template/checkout/cart.phtml +++ b/app/design/frontend/base/default/template/checkout/cart.phtml @@ -49,7 +49,6 @@
    - helper('wishlist')->isAllowInCart()) : ?> @@ -68,11 +67,11 @@ helper('tax')->displayCartPriceInclTax() || $this->helper('tax')->displayCartBothPrices()): ?> + helper('tax')->displayCartBothPrices() ? 2 : 1); ?> - helper('wishlist')->isAllowInCart()) : ?> @@ -81,6 +80,7 @@ + helper('tax')->displayCartBothPrices()): ?> diff --git a/app/design/frontend/base/default/template/checkout/cart/item/default.phtml b/app/design/frontend/base/default/template/checkout/cart/item/default.phtml index 3b6be0a2f9..66dab081ec 100644 --- a/app/design/frontend/base/default/template/checkout/cart/item/default.phtml +++ b/app/design/frontend/base/default/template/checkout/cart/item/default.phtml @@ -26,8 +26,7 @@ ?> getItem()?> - - + helper('wishlist')->isAllowInCart()) : ?> + diff --git a/app/design/frontend/base/default/template/checkout/cart/noItems.phtml b/app/design/frontend/base/default/template/checkout/cart/noItems.phtml index c23c74d1a7..d1cabb9a5c 100644 --- a/app/design/frontend/base/default/template/checkout/cart/noItems.phtml +++ b/app/design/frontend/base/default/template/checkout/cart/noItems.phtml @@ -27,6 +27,8 @@

    __('Shopping Cart is Empty') ?>

    -getMessagesBlock()->getGroupedHtml() ?> -

    __('You have no items in your shopping cart.') ?>

    -

    __('Click here to continue shopping.', $this->getContinueShoppingUrl()) ?>

    +
    + getMessagesBlock()->getGroupedHtml() ?> +

    __('You have no items in your shopping cart.') ?>

    +

    __('Click here to continue shopping.', $this->getContinueShoppingUrl()) ?>

    +
    diff --git a/app/design/frontend/base/default/template/checkout/cart/totals.phtml b/app/design/frontend/base/default/template/checkout/cart/totals.phtml index ed05d562c6..852144288b 100644 --- a/app/design/frontend/base/default/template/checkout/cart/totals.phtml +++ b/app/design/frontend/base/default/template/checkout/cart/totals.phtml @@ -28,7 +28,7 @@ /** * Shopping cart totals template * - * @see Mage_Checkout_Block_Cart + * @see Mage_Checkout_Block_Cart_Totals */ ?>
        __('Product Name') ?> __('Unit Price') ?> __('Qty') ?> __('Subtotal') ?> 
    __('Remove item')?>hasProductUrl()):?><?php echo $this->htmlEscape($this->getProductName()) ?>hasProductUrl()):?>hasProductUrl()):?><?php echo $this->htmlEscape($this->getProductName()) ?>hasProductUrl()):?>

    hasProductUrl()):?> @@ -59,6 +58,9 @@

    *

    + getProductAdditionalInformationBlock()):?> + setItem($_item)->toHtml() ?> +

    @@ -238,4 +240,5 @@ __('Remove item')?>
    diff --git a/app/design/frontend/base/default/template/checkout/multishipping/link.phtml b/app/design/frontend/base/default/template/checkout/multishipping/link.phtml index bebf0ac2b5..c1bb916b51 100644 --- a/app/design/frontend/base/default/template/checkout/multishipping/link.phtml +++ b/app/design/frontend/base/default/template/checkout/multishipping/link.phtml @@ -24,4 +24,4 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -__('Checkout with Multiple Addresses');?> +__('Checkout with Multiple Addresses');?> diff --git a/app/design/frontend/base/default/template/checkout/multishipping/state.phtml b/app/design/frontend/base/default/template/checkout/multishipping/state.phtml index a6fb02306a..db20dfe952 100644 --- a/app/design/frontend/base/default/template/checkout/multishipping/state.phtml +++ b/app/design/frontend/base/default/template/checkout/multishipping/state.phtml @@ -31,8 +31,9 @@ * @see Mage_Checkout_Block_Multishipping_State */ ?> -
      +
        getSteps() as $_step): ?> -
      • getIsActive()): ?> class="active">getLabel() ?>
      • +
      • getIsActive()): ?> class="active">getLabel() ?>
      + diff --git a/app/design/frontend/base/default/template/checkout/multishipping/success.phtml b/app/design/frontend/base/default/template/checkout/multishipping/success.phtml index 9bd4a3f87b..6f59c497d3 100644 --- a/app/design/frontend/base/default/template/checkout/multishipping/success.phtml +++ b/app/design/frontend/base/default/template/checkout/multishipping/success.phtml @@ -24,25 +24,27 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -
      -

      __('Order Success') ?>

      -
      -

      __('Thank you for your purchase!') ?>

      -

      __('We are processing your order and you will soon receive an email with details of the order. Once the order has shipped you will receive another email with a link to track its progress.') ?>

      -getOrderIds()): ?> -

      - - __('Your order number is ') ?> - $incrementId): ?> - - - - - - -

      - -getChildHtml() ?> -
      - +
      +
      +

      __('Order Success') ?>

      +
      +

      __('Thank you for your purchase!') ?>

      +

      __('We are processing your order and you will soon receive an email with details of the order. Once the order has shipped you will receive another email with a link to track its progress.') ?>

      + getOrderIds()): ?> +

      + + __('Your order number is ') ?> + $incrementId): ?> + + + + + + +

      + + getChildHtml() ?> +
      + +
      diff --git a/app/design/frontend/base/default/template/checkout/onepage/billing.phtml b/app/design/frontend/base/default/template/checkout/onepage/billing.phtml index 70a9f8144f..6cd7ccdb14 100644 --- a/app/design/frontend/base/default/template/checkout/onepage/billing.phtml +++ b/app/design/frontend/base/default/template/checkout/onepage/billing.phtml @@ -105,7 +105,7 @@
      -
    • +
    • diff --git a/app/design/frontend/base/default/template/checkout/onepage/link.phtml b/app/design/frontend/base/default/template/checkout/onepage/link.phtml index 645d4139be..f3ec733cb1 100644 --- a/app/design/frontend/base/default/template/checkout/onepage/link.phtml +++ b/app/design/frontend/base/default/template/checkout/onepage/link.phtml @@ -25,5 +25,5 @@ */ ?> isPossibleOnepageCheckout()):?> - + diff --git a/app/design/frontend/base/default/template/checkout/onepage/payment/methods.phtml b/app/design/frontend/base/default/template/checkout/onepage/payment/methods.phtml index f40594ceab..a704622c99 100644 --- a/app/design/frontend/base/default/template/checkout/onepage/payment/methods.phtml +++ b/app/design/frontend/base/default/template/checkout/onepage/payment/methods.phtml @@ -48,6 +48,7 @@ +getChildChildHtml('additional'); ?> +isMessagesAvailable() || $this->isItemsAvailable()): ?> getType()): ?>
      @@ -100,7 +101,7 @@ billing.onSave = function(evt){
      - isMessagesAvailable('quote', $this->getEntity())): ?> + isMessagesAvailable()): ?>

      __('Enter a gift message for entire order.'); ?>

      __('You can leave this box blank if you do not wish to add a gift message for whole order.') ?>

      @@ -204,7 +205,7 @@ billing.onSave = function(evt){
      - isMessagesAvailable('quote', $this->getEntity())): ?> + isMessagesAvailable()): ?>

      __('Enter a gift message for this address.'); ?>

      __('You can leave this box blank if you do not wish to add a gift message for this address.') ?>

      @@ -297,3 +298,4 @@ billing.onSave = function(evt){ + diff --git a/app/design/frontend/base/default/template/googlecheckout/link.phtml b/app/design/frontend/base/default/template/googlecheckout/link.phtml index 257e987b38..126b99d7a8 100644 --- a/app/design/frontend/base/default/template/googlecheckout/link.phtml +++ b/app/design/frontend/base/default/template/googlecheckout/link.phtml @@ -24,10 +24,11 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> +getBeforeHtml(); ?> getIsDisabled()): ?> <?php echo Mage::helper('googlecheckout')->__('Fast checkout through Google');?> -getIsActiveAanalytics()):?> onsubmit="setUrchinInputCode(pageTracker)"> +getOnsubmitJs()):?> onsubmit="getOnsubmitJs() ?>">
      diff --git a/app/design/frontend/base/default/template/page/html/head.phtml b/app/design/frontend/base/default/template/page/html/head.phtml index 6c830e6aa7..eee69efa94 100644 --- a/app/design/frontend/base/default/template/page/html/head.phtml +++ b/app/design/frontend/base/default/template/page/html/head.phtml @@ -29,8 +29,8 @@ - - + +
    - - + + - - -
    escapeHtml($track['title']) : $this->__('N/A')); ?>:escapeHtml($track['number']) : ''); ?>escapeHtml($track['title']) : $this->__('N/A')); ?>:escapeHtml($track['number']) : ''); ?>
    -
    - getProgressdetail())>0): ?> + +
    + + getProgressdetail())>0): ?> +
    @@ -145,18 +146,19 @@ getProgressdetail() as $_detail): ?> formatDeliveryDate($_detail['deliverydate']) : '') ?> - formatDeliveryTime($_detail['deliverytime'], $_detailDate) : '') ?> + formatDeliveryTime($_detail['deliverytime'], $_detail['deliverydate']) : '') ?> - - + +
    - + +
    @@ -168,7 +170,7 @@ -
    __('There is no tracking available.'); ?>
    +

    __('There is no tracking available.'); ?>

    diff --git a/app/design/frontend/base/default/template/tag/customer/view.phtml b/app/design/frontend/base/default/template/tag/customer/view.phtml index 6f6af401ec..26b0217c5b 100644 --- a/app/design/frontend/base/default/template/tag/customer/view.phtml +++ b/app/design/frontend/base/default/template/tag/customer/view.phtml @@ -29,7 +29,7 @@
    getMessagesBlock()->getGroupedHtml() ?>

    - __('Delete') ?> + __('Delete') ?> __('Tag Name: %s', $this->htmlEscape($this->getTagInfo()->getName())) ?>

    diff --git a/app/design/frontend/base/default/template/tag/popular.phtml b/app/design/frontend/base/default/template/tag/popular.phtml index 31fa47cc6b..6361b55a2d 100644 --- a/app/design/frontend/base/default/template/tag/popular.phtml +++ b/app/design/frontend/base/default/template/tag/popular.phtml @@ -29,7 +29,7 @@ __('Popular Tags'); ?>
    -
      +
        getTags() as $_tag): ?>
      • htmlEscape($_tag->getName()) ?>
      • diff --git a/app/design/frontend/base/default/template/wishlist/email/items.phtml b/app/design/frontend/base/default/template/wishlist/email/items.phtml index f185813be6..8accb4ab2d 100644 --- a/app/design/frontend/base/default/template/wishlist/email/items.phtml +++ b/app/design/frontend/base/default/template/wishlist/email/items.phtml @@ -26,16 +26,16 @@ /* @var $this Mage_Wishlist_Block_Share_Email_Items */ ?> getWishlistItemsCount() ?> -
        - +
        +
        getWishlistItems() as $item): $i++ ?> diff --git a/app/design/frontend/base/default/template/wishlist/email/rss.phtml b/app/design/frontend/base/default/template/wishlist/email/rss.phtml index 0ceef965ac..5a1ee63614 100644 --- a/app/design/frontend/base/default/template/wishlist/email/rss.phtml +++ b/app/design/frontend/base/default/template/wishlist/email/rss.phtml @@ -24,8 +24,8 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -
        +

        __("RSS link to %s's wishlist",$this->helper('wishlist')->getCustomerName()) ?>
        helper('wishlist')->getRssUrl(); ?> -

        +

        diff --git a/app/design/frontend/base/default/template/wishlist/shared.phtml b/app/design/frontend/base/default/template/wishlist/shared.phtml index 927f40263e..2724c7e617 100644 --- a/app/design/frontend/base/default/template/wishlist/shared.phtml +++ b/app/design/frontend/base/default/template/wishlist/shared.phtml @@ -53,13 +53,11 @@ getPriceHtml($item) ?> - diff --git a/app/design/frontend/base/default/template/wishlist/sharing.phtml b/app/design/frontend/base/default/template/wishlist/sharing.phtml index 01e5361d25..cf7f3d6831 100644 --- a/app/design/frontend/base/default/template/wishlist/sharing.phtml +++ b/app/design/frontend/base/default/template/wishlist/sharing.phtml @@ -47,12 +47,15 @@ helper('wishlist')->isRssAllow()): ?>
      • - +
        + +
        +
      • -
        +

        __('* Required Fields') ?>

        diff --git a/app/design/frontend/base/default/template/wishlist/view.phtml b/app/design/frontend/base/default/template/wishlist/view.phtml index fabacde565..3712a02027 100644 --- a/app/design/frontend/base/default/template/wishlist/view.phtml +++ b/app/design/frontend/base/default/template/wishlist/view.phtml @@ -67,26 +67,26 @@ getFormatedDate($item->getAddedAt()) ?>
        -

        -

        htmlEscape($item->getName()) ?>

        - hasDescription($item)): ?>

        __('Comment') ?>:
        getEscapedDescription($item) ?>

        -

        __('View Product') ?> - getIsSalable()): ?>| __('Add to Cart') ?> +

        +

        htmlEscape($item->getName()) ?>

        + hasDescription($item)): ?>

        __('Comment') ?>:
        getEscapedDescription($item) ?>

        +

        __('View Product') ?> + getIsSalable()): ?>| __('Add to Cart') ?>

        getEscapedDescription($item) ?> - + + isSaleable()): ?> + + +

        __('Add to Wishlist') ?>

        - isSaleable()): ?> + isSaleable()): ?>

        __('Out of stock') ?>

        - __('Remove item')?> + __('Remove item')?>
        -
        +
        isSaleable()):?> - +
        @@ -100,10 +100,10 @@ } function focusComment(obj) { - if( obj.value == '__('Please enter your comments...') ?>' ) { + if( obj.value == 'helper('wishlist')->defaultCommentString() ?>' ) { obj.value = ''; } else if( obj.value == '' ) { - obj.value = '__('Please enter your comments...') ?>'; + obj.value = 'helper('wishlist')->defaultCommentString() ?>'; } } //]]> diff --git a/app/design/frontend/default/iphone/layout/bundle.xml b/app/design/frontend/default/iphone/layout/bundle.xml deleted file mode 100644 index e00fe7d3d8..0000000000 --- a/app/design/frontend/default/iphone/layout/bundle.xml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/catalog_product_price - - - - - - - - - bundlebundle/catalog_product_price - bundle4 - - - - - - - - bundlebundle/checkout_cart_item_renderer - - - - - - bundlebundle/checkout_cart_item_renderer - - - - - - - - bundlebundle/checkout_cart_item_renderer - - - bundlebundle/catalog_product_price - - - - - - - - bundlebundle/checkout_cart_item_renderer - - - - - - bundlebundle/checkout_cart_item_renderer - - - - - - bundlebundle/checkout_cart_item_renderer - - - bundlebundle/checkout_cart_item_renderer - - - - - - bundlebundle/checkout_cart_item_renderer - - - - - - bundlebundle/checkout_cart_item_renderer - - - - - bundlebundle/checkout_cart_item_renderer - - - - - - - - skin_jsjs/bundle.js - - - - bundlebundle/catalog_product_price - - - - - - selectbundle/catalog_product_view_type_bundle_option_select - multibundle/catalog_product_view_type_bundle_option_multi - radiobundle/catalog_product_view_type_bundle_option_radio - checkboxbundle/catalog_product_view_type_bundle_option_checkbox - - product.info.bundle.options - - - - - - - - bundlebundle/catalog_product_price - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - - - - bundlebundle/sales_order_items_renderer - - - - - - bundlebundle/sales_order_items_renderer - - - - diff --git a/app/design/frontend/default/iphone/layout/catalog.xml b/app/design/frontend/default/iphone/layout/catalog.xml index f50c4318aa..6d476ffe9a 100644 --- a/app/design/frontend/default/iphone/layout/catalog.xml +++ b/app/design/frontend/default/iphone/layout/catalog.xml @@ -43,7 +43,6 @@ Default layout, loads most of the pages --> - @@ -57,7 +56,10 @@ Default layout, loads most of the pages - + + images/media/col_right_callout.jpg + Keep your eyes open for our special Back to School items and save A LOT! + Site Map @@ -65,12 +67,12 @@ Default layout, loads most of the pages - - + + @@ -91,6 +93,11 @@ Category default layout --> list5 + empty6 + one_column5 + two_columns_left4 + two_columns_right4 + three_columns3 product_list_toolbar @@ -101,13 +108,15 @@ Category default layout Category layered navigation layout --> - + + + @@ -122,17 +131,23 @@ Category layered navigation layout grid3 grid6 grid9 - gridall + gridall --> list5 + empty6 + one_column5 + two_columns_left4 + two_columns_right4 + three_columns3 product_list_toolbar - + + @@ -143,10 +158,11 @@ Category layered navigation layout Compare products page --> - + + - + @@ -158,9 +174,9 @@ Compare products page - - catalog_compare_sidebar + catalog.compare.sidebar + @@ -168,7 +184,8 @@ Compare products page Product view --> - + + @@ -181,70 +198,70 @@ Product view jscalendar/calendar-setup.js - - - - - - - 4 - upsell4 - + default + short + ... + --> + + + + - - - detailed_info - Details - - - - + - - - + + 4 + upsell4 + - - - - textcatalog/product_view_options_type_text - filecatalog/product_view_options_type_file - selectcatalog/product_view_options_type_select - datecatalog/product_view_options_type_date - - - - - product.tierprices - - product.info.addtocart - + + + detailed_info + + + detailed_info + + + - - alias_in_layoutcontainer1 - options_containerproduct - product.info.options.wrapper - product.info.options.wrapper.bottom - - - alias_in_layoutcontainer2 - options_containerproduct - product.info.options.wrapper - product.info.options.wrapper.bottom + + + + + + + + + textcatalog/product_view_options_type_text + filecatalog/product_view_options_type_file + selectcatalog/product_view_options_type_select + datecatalog/product_view_options_type_date + + - container1ifEquals0alias_in_layoutoptions_container - container2ifEquals0alias_in_layoutoptions_container + + + product.tierprices + + product.info.addtocart + + + + alias_in_layoutcontainer1 + options_containerproduct + product.info.options.wrapper + product.info.options.wrapper.bottom + + + alias_in_layoutcontainer2 + options_containerproduct + product.info.options.wrapper + product.info.options.wrapper.bottom + + container1ifEquals0alias_in_layoutoptions_container + container2ifEquals0alias_in_layoutoptions_container @@ -255,43 +272,58 @@ Product view - + + - - + + + + - + + - - + + + + - + + - + + + - + + - - + + + + + + - + + @@ -309,10 +341,11 @@ Product send to friend Product additional images gallery popup --> - + + - + @@ -323,7 +356,8 @@ Product additional images gallery popup SEO Site Map --> - + + @@ -339,7 +373,8 @@ SEO Site Map - + + Categories @@ -354,7 +389,8 @@ SEO Site Map - + + @@ -368,7 +404,8 @@ SEO Site Map - + + Products @@ -388,7 +425,8 @@ SEO Site Map Catalog search terms block --> - + + diff --git a/app/design/frontend/default/iphone/layout/catalogsearch.xml b/app/design/frontend/default/iphone/layout/catalogsearch.xml deleted file mode 100644 index a8e1204589..0000000000 --- a/app/design/frontend/default/iphone/layout/catalogsearch.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - Search Terms - Advanced Search - - - - - - - - - - - - - - - - - - - empty6 - one_column5 - two_columns_left4 - two_columns_right4 - three_columns3 - product_list_toolbar - - - - - - - - - - - - - - - - - - - js_csscalendar/calendar-win2k-1.css - jscalendar/calendar.js - jscalendar/calendar-setup.js - - - - - - - - - - - - - - - - - - - - - product_list_toolbar - - - - - - - - - - - - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/checkout.xml b/app/design/frontend/default/iphone/layout/checkout.xml index a4c239f83e..666d6dd85e 100644 --- a/app/design/frontend/default/iphone/layout/checkout.xml +++ b/app/design/frontend/default/iphone/layout/checkout.xml @@ -33,7 +33,6 @@ Default layout, loads most of the pages --> - @@ -42,17 +41,23 @@ Default layout, loads most of the pages - - + + simplecheckout/cart_item_renderer + groupedcheckout/cart_item_renderer_grouped + configurablecheckout/cart_item_renderer_configurable + + + - - - + + + - + + @@ -64,23 +69,37 @@ Default layout, loads most of the pages checkout/cart.phtml checkout/cart/noItems.phtml + simplecheckout/cart_item_renderer + groupedcheckout/cart_item_renderer_grouped + configurablecheckout/cart_item_renderer_configurable - + + - + + + + + + - + + + + + + - + + @@ -113,7 +133,8 @@ will be rendered on all checkout pages Multi address shipping checkout selection of address per item page --> - + + @@ -121,7 +142,8 @@ Multi address shipping checkout selection of address per item page - + + @@ -130,17 +152,20 @@ Multi address shipping checkout selection of address per item page - + + - + + - + + @@ -150,12 +175,14 @@ Multi address shipping checkout selection of address per item page - + + - + + @@ -165,7 +192,8 @@ Multi address shipping checkout selection of address per item page Multi address shipping checkout address page --> - + + @@ -181,7 +209,8 @@ Multi address shipping checkout address page Multi address shipping checkout shipping information --> - + + @@ -203,12 +232,20 @@ Multi address shipping checkout shipping information Multi address shipping checkout billing information --> - + + purchaseorder + + + @@ -217,7 +254,8 @@ Multi address shipping checkout billing information Multi address shipping checkout overview --> - + + @@ -225,12 +263,16 @@ Multi address shipping checkout overview defaultcheckout/cart_item_renderer groupedcheckout/cart_item_renderer_grouped configurablecheckout/cart_item_renderer_configurable + groupedcheckout/cart_item_renderer_grouped + configurablecheckout/cart_item_renderer_configurable - + + + @@ -239,7 +281,8 @@ Multi address shipping checkout overview Multi address shipping checkout success --> - + + @@ -251,16 +294,30 @@ Multi address shipping checkout success One page checkout main layout --> - + + + + + + + checkout-progress-wrapper + + + - + + + + 1 + + @@ -334,7 +391,8 @@ One page checkout shipping methods block One page checkout order review block --> - + + @@ -344,11 +402,14 @@ One page checkout order review block groupedcheckout/cart_item_renderer_grouped configurablecheckout/cart_item_renderer_configurable - + + + - + + @@ -356,14 +417,14 @@ One page checkout order review block - - + + - + - + diff --git a/app/design/frontend/default/iphone/layout/contacts.xml b/app/design/frontend/default/iphone/layout/contacts.xml deleted file mode 100644 index 4c35d074c7..0000000000 --- a/app/design/frontend/default/iphone/layout/contacts.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - contactsContact Ustrue - - - - - - - Contact Us - - - - - - diff --git a/app/design/frontend/default/iphone/layout/customer.xml b/app/design/frontend/default/iphone/layout/customer.xml index 1d7a340598..0d32199539 100644 --- a/app/design/frontend/default/iphone/layout/customer.xml +++ b/app/design/frontend/default/iphone/layout/customer.xml @@ -33,6 +33,7 @@ Supported layout update handles (action): - customer_account_logoutsuccess - customer_account_create - customer_account_forgotpassword +- customer_account_confirmation - customer_account_edit Supported layout update handles (special): @@ -40,43 +41,49 @@ Supported layout update handles (special): --> + + - {{baseUrl}}Catalog9 - - - My Account2 - - - javascript:void(0);>Search0
      • onClick="showSearchForm(1);" + My Account10 + + - - Log Out1 + + Log Out100 + + - - Log In1 + + + Log In100 + - + + + @@ -88,10 +95,13 @@ Layout for customer login page + - + + + @@ -103,26 +113,31 @@ Layout for customer log out page + - + + + - - - - + + + + + - + + @@ -136,12 +151,26 @@ New customer registration - + + + + + + + Send confirmation link + + + + + + + + Edit Account Info - + @@ -149,13 +178,25 @@ New customer registration left.permanent.callout + - + + + + - + + + + + + + my-account + @@ -164,57 +205,63 @@ Customer account pages, rendered for all tabs in dashboard account_editcustomer/account/edit/ address_bookcustomer/address/ - + + simplecheckout/cart_item_renderer + groupedcheckout/cart_item_renderer_grouped + configurablecheckout/cart_item_renderer_configurable + + + + - - - - tags_popular - + - + + + - + - + - - + - + + + - - + + + - + + + - - - - + diff --git a/app/design/frontend/default/iphone/layout/directory.xml b/app/design/frontend/default/iphone/layout/directory.xml deleted file mode 100644 index 7ff92dc0c1..0000000000 --- a/app/design/frontend/default/iphone/layout/directory.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/downloadable.xml b/app/design/frontend/default/iphone/layout/downloadable.xml deleted file mode 100644 index d64635341b..0000000000 --- a/app/design/frontend/default/iphone/layout/downloadable.xml +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - downloadable_productsdownloadable/customer/products - - - - - - - - - - My Downloadable Products - - - - - - downloadabledownloadable/checkout_cart_item_renderer - - - - - - downloadabledownloadable/checkout_cart_item_renderer - - - - - - - - - - - - downloadabledownloadable/checkout_cart_item_renderer - - - - - - downloadabledownloadable/checkout_cart_item_renderer - - - - - - downloadabledownloadable/checkout_cart_item_renderer - - - - - - - - - - - - downloadabledownloadable/checkout_cart_item_renderer - - - - - downloadabledownloadable/checkout_cart_item_renderer - - - - - - downloadabledownloadable/sales_order_item_renderer_downloadable - - - - - - downloadabledownloadable/sales_order_item_renderer_downloadable - - - - - - downloadabledownloadable/sales_order_item_renderer_downloadable - - - - - - - - downloadabledownloadable/sales_order_item_renderer_downloadable - - - - - - downloadabledownloadable/sales_order_item_renderer_downloadable - - - - - - downloadabledownloadable/sales_order_item_renderer_downloadable - - - - - - - - - - downloadabledownloadable/sales_order_email_items_order_downloadable - - - - - - downloadabledownloadable/sales_order_email_items_downloadable - - - - - - downloadabledownloadable/sales_order_email_items_downloadable - - - - - - - - - - - - - product.info.downloadable.options - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/giftmessage.xml b/app/design/frontend/default/iphone/layout/giftmessage.xml deleted file mode 100644 index 2f4affa87d..0000000000 --- a/app/design/frontend/default/iphone/layout/giftmessage.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - save - - - - - - - - - - - - remove - - - - - diff --git a/app/design/frontend/default/iphone/layout/newsletter.xml b/app/design/frontend/default/iphone/layout/newsletter.xml deleted file mode 100644 index 539c4a1de5..0000000000 --- a/app/design/frontend/default/iphone/layout/newsletter.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - newsletternewsletter/manage/ - - - - - - - right.newsletter - - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/page.xml b/app/design/frontend/default/iphone/layout/page.xml index 2120ffd4f1..f34a2a51f1 100644 --- a/app/design/frontend/default/iphone/layout/page.xml +++ b/app/design/frontend/default/iphone/layout/page.xml @@ -29,10 +29,13 @@ - + + + + @@ -42,73 +45,52 @@ Default layout, loads most of the pages - css/iphone.css - - + + + + - + - - - - - - + + + - - + + + - - - - - - - - - css/reset.css - css/boxes.css - css/clears.css - css/menu.css - - css/print.cssmedia="print" - - - - - - - 1 + empty @@ -117,30 +99,34 @@ Default layout, loads most of the pages 1 + one_column - + 1 + two_columns_left - + 1 + two_columns_right - + 1 + three_columns diff --git a/app/design/frontend/default/iphone/layout/productalert.xml b/app/design/frontend/default/iphone/layout/productalert.xml deleted file mode 100644 index 504952acb1..0000000000 --- a/app/design/frontend/default/iphone/layout/productalert.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/reports.xml b/app/design/frontend/default/iphone/layout/reports.xml deleted file mode 100644 index 892c41ace8..0000000000 --- a/app/design/frontend/default/iphone/layout/reports.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/review.xml b/app/design/frontend/default/iphone/layout/review.xml index 8d21a3aa09..1b0f70829c 100644 --- a/app/design/frontend/default/iphone/layout/review.xml +++ b/app/design/frontend/default/iphone/layout/review.xml @@ -31,7 +31,7 @@ - reviewscustomer/review/ + reviewsreview/customer @@ -43,10 +43,10 @@ Customer account home dashboard layout - + @@ -58,7 +58,7 @@ Product reviews page (?) - + @@ -66,25 +66,39 @@ Product reviews page (?) Product reviews page --> - - + + - + - - - 1 - - + + + + + + + + + + + + + + + 1 + + + - + + @@ -93,18 +107,21 @@ Product reviews page - + + - + - + + - + + diff --git a/app/design/frontend/default/iphone/layout/rss.xml b/app/design/frontend/default/iphone/layout/rss.xml deleted file mode 100644 index bbcec5a754..0000000000 --- a/app/design/frontend/default/iphone/layout/rss.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - rssRSS testingtrue
      • class="link-feed" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/sales.xml b/app/design/frontend/default/iphone/layout/sales.xml deleted file mode 100644 index 91e2996dec..0000000000 --- a/app/design/frontend/default/iphone/layout/sales.xml +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - - - - - - - - - - reorder - - - - - - - orderssales/order/history/ - - - - - - - - - - top - - - - - - - - - - - - - - - - - - - - - - - defaultsales/order_item_renderer_default - - colspan="4" class="a-right" - class="last a-right" - - - - - - - view - invoice*/*/invoice - shipment*/*/shipment - creditmemo*/*/creditmemo - - - - - - - - - - colspan="4" class="a-right" - class="last a-right" - - - - - - view*/*/view - invoice - shipment*/*/shipment - creditmemo*/*/creditmemo - - - - - - - - - - - view*/*/view - invoice*/*/invoice - shipment - creditmemo*/*/creditmemo - - - - - - - - - - colspan="7" align="right" - align="right" - - - - - - view*/*/view - invoice*/*/invoice - shipment*/*/shipment - creditmemo - - - - - - - - - - - - - - defaultsales/order_item_renderer_default - groupedsales/order_item_renderer_grouped - - colspan="4" class="a-right" - class="last a-right" - - 1 - - - - - - - - - - defaultsales/order_item_renderer_default - groupedsales/order_item_renderer_grouped - - colspan="4" class="a-right" - class="last a-right" - - - - - - - - - - - - - - - - defaultsales/order_item_renderer_default - groupedsales/order_item_renderer_grouped - - colspan="7" align="right" style="padding:3px 9px" - align="right" style="padding:3px 9px" - - - - - - - - - defaultsales/order_email_items_order_default - groupedsales/order_email_items_order_grouped - - colspan="3" align="right" style="padding:3px 9px" - align="right" style="padding:3px 9px" - - 1 - - - - - - - - defaultsales/order_email_items_default - groupedsales/order_email_items_order_grouped - - colspan="3" align="right" style="padding:3px 9px" - align="right" style="padding:3px 9px" - - - - - - - - defaultsales/order_email_items_default - - - - - - defaultsales/order_email_items_default - groupedsales/order_email_items_order_grouped - - colspan="3" align="right" style="padding:3px 9px" - align="right" style="padding:3px 9px" - - - - - diff --git a/app/design/frontend/default/iphone/layout/shipping.xml b/app/design/frontend/default/iphone/layout/shipping.xml deleted file mode 100644 index a1b0ed3691..0000000000 --- a/app/design/frontend/default/iphone/layout/shipping.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/layout/tag.xml b/app/design/frontend/default/iphone/layout/tag.xml index 05de7cb091..62375d3fa0 100644 --- a/app/design/frontend/default/iphone/layout/tag.xml +++ b/app/design/frontend/default/iphone/layout/tag.xml @@ -35,11 +35,8 @@ Default layout, loads most of the pages - - - + - - + - + + - + + + + 1 + + @@ -76,7 +79,8 @@ Customer account home dashboard layout All tags page --> - + + @@ -86,11 +90,18 @@ All tags page - + + - + + + + list5 + + product_list_toolbar + @@ -98,22 +109,24 @@ All tags page - + + My Account - + - + + My Account - + diff --git a/app/design/frontend/default/iphone/layout/wishlist.xml b/app/design/frontend/default/iphone/layout/wishlist.xml deleted file mode 100644 index a193ea1d9f..0000000000 --- a/app/design/frontend/default/iphone/layout/wishlist.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - {{baseUrl}}wishlist/Wishlist3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - wishlist_customer_sidebar - - - - - - - - - - - wishlist_customer_sidebar - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/locale/en_US/translate.csv b/app/design/frontend/default/iphone/locale/en_US/translate.csv index ab952f2ca6..3babf9de36 100644 --- a/app/design/frontend/default/iphone/locale/en_US/translate.csv +++ b/app/design/frontend/default/iphone/locale/en_US/translate.csv @@ -1 +1,8 @@ "Keep your eyes open for our special Back to School items and save A LOT!","Keep your eyes open for our special Back to School items and save A LOT!" +"My Account","Account" +"My Wishlist","Wishlist" +"My Wishlist (%d item)","Wishlist (%d)" +"My Wishlist (%d items)","Wishlist (%d)" +"My Cart","Cart" +"My Cart (%s item)","Cart (%s)" +"My Cart (%s items)","Cart (%s)" \ No newline at end of file diff --git a/app/design/frontend/default/iphone/template/catalog/category/view.phtml b/app/design/frontend/default/iphone/template/catalog/category/view.phtml deleted file mode 100644 index e1b54af349..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/category/view.phtml +++ /dev/null @@ -1,48 +0,0 @@ - - -
        -getMessagesBlock()->getGroupedHtml() ?> -
        - -

        htmlEscape($this->getCurrentCategory()->getName()) ?>

        -
        - getCurrentCategory()->getDescription()): ?> -

        categoryAttribute($this->getCurrentCategory(), $_description, 'description') ?>

        - - getProductListHtml() ?> -
        diff --git a/app/design/frontend/default/iphone/template/catalog/layer/state.phtml b/app/design/frontend/default/iphone/template/catalog/layer/state.phtml deleted file mode 100644 index 9f820c226f..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/layer/state.phtml +++ /dev/null @@ -1,46 +0,0 @@ - - -getActiveFilters() ?> - -

        __('Currently Shopping By') ?>

        -
          - -
        1. - <?php echo $this->__('Remove This Item') ?> - __($_filter->getName()) ?>: getLabel() ?> -
        2. - -
        - - diff --git a/app/design/frontend/default/iphone/template/catalog/layer/view.phtml b/app/design/frontend/default/iphone/template/catalog/layer/view.phtml deleted file mode 100644 index 2a72a39942..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/layer/view.phtml +++ /dev/null @@ -1,62 +0,0 @@ - - -canShowBlock()): ?> -
        -
        -

        __('Shop By') ?>

        -
        - -
        - getStateHtml() ?> - canShowOptions()): ?> -
        -

        __('Shopping Options') ?>

        -
        - getFilters() ?> - - getItemsCount()): ?> -
        __($_filter->getName()) ?>
        -
        - getHtml() ?> -
        - - -
        - -
        - -
        -
        - - diff --git a/app/design/frontend/default/iphone/template/catalog/navigation/left.phtml b/app/design/frontend/default/iphone/template/catalog/navigation/left.phtml deleted file mode 100644 index bbf0a53a1e..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/navigation/left.phtml +++ /dev/null @@ -1,61 +0,0 @@ - - -getCurrentChildCategories() ?> -count(); ?> - -
        -
        -

        __('Browse By') ?>

        -
        -
        -
        -
        -
        __('Category') ?>
        -
        -
          - - getIsActive()): ?> -
        1. - isCategoryActive($_category)): ?> class="active">htmlEscape($_category->getName()) ?> (getProductCount() ?>) -
        2. - - -
        -
        -
        -
        -
        -
        - - diff --git a/app/design/frontend/default/iphone/template/catalog/navigation/top.phtml b/app/design/frontend/default/iphone/template/catalog/navigation/top.phtml deleted file mode 100644 index d5b18b307d..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/navigation/top.phtml +++ /dev/null @@ -1,44 +0,0 @@ - - -
        -
        - getStoreCategories()) > 0): ?> - - -
        -
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/compare/list.phtml b/app/design/frontend/default/iphone/template/catalog/product/compare/list.phtml deleted file mode 100644 index 75231b172b..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/compare/list.phtml +++ /dev/null @@ -1,131 +0,0 @@ - -
        -

        __('Compare Products') ?>

        - __('Print This Page') ?> -
        -getItems()->getSize() ?> - -
        - -2): ?> - - - - getItems() as $_item): ?> - - - - - - - - - - - - getItems() as $_item): ?> - - - - - - - - - getAttributes() as $_attribute): ?> - - - getItems() as $_item): ?> - - - - - - - - - - - - getItems() as $_item): ?> - - - - - - - -
         <?php echo $this->__('Remove Product') ?>
          - <?php echo $this->stripTags($_item->getName(), null, true) ?> -
        helper('catalog/output')->productAttribute($_item, $_item->getName(), 'name') ?>
        - helper('review/product')->getSummaryHtml($_item, 'short') ?> - getPriceHtml($_item, false, '-compare-list-top') ?> - isSaleable()): ?> -
        - -
        __('Out of stock') ?>
        - - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> - -
        getStoreLabel() ?> - getAttributeCode()) { - case "price": ?> - getPriceHtml($_item, false, '-compare-list-' . $_attribute->getCode()) ?> - - <?php echo $this->htmlEscape($_item->getName()) ?> - - productAttribute($_item, $this->getProductAttributeValue($_item, $_attribute), $_attribute->getCode()) ?> - -
          - getPriceHtml($_item, false, '-compare-list-bottom') ?> - isSaleable()): ?> -
        - -
        __('Out of stock') ?>
        - - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> - -
        -
        - -
        -
        - - - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/compare/sidebar.phtml b/app/design/frontend/default/iphone/template/catalog/product/compare/sidebar.phtml deleted file mode 100644 index dc1ac9e982..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/compare/sidebar.phtml +++ /dev/null @@ -1,54 +0,0 @@ - -
        -
        - helper('catalog/product_compare')->getItemCount() > 0): ?> -

        __('Compare Products - %d Items', $this->helper('catalog/product_compare')->getItemCount()) ?>

        - -

        __('Compare Products') ?>

        - -
        - helper('catalog/product_compare')->getItemCount() > 0): ?> -
          - helper('catalog/product_compare')->getItemCollection() as $_index=>$_item): ?> -
        1. - - <?php echo $this->__('Remove This Item') ?> - helper('catalog/output')->productAttribute($_item, $_item->getName(), 'name') ?> -
        2. - -
        - -
        - __('Clear All Items') ?> - -
        - -

        __('You have no items to compare.') ?>

        - -
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/gallery.phtml b/app/design/frontend/default/iphone/template/catalog/product/gallery.phtml deleted file mode 100644 index dda85d916d..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/gallery.phtml +++ /dev/null @@ -1,52 +0,0 @@ - - -getImageWidth() ?> -
        getPreviusImageUrl()): ?> -« __('Prev') ?> - -getNextImageUrl()): ?> -__('Next') ?> » - -
        -
        htmlEscape($this->getCurrentImage()->getLabel()) ?>
        -
        -

        width="" src="helper('catalog/image')->init($this->getProduct(), 'image', $this->getImageFile()); ?>" alt="htmlEscape($this->getCurrentImage()->getLabel()) ?>" title="htmlEscape($this->getCurrentImage()->getLabel()) ?>" id="product-gallery-image" />

        -
        getPreviusImageUrl()): ?> -« __('Prev') ?> - -getNextImageUrl()): ?> -__('Next') ?> » - -
        - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/list.phtml b/app/design/frontend/default/iphone/template/catalog/product/list.phtml deleted file mode 100644 index e9e46c8f78..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/list.phtml +++ /dev/null @@ -1,81 +0,0 @@ - - -getLoadedProductCollection() ?> -count()): ?> -
        - __('There are no products matching the selection.') ?> -
        - - -getToolbarHtml() ?> - - - -
        - -
        - -getToolbarHtml() ?> - diff --git a/app/design/frontend/default/iphone/template/catalog/product/list/crosssell.phtml b/app/design/frontend/default/iphone/template/catalog/product/list/crosssell.phtml deleted file mode 100644 index 2aae5f91a2..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/list/crosssell.phtml +++ /dev/null @@ -1,51 +0,0 @@ - -getItems()->getSize()): ?> -
        -
        -

        __('Cross-sell Products') ?>

        -
        -
          - getItems() as $_item): ?> -
        1. -
          - <?php echo $this->htmlEscape($_item->getName()) ?> -
          -
          - htmlEscape($_item->getName()) ?> - helper('catalog/product')->getPriceHtml($_item) ?> - __('Add to Cart') ?> - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> - -
          -
        2. - -
        - -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/list/related.phtml b/app/design/frontend/default/iphone/template/catalog/product/list/related.phtml deleted file mode 100644 index 295fdccaf7..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/list/related.phtml +++ /dev/null @@ -1,99 +0,0 @@ - -getItems()->getSize()): ?> - - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/list/toolbar.phtml b/app/design/frontend/default/iphone/template/catalog/product/list/toolbar.phtml index 707f25caa5..d0fe6125f8 100644 --- a/app/design/frontend/default/iphone/template/catalog/product/list/toolbar.phtml +++ b/app/design/frontend/default/iphone/template/catalog/product/list/toolbar.phtml @@ -32,16 +32,31 @@ */ ?> getCollection()->getSize()): ?> -
        -
        - getLastPageNum()>1): ?> - __('%s to %s of %s', $this->getFirstNum(), $this->getLastNum(), $this->getTotalNum()) ?> - - __('%s Item(s)', $this->getTotalNum()) ?> - +
        +
        + getPagerHtml() ?> +
        + + isExpanded() ): ?> +
        +
        + + getAvailableOrders() as $_key=>$_order): ?> + isOrderCurrent($_key)): ?> + + + getCurrentDirection() == 'desc'): ?> + <?php echo $this->__('Set Ascending Direction') ?> + + <?php echo $this->__('Set Descending Direction') ?> + + + + + +
        -
        - getPagerHtml() ?> -
        + +
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/list/toolbar/pager.phtml b/app/design/frontend/default/iphone/template/catalog/product/list/toolbar/pager.phtml deleted file mode 100644 index 4d307bfa0b..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/list/toolbar/pager.phtml +++ /dev/null @@ -1,68 +0,0 @@ - - - -
          -isFirstPage()): ?> -
        1. - - -canShowFirst()): ?> -
        2. 1
        3. - - -canShowPreviousJump()): ?> -
        4. ...
        5. - - -getFramePages() as $_page): ?> - isPageCurrent($_page)): ?> -
        6. - -
        7. - - - - -canShowNextJump()): ?> -
        8. ...
        9. - - -canShowLast()): ?> -
        10. getLastPageNum() ?>
        11. - - -isLastPage()): ?> -
        12. - -
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/list/upsell.phtml b/app/design/frontend/default/iphone/template/catalog/product/list/upsell.phtml deleted file mode 100644 index ee3c40ef1e..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/list/upsell.phtml +++ /dev/null @@ -1,48 +0,0 @@ - -getItemCollection()->getSize()): ?> -
        -

        __('You may also be interested in the following product(s)') ?>

        - -resetItemsIterator() ?> -getRowCount();$_i++): ?> - - getColumnCount();$_j++): ?> - getIterableItem()): ?> - - - - - - - -
        -

        <?php echo $this->htmlEscape($_link->getName()) ?>

        -
        htmlEscape($_link->getName()) ?>
        - getPriceHtml($_link, true, '-upsell') ?> -
         
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/new.phtml b/app/design/frontend/default/iphone/template/catalog/product/new.phtml deleted file mode 100644 index fef51a3b68..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/new.phtml +++ /dev/null @@ -1,65 +0,0 @@ - -getProductCollection()) && $_products->getSize()): ?> -
        -

        __('New Products') ?>

        - - -getItems() as $_product): ?> - 5): continue; endif; ?> - - - - - - - -
        -
        - - <?php echo $this->htmlEscape($_product->getName()) ?> - -
        -

        htmlEscape($_product->getName()) ?>

        - getReviewsSummaryHtml($_product, 'short') ?> - getPriceHtml($_product, true, '-new') ?> - isSaleable()): ?> - - -
        __('Out of stock') ?>
        - -
        -

        - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> - - getAddToCompareUrl($_product)): ?>
        - __('Add to Compare') ?> - -

        -
         
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/price.phtml b/app/design/frontend/default/iphone/template/catalog/product/price.phtml deleted file mode 100644 index d90f93c733..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/price.phtml +++ /dev/null @@ -1,358 +0,0 @@ - - - - -getProduct() ?> -getId() ?> - - - -helper('tax')->displayPriceIncludingTax() || $this->helper('tax')->displayBothPrices()); ?> - -getMinimalPrice() ?> -helper('tax')->getPrice($_product, $_minimalPriceValue, $simplePricesTax) ?> - -isGrouped()): ?> - getAmountForDisplay($_product); ?> - typeOfDisplay($_product, array(1,2,4))): ?> - getAmount($_product); ?> - getProductWeeeAttributesForDisplay($_product); ?> - - -
        - helper('tax')->getPrice($_product, $_product->getPrice()) ?> - helper('tax')->getPrice($_product, $_product->getPrice(), $simplePricesTax) ?> - helper('tax')->getPrice($_product, $_product->getFinalPrice()) ?> - helper('tax')->getPrice($_product, $_product->getFinalPrice(), true) ?> - getPriceDisplayType(); ?> - - helper('tax')->displayBothPrices()): ?> - typeOfDisplay($_product, 0)): // including ?> - - __('Excl. Tax:') ?> - currency($_price+$_weeeTaxAmount,true,false) ?> - -
        - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> - - typeOfDisplay($_product, 1)): // incl. + weee ?> - - __('Excl. Tax:') ?> - currency($_price+$_weeeTaxAmount,true,false) ?> - -
        - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> -
        - ( - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount(), true, true); ?> - - - ) -
        - typeOfDisplay($_product, 4)): // incl. + weee ?> - - __('Excl. Tax:') ?> - currency($_price+$_weeeTaxAmount,true,false) ?> - -
        - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> -
        - ( - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount()+$_weeeTaxAttribute->getTaxAmount(), true, true); ?> - - - ) -
        - typeOfDisplay($_product, 2)): // excl. + weee + final ?> - - __('Excl. Tax:') ?> - currency($_price,true,false) ?> - - - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount(), true, true); ?> - - -
        - - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> - - - - __('Excl. Tax:') ?> - currency($_price,true,false) ?> - -
        - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax,true,false) ?> - - - - typeOfDisplay($_product, 0)): // including ?> - currency($_price+$_weeeTaxAmount,true,true) ?> - typeOfDisplay($_product, 1)): // incl. + weee ?> - currency($_price+$_weeeTaxAmount,true,true) ?> -
        - ( - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount(), true, true); ?> - - - ) - typeOfDisplay($_product, 4)): // incl. + weee ?> - currency($_price+$_weeeTaxAmount,true,true) ?> -
        - ( - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount()+$_weeeTaxAttribute->getTaxAmount(), true, true); ?> - - - ) - typeOfDisplay($_product, 2)): // excl. + weee + final ?> - currency($_price,true,true) ?>
        - - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount(), true, true); ?> - - -
        - - currency($_price+$_weeeTaxAmount,true,true) ?> - - currency($_price,true,true) ?> - - - - getOriginalAmount($_product); ?> - - typeOfDisplay($_product, 0)): // including ?> -

        - __('Regular Price:') ?> - currency($_regularPrice+$_originalWeeeTaxAmount,true,false) ?> -

        - - helper('tax')->displayBothPrices()): ?> -

        - __('Special Price:') ?> - - __('Excl. Tax:') ?> - currency($_finalPrice+$_weeeTaxAmount,true,false) ?> - -
        - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> - -

        - -

        - __('Special Price:') ?> - currency($_finalPrice+$_weeeTaxAmount,true,false) ?> -

        - - - typeOfDisplay($_product, 1)): // incl. + weee ?> -

        - __('Regular Price:') ?> - currency($_regularPrice+$_originalWeeeTaxAmount,true,false) ?> -

        - -

        - __('Special Price:') ?> - - __('Excl. Tax:') ?> - currency($_finalPrice+$_weeeTaxAmount,true,false) ?> - -
        - ( - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount(), true, true); ?> - - - ) - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> - -

        - typeOfDisplay($_product, 4)): // incl. + weee ?> -

        - __('Regular Price:') ?> - currency($_regularPrice+$_originalWeeeTaxAmount,true,false) ?> -

        - -

        - __('Special Price:') ?> - - __('Excl. Tax:') ?> - currency($_finalPrice,true,false) ?> - -
        - ( - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount()+$_weeeTaxAttribute->getTaxAmount(), true, true); ?> - - - ) - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> - -

        - typeOfDisplay($_product, 2)): // excl. + weee + final ?> -

        - __('Regular Price:') ?> - currency($_regularPrice,true,false) ?> -

        - -

        - __('Special Price:') ?> - - __('Excl. Tax:') ?> - currency($_finalPrice,true,false) ?> - -
        - - - - getName(); ?>: currency($_weeeTaxAttribute->getAmount(), true, true); ?> - - -
        - - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax+$_weeeTaxAmount,true,false) ?> - -

        - -

        - __('Regular Price:') ?> - currency($_regularPrice,true,false) ?> -

        - - helper('tax')->displayBothPrices()): ?> -

        - __('Special Price:') ?> - - __('Excl. Tax:') ?> - currency($_finalPrice,true,false) ?> - -
        - - __('Incl. Tax:') ?> - currency($_finalPriceInclTax,true,false) ?> - -

        - -

        - __('Special Price:') ?> - currency($_finalPrice,true,false) ?> -

        - - - - - - getDisplayMinimalPrice() && $_minimalPriceValue && $_minimalPriceValue < $_product->getFinalPrice()): ?> - - - typeOfDisplay($_product, array(0, 1, 4))): ?> - - - - getUseLinkForAsLowAs()):?> - - - - - __('As low as:') ?> - currency($_minimalPriceDisplayValue,true,false) ?> - getUseLinkForAsLowAs()):?> - - - - - getDisplayMinimalPrice() && $_minimalPrice && $_minimalPrice < $_finalPrice): */ ?> -
        - -isGrouped()): */ ?> - helper('tax')->getPrice($_product, $_minimalPriceValue, $includingTax = null); - $_inclTax = $this->helper('tax')->getPrice($_product, $_minimalPriceValue, $includingTax = true); - ?> - getDisplayMinimalPrice() && $_minimalPriceValue): ?> -
        - __('Starting at:') ?> - helper('tax')->displayBothPrices()): ?> - - __('Excl. Tax:') ?> - currency($_exclTax, true, false) ?> - -
        - - __('Incl. Tax:') ?> - currency($_inclTax, true, false) ?> - - - helper('tax')->displayPriceIncludingTax()) { - $_showPrice = $_exclTax; - } - ?> - currency($_showPrice, true, false) ?> - -
        - getDisplayMinimalPrice() && $_minimalPrice): */ ?> -isGrouped()): */ ?> diff --git a/app/design/frontend/default/iphone/template/catalog/product/send.phtml b/app/design/frontend/default/iphone/template/catalog/product/send.phtml deleted file mode 100644 index 5d85166934..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/send.phtml +++ /dev/null @@ -1,141 +0,0 @@ - - - -getMessagesBlock()->getGroupedHtml() ?> -
        -

        __('Email to a Friend') ?>

        -
        -
        - -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view.phtml b/app/design/frontend/default/iphone/template/catalog/product/view.phtml deleted file mode 100644 index 9a8473705b..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view.phtml +++ /dev/null @@ -1,121 +0,0 @@ - - -
        getMessagesBlock()->getGroupedHtml() ?>
        -getProduct() ?> -
        getOptions()): ?> enctype="multipart/form-data"> -
        -
        -
        -
        -
        -
        <?php echo $this->htmlEscape($_product->getName()) ?>
        - isSaleable()): ?> - helper('wishlist')->isAllow()) : ?> - - - - canEmailToFriend()): ?> - - -
        -
        -

        htmlEscape($_product->getName()) ?>

        - getChildHtml('product_type_data') ?> - getChildHtml('extrahint') ?> - -
        - - -
        - - -
        - - getChildHtml('tierprices') ?> - - hasOptions()):?> - isSaleable()): ?> - getChildHtml('addtocart') ?> - - - getChildHtml('other');?> - - isSaleable() && $this->hasOptions()):?> - getChildChildHtml('container1', '', true, true) ?> - -
        -
        -
        -
        - isSaleable() && $this->hasOptions()):?> - getChildChildHtml('container2', '', true, true) ?> - -
        - -
        - getChildGroup('detailed_info', 'getChildHtml') as $alias => $html):?> -
        -

        escapeHtml($this->getChildData($alias, 'title'));?>

        -
        - - - getAdditionalData()): ?> -
        -

        __('Additional Information') ?>

        - - - - - - - -
        - -
        - - - getChildHtml('upsell_products') ?> - getChildHtml('product_additional_data') ?> -
        -
        -
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/addto.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/addto.phtml deleted file mode 100644 index 25f954467a..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/addto.phtml +++ /dev/null @@ -1,37 +0,0 @@ - - -getProduct() ?> - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/addtocart.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/addtocart.phtml deleted file mode 100644 index dc077efc0d..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/addtocart.phtml +++ /dev/null @@ -1,40 +0,0 @@ - - -getProduct() ?> - -isSaleable()): ?> -
        - __('Add Items to Cart') ?> - isGrouped()): ?> - - - - - getChildHtml('', true, true) ?> -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/attributes.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/attributes.phtml deleted file mode 100644 index 2f9cc2c396..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/attributes.phtml +++ /dev/null @@ -1,45 +0,0 @@ - -getAdditionalData()): ?> -
        - - - - - - - -
        - -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/bundle.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/bundle.phtml deleted file mode 100644 index 2a5510be9e..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/bundle.phtml +++ /dev/null @@ -1,205 +0,0 @@ - - - -getMessagesBlock()->getGroupedHtml() ?> -getProduct() ?> -
        -
        -
        -

        - <?php echo $this->htmlEscape($_product->getName()) ?> -

        -
        - <?php echo $this->__('Zoom Out') ?> -
        -
        -
        - <?php echo $this->__('Zoom Out') ?> -
        - - getGalleryImages() && $this->getGalleryImages()->getSize()): ?> -
        -

        __('More Views') ?>

        -
          - getGalleryImages() as $_image): ?> -
        • - - - -
        • - -
        -
        - -
        -
        -

        htmlEscape($_product->getName()) ?>

        - getHelper('review/helper')->getSummaryHtml($_product, null, 1) ?> -
        -
        - - -
        - - isBundle()): ?> -
        - isAvailableBundle()): ?> - - getBundleOptionCollection() as $_bundleOption): ?> - - - - - -
        getLabel() ?>: - getLinkCollection()->getItems())>1): ?> - - getLinkCollection()->getItems())==1): ?> - getLinkCollection()->getFirstItem() ?> - getName() ?> - - __('Out of Stock') ?> - -
        - - -

        __('This bundle is out of stock.') ?>

        - -
        - - isSuperConfig()): ?> - getChildHtml('super_config') ?> - - - getTierPriceCount()>1): ?> -
        -
          - getFormatedTierPrice() as $_price): ?> -
        • __('Buy %s for %s each', $_price['price_qty'], $_price['price']) ?>
        • - -
        -
        - - - isSuperGroup()): ?> - getChildHtml('super_group') ?> - - - isSuperGroup()): ?> - isBundle() || $_product->isAvailableBundle()): ?> -

        __('Availability: In stock. Ships within 24 hours.') ?>

        - helper('catalog/product')->getPriceHtml($_product) ?> -
        - __('Add Items to Cart') ?> - - - - __('OR') ?> -
        -
        - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?>
        - - __('Add to Compare') ?> -
        - -

        __('Availability: Out of stock.') ?>

        -

        - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?>
        - - __('Add to Compare') ?> -

        - - -

        __('Availability: In stock. Ships within 24 hours.') ?>

        - __('OR') ?> -    - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> - | - - __('Add to Compare') ?> - -
        - -
        -
        -

        __('Product Description') ?>

        -
        htmlEscape($_product->getDescription()) ?>
        -
        -
        - -
        - getChildHtml('upsell_products') ?> - getAdditionalData()): ?> -
        -
        -

        __('Product Attribute Specs') ?>

        -
        - - - - - - - -
        - -
        - -
        - getChildHtml('product_additional_data') ?> -
        -
        -
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/media.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/media.phtml deleted file mode 100644 index 7c2cd80cae..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/media.phtml +++ /dev/null @@ -1,66 +0,0 @@ - -getProduct() ?> -getImage() != 'no_selection' && $_product->getImage()): ?> -

        - <?php echo $this->htmlEscape($this->getImageLabel()) ?> -

        -
        - <?php echo $this->__('Zoom Out') ?> -
        -
        -
        - <?php echo $this->__('Zoom In') ?> -
        - - -<?php echo $this->htmlEscape($_product->getImageLabel()) ?> - -getGalleryImages()) > 0): ?> -
        -

        __('More Views') ?>

        -
          - getGalleryImages() as $_image): ?> -
        • - - <?php echo $this->htmlEscape($_image->getLabel()) ?> - -
        • - -
        -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/options.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/options.phtml deleted file mode 100644 index 89dc0aa8b6..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/options.phtml +++ /dev/null @@ -1,180 +0,0 @@ - - -decorateArray($this->getOptions()) ?> - - -
        - - getOptionHtml($_option) ?> - -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/options/js.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/options/js.phtml deleted file mode 100644 index 10f29dd122..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/options/js.phtml +++ /dev/null @@ -1,63 +0,0 @@ - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/date.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/options/type/date.phtml deleted file mode 100644 index 24e647d782..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/date.phtml +++ /dev/null @@ -1,90 +0,0 @@ - -getOption() ?> -getId() ?> -
        - getFormatedPrice() ?>
        -decoratedIsLast){?> class="last"> - -getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_DATE_TIME - || $_option->getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_DATE): ?> - - getDateHtml() ?> - - useCalendar()): ?> - - - - - -getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_DATE_TIME - || $_option->getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_TIME): ?> - getTimeHtml() ?> - - - - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/file.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/options/type/file.phtml deleted file mode 100644 index 27cf716ac8..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/file.phtml +++ /dev/null @@ -1,41 +0,0 @@ - -getOption() ?> -
        - getFormatedPrice() ?>
        -decoratedIsLast){?> class="last"> - -getFileExtension()): ?> -

        __('Allowed file extensions to upload')?>: getFileExtension() ?>

        - -getImageSizeX() > 0): ?> -

        __('Maximum image width')?>: getImageSizeX() ?> __('px.')?>

        - -getImageSizeY() > 0): ?> -

        __('Maximum image height')?>: getImageSizeY() ?> __('px.')?>

        - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/select.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/options/type/select.phtml deleted file mode 100644 index e5eb4d3427..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/select.phtml +++ /dev/null @@ -1,37 +0,0 @@ - - -getOption() ?> -
        -decoratedIsLast){?> class="last"> - getValuesHtml() ?> - getIsRequire()): ?> - getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_RADIO || $_option->getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_CHECKBOX): ?> - - - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/text.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/options/type/text.phtml deleted file mode 100644 index 03e6415528..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/options/type/text.phtml +++ /dev/null @@ -1,39 +0,0 @@ - -getOption() ?> -
        - getFormatedPrice() ?>
        -decoratedIsLast){?> class="last"> -getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_FIELD): ?> - -getType() == Mage_Catalog_Model_Product_Option::OPTION_TYPE_AREA): ?> - - -getMaxCharacters()): ?> -

        __('Maximum number of characters')?>: getMaxCharacters() ?>

        - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/options/wrapper.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/options/wrapper.phtml deleted file mode 100644 index 05db366b8a..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/options/wrapper.phtml +++ /dev/null @@ -1,36 +0,0 @@ - - -
        -getChildHtml('', true, true);?> -hasRequiredOptions()):?> -

        __('* Required Fields') ?>

        - -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/price.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/price.phtml deleted file mode 100644 index 71ab32cc95..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/price.phtml +++ /dev/null @@ -1,30 +0,0 @@ - -
        - __('Old Price:') ?> getPrice() ?>
        - getPrice() ?> -
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/price_clone.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/price_clone.phtml deleted file mode 100644 index 0e0396de9e..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/price_clone.phtml +++ /dev/null @@ -1,28 +0,0 @@ - -getProduct() ?> -getPriceHtml($_product, false, '_clone') ?> diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/tierprices.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/tierprices.phtml deleted file mode 100644 index b798cd9cc2..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/tierprices.phtml +++ /dev/null @@ -1,181 +0,0 @@ - - -getProduct(); -$_tierPrices = $this->getTierPrices(); -$_finalPriceInclTax = $this->helper('tax')->getPrice($_product, $_product->getFinalPrice(), true); - -$_weeeTaxAmount = Mage::helper('weee')->getAmountForDisplay($_product); -if (Mage::helper('weee')->typeOfDisplay($_product, array(1,2,4))) { - $_weeeTaxAttributes = Mage::helper('weee')->getProductWeeeAttributesForDisplay($_product); -} - -?> - 0): ?> -
          - getInGrouped()): ?> - getTierPrices($_product); ?> - - processTierPrices($_product, $_tierPrices); ?> - - - helper('tax')->displayBothPrices()): ?> - typeOfDisplay($_product, 0)): ?> -
        • __('Buy %1$s for %2$s (%3$s incl. tax) each', $_price['price_qty'], $_price['formated_price_incl_weee_only'], $_price['formated_price_incl_weee']) ?> - typeOfDisplay($_product, 1)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price_incl_weee_only']); ?> - - ( - __('%1$s incl tax.', $_price['formated_price_incl_weee']); ?> - - - getName(); ?>: currency($_attribute->getAmount()); ?> - - ) - - __('each') ?> - typeOfDisplay($_product, 4)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price_incl_weee_only']); ?> - - ( - __('%1$s incl tax.', $_price['formated_price_incl_weee']); ?> - - - getName(); ?>: currency($_attribute->getAmount()+$_attribute->getTaxAmount()); ?> - - ) - - __('each') ?> - typeOfDisplay($_product, 2)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price']); ?> - - ( - - getName(); ?>: currency($_attribute->getAmount()); ?> - - __('Total incl. Tax: %1$s', $_price['formated_price_incl_weee']); ?> - ) - - __('each') ?> - -
        • __('Buy %1$s for %2$s (%3$s incl. tax) each', $_price['price_qty'], $_price['formated_price'], $_price['formated_price_incl_tax']) ?> - - - helper('tax')->displayPriceIncludingTax()): ?> - typeOfDisplay($_product, 0)): ?> -
        • __('Buy %1$s for %2$s each', $_price['price_qty'], $_price['formated_price_incl_weee']) ?> - typeOfDisplay($_product, 1)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price_incl_weee']); ?> - - ( - - - getName(); ?>: currency($_attribute->getAmount()); ?> - - ) - - __('each') ?> - typeOfDisplay($_product, 4)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price_incl_weee']); ?> - - ( - - - getName(); ?>: currency($_attribute->getAmount()+$_attribute->getTaxAmount()); ?> - - ) - - __('each') ?> - typeOfDisplay($_product, 2)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price_incl_tax']); ?> - - ( - - getName(); ?>: currency($_attribute->getAmount()); ?> - - __('Total incl. Tax: %1$s', $_price['formated_price_incl_weee']); ?> - ) - - __('each') ?> - -
        • __('Buy %1$s for %2$s each', $_price['price_qty'], $_price['formated_price_incl_tax']) ?> - - - typeOfDisplay($_product, 0)): ?> -
        • __('Buy %1$s for %2$s each', $_price['price_qty'], $_price['formated_price_incl_weee_only']) ?> - typeOfDisplay($_product, 1)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price_incl_weee_only']); ?> - - ( - - - getName(); ?>: currency($_attribute->getAmount()); ?> - - ) - - __('each') ?> - typeOfDisplay($_product, 4)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price_incl_weee_only']); ?> - - ( - - - getName(); ?>: currency($_attribute->getAmount()+$_attribute->getTaxAmount()); ?> - - ) - - __('each') ?> - typeOfDisplay($_product, 2)): ?> -
        • __('Buy %1$s for %2$s', $_price['price_qty'], $_price['formated_price']); ?> - - ( - - getName(); ?>: currency($_attribute->getAmount()); ?> - - __('Total incl. Tax: %1$s', $_price['formated_price_incl_weee_only']); ?> - ) - - __('each') ?> - -
        • __('Buy %1$s for %2$s each', $_price['price_qty'], $_price['formated_price']) ?> - - - - getInGrouped()): ?> - getPrice() == $_product->getFinalPrice() && $_product->getPrice() > $_price['price']) - || ($_product->getPrice() != $_product->getFinalPrice() && $_product->getFinalPrice() > $_price['price'])): ?> - __('and') ?> __('save')?> % - - -
        • - -
        - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/type/configurable.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/type/configurable.phtml deleted file mode 100644 index 894a1d14ab..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/type/configurable.phtml +++ /dev/null @@ -1,41 +0,0 @@ - -getProduct() ?> -isSaleable()): ?> -

        __('Availability: In stock.') ?>

        - -

        __('Availability: Out of stock.') ?>

        - -getChildHtml('product_type_data_extra') ?> -getPriceHtml($_product) ?> diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/type/grouped.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/type/grouped.phtml deleted file mode 100644 index aa61580111..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/type/grouped.phtml +++ /dev/null @@ -1,80 +0,0 @@ - -getProduct() ?> -getAssociatedProducts() ?> -isSaleable() && count($_associatedProducts)): ?> -

        __('Availability: In stock.') ?>

        - -

        __('Availability: Out of stock.') ?>

        - -getChildHtml('product_type_data_extra') ?> - - - - - - - - - isSaleable()): ?> - - - - - - - - - - - isSaleable()): ?> - - - - - - - - - - -
        __('Product Name') ?>__('Price') ?>__('Qty') ?>
        htmlEscape($_item->getName()) ?> - getPriceHtml($_item, true) ?> - - isSaleable()) : ?> - - - __('Out of stock.') ?> - -
        __('No options of this product are available.') ?>
        diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/type/options/configurable.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/type/options/configurable.phtml deleted file mode 100644 index e4e6f53d0f..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/type/options/configurable.phtml +++ /dev/null @@ -1,46 +0,0 @@ - - -getProduct(); -$_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes()); -?> -isSaleable() && count($_attributes)):?> -
        - -
        - decoratedIsLast){?> class="last"> - - - -
        - - diff --git a/app/design/frontend/default/iphone/template/catalog/product/view/type/simple.phtml b/app/design/frontend/default/iphone/template/catalog/product/view/type/simple.phtml deleted file mode 100644 index ca53a58f34..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/product/view/type/simple.phtml +++ /dev/null @@ -1,40 +0,0 @@ - -getProduct() ?> -isSaleable()): ?> -

        __('Availability: In stock.') ?>

        - -

        __('Availability: Out of stock.') ?>

        - -getChildHtml('product_type_data_extra') ?> -getPriceHtml($_product) ?> diff --git a/app/design/frontend/default/iphone/template/catalog/seo/sitemap/container.phtml b/app/design/frontend/default/iphone/template/catalog/seo/sitemap/container.phtml deleted file mode 100644 index f792e243d8..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/seo/sitemap/container.phtml +++ /dev/null @@ -1,36 +0,0 @@ - -
        -

        getTitle() ?>

        -
        -
        - getChildHtml('links') ?> -
        -
        -getChildHtml('pager_top') ?> -getChildHtml('sitemap') ?> -getChildHtml('pager_bottom') ?> diff --git a/app/design/frontend/default/iphone/template/catalog/seo/tree.phtml b/app/design/frontend/default/iphone/template/catalog/seo/tree.phtml deleted file mode 100644 index 77f8e16e75..0000000000 --- a/app/design/frontend/default/iphone/template/catalog/seo/tree.phtml +++ /dev/null @@ -1,43 +0,0 @@ - - -getCollection(); ?> -getSize()): ?> -
          - -
        • getLevel($_item)?'style="padding-left:' . $this->getLevel($_item, 2) . '0px;"':'' ?>>name ?>
        • - -
        - -

        - __('There are no %s available.', $this->getItemsTitle()); ?> -

        - diff --git a/app/design/frontend/default/iphone/template/catalogsearch/advanced/form.phtml b/app/design/frontend/default/iphone/template/catalogsearch/advanced/form.phtml deleted file mode 100644 index 8a6e42dd24..0000000000 --- a/app/design/frontend/default/iphone/template/catalogsearch/advanced/form.phtml +++ /dev/null @@ -1,90 +0,0 @@ - - -
        -

        __('Catalog Advanced Search') ?>

        -
        -getMessagesBlock()->getGroupedHtml() ?> -
        - -
        - -
        -
        - -
        diff --git a/app/design/frontend/default/iphone/template/catalogsearch/advanced/result.phtml b/app/design/frontend/default/iphone/template/catalogsearch/advanced/result.phtml deleted file mode 100644 index 13907df783..0000000000 --- a/app/design/frontend/default/iphone/template/catalogsearch/advanced/result.phtml +++ /dev/null @@ -1,67 +0,0 @@ - -
        -

        __('Catalog Advanced Search') ?>

        -
        -getMessagesBlock()->getGroupedHtml() ?> -getResultCount()): ?> -
        - helper('catalogsearch') - ->__('%d item(s) were found using the following search criteria', $this->getResultCount()); ?> -
        - -
        helper('catalogsearch')->__('No items were found using the following search criteria.');?> helper('catalogsearch')->__('Modify your search'); ?>
        - - -getSearchCriterias(); ?> -
        - - -
          - -
        • htmlEscape($this->helper('catalog')->__($criteria['name'])); ?>: htmlEscape($criteria['value']); ?>
        • - -
        - - - - getResultCount()): ?> -
        - helper('catalogsearch')->__("Don't see what you're looking for?"); ?> - helper('catalogsearch')->__('Modify your search'); ?> -
        - -
        -
        - -
        - - -getResultCount()): ?> - getProductListHtml() ?> - -getSearchCriterias(); ?> diff --git a/app/design/frontend/default/iphone/template/catalogsearch/form.mini.phtml b/app/design/frontend/default/iphone/template/catalogsearch/form.mini.phtml index ae06d23ada..0d1aab78af 100644 --- a/app/design/frontend/default/iphone/template/catalogsearch/form.mini.phtml +++ b/app/design/frontend/default/iphone/template/catalogsearch/form.mini.phtml @@ -24,7 +24,7 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -
      -
    - diff --git a/app/design/frontend/default/iphone/template/payment/form/cc.phtml b/app/design/frontend/default/iphone/template/payment/form/cc.phtml deleted file mode 100644 index 9bf8f7d868..0000000000 --- a/app/design/frontend/default/iphone/template/payment/form/cc.phtml +++ /dev/null @@ -1,85 +0,0 @@ - -
    - getMethodCode() ?> - -
    diff --git a/app/design/frontend/default/iphone/template/payment/form/ccsave.phtml b/app/design/frontend/default/iphone/template/payment/form/ccsave.phtml deleted file mode 100644 index c2d5c05c3c..0000000000 --- a/app/design/frontend/default/iphone/template/payment/form/ccsave.phtml +++ /dev/null @@ -1,84 +0,0 @@ - -
    - getMethodCode() ?> - -
    diff --git a/app/design/frontend/default/iphone/template/payment/form/checkmo.phtml b/app/design/frontend/default/iphone/template/payment/form/checkmo.phtml deleted file mode 100644 index 87b0985e8f..0000000000 --- a/app/design/frontend/default/iphone/template/payment/form/checkmo.phtml +++ /dev/null @@ -1,43 +0,0 @@ - -
    - -
    diff --git a/app/design/frontend/default/iphone/template/payment/form/purchaseorder.phtml b/app/design/frontend/default/iphone/template/payment/form/purchaseorder.phtml deleted file mode 100644 index 5ff8baa0f9..0000000000 --- a/app/design/frontend/default/iphone/template/payment/form/purchaseorder.phtml +++ /dev/null @@ -1,36 +0,0 @@ - -
    - -
    diff --git a/app/design/frontend/default/iphone/template/payment/info/checkmo.phtml b/app/design/frontend/default/iphone/template/payment/info/checkmo.phtml deleted file mode 100644 index d5d65fb278..0000000000 --- a/app/design/frontend/default/iphone/template/payment/info/checkmo.phtml +++ /dev/null @@ -1,38 +0,0 @@ - -

    getMethod()->getTitle() ?> -getInfo()->getAdditionalData()): ?> - getPayableTo()): ?>
    __('Make Check payable to: %s', $this->htmlEscape($this->getPayableTo())) ?> - getMailingAddress()): ?> -
    __('Send Check to:') ?> -
    - - htmlEscape($this->getMailingAddress())) ?> - - - -

    diff --git a/app/design/frontend/default/iphone/template/payment/info/purchaseorder.phtml b/app/design/frontend/default/iphone/template/payment/info/purchaseorder.phtml deleted file mode 100644 index a10ae9fb85..0000000000 --- a/app/design/frontend/default/iphone/template/payment/info/purchaseorder.phtml +++ /dev/null @@ -1,29 +0,0 @@ - -

    getMethod()->getTitle() ?>

    -

    __('Purchase Order Number') ?>: htmlEscape($this->getInfo()->getPoNumber()) ?>

    - diff --git a/app/design/frontend/default/iphone/template/poll/active.phtml b/app/design/frontend/default/iphone/template/poll/active.phtml deleted file mode 100644 index 6814fea965..0000000000 --- a/app/design/frontend/default/iphone/template/poll/active.phtml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - -
    -
    -

    __('Community Poll') ?>

    -
    -
    -
    -
    htmlEscape($poll->getPollTitle()); ?>
    - - - - - - - - - - -
     
    - -
    -
    -
    -
    - diff --git a/app/design/frontend/default/iphone/template/poll/result.phtml b/app/design/frontend/default/iphone/template/poll/result.phtml deleted file mode 100644 index e983bd658b..0000000000 --- a/app/design/frontend/default/iphone/template/poll/result.phtml +++ /dev/null @@ -1,50 +0,0 @@ - - -
    -
    -

    __('Community Poll') ?>

    -
    -
    -
    htmlEscape($poll->getPollTitle()); ?>
    - - - - - - - - - - -
    htmlEscape($answer->getAnswerTitle()) ?>getVotesCount() ?> (getPercent() ?>%)
    - -
    -
    - - - diff --git a/app/design/frontend/default/iphone/template/productalert/price.phtml b/app/design/frontend/default/iphone/template/productalert/price.phtml deleted file mode 100644 index 1e32616e93..0000000000 --- a/app/design/frontend/default/iphone/template/productalert/price.phtml +++ /dev/null @@ -1,29 +0,0 @@ - -isShow()): ?> - - diff --git a/app/design/frontend/default/iphone/template/productalert/stock.phtml b/app/design/frontend/default/iphone/template/productalert/stock.phtml deleted file mode 100644 index 3316b2d764..0000000000 --- a/app/design/frontend/default/iphone/template/productalert/stock.phtml +++ /dev/null @@ -1,29 +0,0 @@ - -isShow()): ?> - - diff --git a/app/design/frontend/default/iphone/template/rating/detailed.phtml b/app/design/frontend/default/iphone/template/rating/detailed.phtml deleted file mode 100644 index d42198084c..0000000000 --- a/app/design/frontend/default/iphone/template/rating/detailed.phtml +++ /dev/null @@ -1,44 +0,0 @@ - -getSize()): ?> - - - - getSummary()): ?> - - - - - - - -
    __($this->escapeHtml($_rating->getRatingCode())) ?> -
    -
    -
    -
    - diff --git a/app/design/frontend/default/iphone/template/rating/empty.phtml b/app/design/frontend/default/iphone/template/rating/empty.phtml deleted file mode 100644 index 1ccfc5a7f0..0000000000 --- a/app/design/frontend/default/iphone/template/rating/empty.phtml +++ /dev/null @@ -1,27 +0,0 @@ - -

    __('Be the first to review this product') ?>

    diff --git a/app/design/frontend/default/iphone/template/reports/home_product_compared.phtml b/app/design/frontend/default/iphone/template/reports/home_product_compared.phtml deleted file mode 100644 index 30b903bd0c..0000000000 --- a/app/design/frontend/default/iphone/template/reports/home_product_compared.phtml +++ /dev/null @@ -1,65 +0,0 @@ - -getRecentlyComparedProducts()): ?> -
    -

    __('Your Recently Compared') ?>

    - - - - 5): continue; endif; ?> - - - - - - - -
    -
    - - <?php echo $this->stripTags($_product->getName(), null, true) ?> - -
    -

    helper('catalog/output')->productAttribute($_product, $_product->getName() , 'name') ?>

    - getPriceHtml($_product, true, '-home-compared') ?> - isSaleable()): ?> - - -
    __('Out of stock') ?>
    - -
    -

    - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> - - getAddToCompareUrl($_product)): ?>
    - __('Add to Compare') ?> - -

    -
     
    - diff --git a/app/design/frontend/default/iphone/template/reports/home_product_viewed.phtml b/app/design/frontend/default/iphone/template/reports/home_product_viewed.phtml deleted file mode 100644 index 746e79e532..0000000000 --- a/app/design/frontend/default/iphone/template/reports/home_product_viewed.phtml +++ /dev/null @@ -1,70 +0,0 @@ - - -getRecentlyViewedProducts()): ?> -
    -

    __('Your Recently Viewed') ?>

    - - - - 5): continue; endif; ?> - - - - - - - -
    -
    - - <?php echo $this->stripTags($_product->getName(), null, true) ?> - -
    -

    helper('catalog/output')->productAttribute($_product, $_product->getName() , 'name') ?>

    - getPriceHtml($_product, true, '-home-viewed') ?> - isSaleable()): ?> - - -
    __('Out of stock') ?>
    - -
    -

    - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?> - - getAddToCompareUrl($_product)): ?>
    - __('Add to Compare') ?> - -

    -
     
    - diff --git a/app/design/frontend/default/iphone/template/reports/product_compared.phtml b/app/design/frontend/default/iphone/template/reports/product_compared.phtml deleted file mode 100644 index c2e09875b5..0000000000 --- a/app/design/frontend/default/iphone/template/reports/product_compared.phtml +++ /dev/null @@ -1,44 +0,0 @@ - -getRecentlyComparedProducts()): ?> -
    -
    -

    __('Recently Compared Products') ?>

    -
    - - -
    - diff --git a/app/design/frontend/default/iphone/template/reports/product_viewed.phtml b/app/design/frontend/default/iphone/template/reports/product_viewed.phtml deleted file mode 100644 index 038c2c4d0f..0000000000 --- a/app/design/frontend/default/iphone/template/reports/product_viewed.phtml +++ /dev/null @@ -1,44 +0,0 @@ - -getRecentlyViewedProducts()): ?> -
    -
    -

    __('Recently Viewed Products') ?>

    -
    - - -
    - diff --git a/app/design/frontend/default/iphone/template/review/customer/list.phtml b/app/design/frontend/default/iphone/template/review/customer/list.phtml deleted file mode 100644 index 4822bde5bf..0000000000 --- a/app/design/frontend/default/iphone/template/review/customer/list.phtml +++ /dev/null @@ -1,63 +0,0 @@ - -
    -

    __('My Product Reviews') ?>

    -
    -getCollection() && $this->count()): ?> - getToolbarHtml() ?> - - - - - - - - getCollection() as $_review): ?> - - - - - - - - - -
    dateFormat($_review->getCreatedAt()) ?>htmlEscape($_review->getName()) ?> - getSum()): ?> -
    -
    -
    - -
    htmlEscape($this->helper('review')->getDetail($_review->getDetail())) ?>__('View Details') ?>
    - - getToolbarHtml() ?> - -

    __('You have submitted no reviews.') ?>

    - - diff --git a/app/design/frontend/default/iphone/template/review/customer/recent.phtml b/app/design/frontend/default/iphone/template/review/customer/recent.phtml deleted file mode 100644 index 940b15b658..0000000000 --- a/app/design/frontend/default/iphone/template/review/customer/recent.phtml +++ /dev/null @@ -1,53 +0,0 @@ - -getCollection() && $this->count()): ?> - - diff --git a/app/design/frontend/default/iphone/template/review/customer/view.phtml b/app/design/frontend/default/iphone/template/review/customer/view.phtml deleted file mode 100644 index c52f275769..0000000000 --- a/app/design/frontend/default/iphone/template/review/customer/view.phtml +++ /dev/null @@ -1,68 +0,0 @@ - -getProductData()->getId()): ?> -
    -

    __('Review Details') ?>

    -
    - -
    -
    -

    <?php echo $this->htmlEscape($this->getProductData()->getName()) ?>

    - getRating() && $this->getRating()->getSize()): ?> - __('Average Customer Rating:') ?> - helper('review/product')->getSummaryHtml($this->getProductData()) ?> - -
    -
    -

    htmlEscape($this->getProductData()->getName()) ?>

    - getRating() && $this->getRating()->getSize()): ?> - isReviewOwner()) ? $this->__('Your Rating:') : $this->__('Rating:'); ?> - - getRating() as $_rating): ?> - getPercent()): ?> - - - - - - -
    escapeHtml($_rating->getRatingCode()) ?>
    -
    -
    - - isReviewOwner()): ?> - __('Your Review (submitted on %s):', $this->dateFormat($this->getReviewData()->getCreatedAt())) ?> - - __('Review (submitted on %s):', $this->dateFormat($this->getReviewData()->getCreatedAt())) ?> - -
    -

    htmlEscape($this->getReviewData()->getDetail())) ?>

    -
    -
    - -
    - diff --git a/app/design/frontend/default/iphone/template/review/form.phtml b/app/design/frontend/default/iphone/template/review/form.phtml deleted file mode 100644 index 5fa756800a..0000000000 --- a/app/design/frontend/default/iphone/template/review/form.phtml +++ /dev/null @@ -1,119 +0,0 @@ - -
    -

    __('Write Your Own Review') ?>

    -
    -

    __("You're reviewing: %s", $this->htmlEscape($this->getProductInfo()->getName())) ?>

    -
    -
    - getRatings() && $this->getRatings()->getSize()): ?> - __('How do you rate this product?') ?>*
    - - - - - - - - - - - - - - - getRatings() as $_rating): ?> - - - - getOptions() as $_option): ?> - - class="last" style="width:60px;"> - - - - - - -
     __('1 star') ?>__('2 stars') ?>__('3 stars') ?>__('4 stars') ?>__('5 stars') ?>
    escapeHtml($_rating->getRatingCode()) ?>
    - - - - -
    -
    - -
    - -
    -
    - -
    - -
    -
    - -
    - -
    - -
    -
    -
    - diff --git a/app/design/frontend/default/iphone/template/review/helper/summary.phtml b/app/design/frontend/default/iphone/template/review/helper/summary.phtml deleted file mode 100644 index f18c7111e2..0000000000 --- a/app/design/frontend/default/iphone/template/review/helper/summary.phtml +++ /dev/null @@ -1,40 +0,0 @@ - -getProduct()->getRatingSummary()->getReviewsCount()): ?> - - - -getProduct()->getRatingSummary()->getReviewsCount() && $this->getDisplayBlock() ): ?> -

    __('Be the first to review this product') ?>

    - diff --git a/app/design/frontend/default/iphone/template/review/helper/summary_short.phtml b/app/design/frontend/default/iphone/template/review/helper/summary_short.phtml deleted file mode 100644 index 85fa23c4f7..0000000000 --- a/app/design/frontend/default/iphone/template/review/helper/summary_short.phtml +++ /dev/null @@ -1,39 +0,0 @@ - -SUMMARY SHORT -getProduct()->getRatingSummary()->getReviewsCount()): ?> -
    -
    -
    -
    - ( getProduct()->getRatingSummary()->getReviewsCount()) ?> ) -
    - - -getProduct()->getRatingSummary()->getReviewsCount() && $this->getDisplayBlock() ): ?> -

    __('Be the first to review this product') ?>

    - diff --git a/app/design/frontend/default/iphone/template/review/list.phtml b/app/design/frontend/default/iphone/template/review/list.phtml deleted file mode 100644 index 2ccf2b7eaa..0000000000 --- a/app/design/frontend/default/iphone/template/review/list.phtml +++ /dev/null @@ -1,65 +0,0 @@ - -getSize()): ?> -
    -

    __('Customer Reviews') ?>

    - - getUseBackLink() ): ?> - « __('Back') ?> - - __('View All Reviews') ?> - - - | - __('Add Your Review') ?> -
    - getUseBackLink() ): ?> - getToolbarHtml() ?> - -
      - getCollection() as $_review): ?> -
    1. - getRatingVotes()->getItems()) && $this->getAverage($_review->getRatingVotes()) ): ?> -
      -
      -
      - - htmlEscape($_review->getTitle()) ?> - __('Review by %s', $this->htmlEscape($_review->getNickname())) ?> -

      htmlEscape($_review->getDetail())) ?>

      -
    2. - -
    - getUseBackLink() ): ?> - getToolbarHtml() ?> - - -
    -

    __('Customer Reviews') ?>

    -
    -

    __('Be the first to review this product') ?>

    - diff --git a/app/design/frontend/default/iphone/template/review/product/detailed.phtml b/app/design/frontend/default/iphone/template/review/product/detailed.phtml deleted file mode 100644 index 47a703d335..0000000000 --- a/app/design/frontend/default/iphone/template/review/product/detailed.phtml +++ /dev/null @@ -1,183 +0,0 @@ - -getMessagesBlock()->getGroupedHtml() ?> -getProduct() ?> -
    -
    -
    - getImage() != 'no_selection' && $_product->getImage()): ?> -

    - <?php echo $this->htmlEscape($_product->getName()) ?> -

    -
    - <?php echo $this->__('Zoom Out') ?> -
    -
    -
    - <?php echo $this->__('Zoom In') ?> -
    - - - <?php echo $this->htmlEscape($_product->getName()) ?> - -
    - -
    -

    htmlEscape($product->getName()) ?>

    - getChildHtml('rating') ?> - - __('%s Review(s)', $reviewCount) ?> - - -
    -
    - -
    - - isSuperConfig()): ?> - getChildHtml('super_config') ?> - - getTierPrices($product) ?> - 0): ?> -
    -
      - -
    • __('Buy %s for %s', $_price['price_qty'], $_price['formated_price']) ?>
    • - -
    -
    - - - isGrouped()): ?> - getChildHtml('super_group') ?> - - - isGrouped()): ?> - isSaleable()): ?> -

    __('Availability: In stock.') ?>

    - -

    __('Availability: Out of stock.') ?>

    - - - isSaleable()): ?> - helper('catalog/product')->getPriceHtml($product) ?> -
    - __('Add Items to Cart') ?> - - __('OR') ?> -
    - -
    - helper('wishlist')->isAllow()) : ?> - __('Add to Wishlist') ?>
    - - - helper('catalog/product_compare')->getAddUrl($product)): ?> - __('Add to Compare') ?> - -
    - - - helper('wishlist')->isAllow()) : ?> -

    __('Add to Wishlist') ?>
    - - - helper('catalog/product_compare')->getAddUrl($product)): ?> - __('Add to Compare') ?> -

    - - - - __('OR') ?> - - helper('wishlist')->isAllow()) : ?> -   __('Add to Wishlist') ?> - - - helper('catalog/product_compare')->getAddUrl($product)): ?> - |__('Add to Compare') ?> - - - -
    - -
    -
    - -

    « __('Back to Main Product Info') ?>

    - -
    -
    - -
    - getCollection() && $this->count()): ?> -
    -
    -

    __('Customer Reviews') ?>

    -
    - getToolbarHtml() ?> -
      - getCollection()->getItems() as $_review ): ?> -
    1. - htmlEscape($_review->getTitle()) ?> __('Review by %s', $this->htmlEscape($_review->getNickname())) ?> - - - getRatingVotes() as $_vote ): ?> - - - - - - -
      escapeHtml($_vote->getRatingCode()) ?> -
      -
      -
      -
      -

      htmlEscape($_review->getDetail())) ?> __('(Posted on %s)', $this->formatDate($_review->getCreatedAt()), 'long') ?>

      -
    2. - -
    -
    - getToolbarHtml() ?> - - -
    - getChildHtml('reviewForm') ?> -
    -
    diff --git a/app/design/frontend/default/iphone/template/review/view.phtml b/app/design/frontend/default/iphone/template/review/view.phtml deleted file mode 100644 index 16965ffc7e..0000000000 --- a/app/design/frontend/default/iphone/template/review/view.phtml +++ /dev/null @@ -1,61 +0,0 @@ - -getProductData()->getId()): ?> -
    -

    __('Review Details') ?>

    -
    -
    -
    -

    <?php echo $this->htmlEscape($this->getProductData()->getName()) ?>

    - getRating() && $this->getRating()->getSize()): ?> - __('Average Customer Rating') ?>: - helper('review/product')->getSummaryHtml($this->getProductData()) ?> - -
    -
    -

    htmlEscape($this->getProductData()->getName()) ?>

    - getRating() && $this->getRating()->getSize()): ?> - __('Product Rating:') ?> - getRating() as $_rating): ?> - getPercent()): ?> -
    - __($this->escapeHtml($_rating->getRatingCode())) ?> -
    -
    -
    -
    - - - -
    - __('Product Review (submitted on %s):', $this->dateFormat($this->getReviewData()->getCreatedAt())) ?> -
    -

    htmlEscape($this->getReviewData()->getDetail())) ?>

    -
    -
    -
    - diff --git a/app/design/frontend/default/iphone/template/rss/list.phtml b/app/design/frontend/default/iphone/template/rss/list.phtml deleted file mode 100644 index 0641f7bf02..0000000000 --- a/app/design/frontend/default/iphone/template/rss/list.phtml +++ /dev/null @@ -1,61 +0,0 @@ - -
    -

    __('RSS Feeds') ?>

    -
    -getRssCatalogFeeds(); -$_misc = $this->getRssMiscFeeds(); -?> - - - - - - - - - - -
    __('Miscellaneous Feeds') ?>
    getLabel() ?>__('Get Feed'); ?>
    - -
    - - - - - - - - - - -
    __('Category Feeds') ?>
    getLabel() ?>__('Get Feed'); ?>
    - - -

    __('There are no Rss Feeds.'); ?>

    - diff --git a/app/design/frontend/default/iphone/template/rss/nofeed.phtml b/app/design/frontend/default/iphone/template/rss/nofeed.phtml deleted file mode 100644 index 02bf5d89bc..0000000000 --- a/app/design/frontend/default/iphone/template/rss/nofeed.phtml +++ /dev/null @@ -1 +0,0 @@ -There was no RSS feed enabled. diff --git a/app/design/frontend/default/iphone/template/rss/order/details.phtml b/app/design/frontend/default/iphone/template/rss/order/details.phtml deleted file mode 100644 index 4b848eaef3..0000000000 --- a/app/design/frontend/default/iphone/template/rss/order/details.phtml +++ /dev/null @@ -1,102 +0,0 @@ -getStore()->getName() -web site name = $_order->getStore()->getWebsite()->getName() -store name = $_order->getStore()->getGroup()->getName() -*/ -?> -getOrder() ?> -
    -__('Customer Name: %s', $_order->getCustomerFirstname()?$_order->getCustomerName():$_order->getBillingAddress()->getName()) ?>
    -__('Purchased From: %s', $_order->getStore()->getGroup()->getName()) ?>
    -
    - - - - - - - - - - -getAllItems() as $_item): $i++ ?> - > - - - - - - - - - getGiftMessageId() && $_giftMessage = $this->helper('giftmessage/message')->getGiftMessage($_order->getGiftMessageId())): ?> - - - - - - - - - getDiscountAmount() > 0): ?> - - - - - - getShippingAmount() || $_order->getShippingDescription()): ?> - - - - - - getTaxAmount() > 0): ?> - - - - - - - - - - - -
    ItemQtySubtotal
    htmlEscape($_item->getName()) ?> - getGiftMessageId() && $_giftMessage = $this->helper('giftmessage/message')->getGiftMessage($_item->getGiftMessageId())): ?> -
    __('Gift Message') ?> -
    __('From:'); ?> htmlEscape($_giftMessage->getSender()) ?> -
    __('To:'); ?> htmlEscape($_giftMessage->getRecipient()) ?> -
    __('Message:'); ?>
    htmlEscape($_giftMessage->getMessage()) ?> - -
    getQtyOrdered()*1 ?>formatPrice($_item->getRowTotal()) ?>
    - __('Gift Message') ?> -
    __('From:'); ?> htmlEscape($_giftMessage->getSender()) ?> -
    __('To:'); ?> htmlEscape($_giftMessage->getRecipient()) ?> -
    __('Message:'); ?>
    htmlEscape($_giftMessage->getMessage()) ?> -
    __('Subtotal') ?>formatPrice($_order->getSubtotal()) ?>
    getCouponCode() ? $this->__('Discount (%s)', $_order->getCouponCode()) : $this->__('Discount'); ?>formatPrice(0.00 - $_order->getDiscountAmount()) ?>
    __('Shipping & Handling') ?>formatPrice($_order->getShippingAmount()) ?>
    __('Tax') ?>formatPrice($_order->getTaxAmount()) ?>
    __('Grand Total') ?>formatPrice($_order->getGrandTotal()) ?>
    diff --git a/app/design/frontend/default/iphone/template/sales/order/creditmemo.phtml b/app/design/frontend/default/iphone/template/sales/order/creditmemo.phtml deleted file mode 100644 index ff0807fa98..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/creditmemo.phtml +++ /dev/null @@ -1,111 +0,0 @@ - -helper('giftmessage/message')->getIsMessagesAvailable('order', $this->getOrder())): ?> - - -getOrder() ?> -__('Print All Refunds') ?> -getCreditmemosCollection() as $_creditmemo): ?> -
    -
    -

    __('Refund #') ?>getIncrementId(); ?>

    - __('Print Refund') ?> -
    -

    __('Items Refunded') ?>

    - - - - - - - - - - - - - - - getAllItems(); ?> - - - - $_count ? ' class="last"' : '') ?> id="order-item-row-getId() ?>"> - - - - - - - - - - - - - - getTotalsHtml($_creditmemo);?> - -
    __('Product Name') ?>__('SKU') ?>__('Price') ?>__('Qty') ?>__('Subtotal') ?>__('Tax Amount') ?>__('Discount Amount') ?>__('Row Total') ?>
    - htmlEscape($_item->getName()) ?> - htmlEscape($_item->getDescription()) ?> - htmlEscape($_item->getSku()) ?>formatPrice($_item->getPrice()) ?> getQty()*1 ?>formatPrice($_item->getRowTotal()) ?>formatPrice($_item->getTaxAmount()) ?>formatPrice(-$_item->getDiscountAmount()) ?> - formatPrice($_item->getRowTotal()-$_item->getDiscountAmount()+$_item->getTaxAmount()) ?> -
    - - - diff --git a/app/design/frontend/default/iphone/template/sales/order/details.phtml b/app/design/frontend/default/iphone/template/sales/order/details.phtml deleted file mode 100644 index 11901c3545..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/details.phtml +++ /dev/null @@ -1,107 +0,0 @@ - -getOrder() ?> -
    -

    __('My Orders - Details') ?>

    - -
    -

    __('Order #%s', $_order->getRealOrderId()) ?>

    -getInvoices() as $_invoice): ?> -
    -
    -

    __('Invoice #%s', $_invoice->getIncrementId()) ?>

    - __('Print Invoice') ?> -
    -
    -
    -

    __('Shipping Address') ?>

    - getShippingAddress() ?> -
    getFirstname() ?> getLastname() ?>
    - getCompany() ?>
    - getStreet() ?>
    - getCity() ?>, getRegion() ?> getPostcode() ?>
    - T | getTelephone(); - if ($_shipping->getFax()): ?>
    F | getFax() ?>
    -
    -
    -

    __('Billing Address') ?>

    - getbillingAddress() ?> -
    getFirstname() ?> getLastname() ?>
    - getCompany() ?>
    - getStreet() ?>
    - getCity() ?>, getRegion() ?> getPostcode() ?>
    - T | getTelephone(); - if ($_billing->getFax()): ?>
    F | getFax() ?>
    -
    -
    -
    -
    -
    -

    __('Shipping Method') ?>

    - getShippingMethod() ?> getShippingDescription() ?> -
    -
    -

    __('Payment Method') ?>

    - getPayment() ?> - getMethod() ?>: getCcType() ?> xxxxgetCcLast4() ?> -
    -
    -
    -

    __('Items Ordered') ?>

    - - - - - - - - - - - - getItemsCollection(); ?> - count(); ?> - - - $_count ? ' class="last"' : '') ?>> - - - - - - - - - - - - - - -
    __('Product Name') ?>__('Price') ?>__('Qty Ordered') ?>__('Qty Shipped') ?>__('Subtotal') ?>
    htmlEscape($_item->getProductName()) ?>formatPrice($_item->getPrice()*1) ?>getQty()*1 ?>getQty()*1 ?>formatPrice($_item->getRowTotal()*1) ?>
    __('Order Subtotal') ?>formatPrice($_invoice->getSubtotal()) ?>
    -
    - diff --git a/app/design/frontend/default/iphone/template/sales/order/history.phtml b/app/design/frontend/default/iphone/template/sales/order/history.phtml index 3e5a42c952..d46d2c0c62 100644 --- a/app/design/frontend/default/iphone/template/sales/order/history.phtml +++ b/app/design/frontend/default/iphone/template/sales/order/history.phtml @@ -24,43 +24,42 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> +getMessagesBlock()->getGroupedHtml() ?> getOrders(); ?> -
    -

    __('My Orders') ?>

    - getPagerHtml(); ?> - getSize()): ?> - - - - - - - - - - - - - - - - - - - - - - - - -
    __('Order #') ?>__('Date') ?>__('Ship To') ?>__('Total') ?>__('Status') ?> 
    getRealOrderId() ?>formatDate($_order->getCreatedAtStoreDate()) ?>getShippingAddress() ? $this->htmlEscape($_order->getShippingAddress()->getName()): '' ?>formatPrice($_order->getGrandTotal()) ?>getStatusLabel() ?>__('View') ?> - helper('sales/reorder')->canReorder($_order)) : ?> -
    __('Reorder') ?> - -
    - - getPagerHtml(); ?> - -

    __('You have placed no orders.'); ?>

    - +
    +

    __('My Orders') ?>

    +getPagerHtml(); ?> +getSize()): ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
    __('Order #') ?>__('Date') ?>__('Order Total') ?>__('Order Status') ?> 
    getRealOrderId() ?>formatDate($_order->getCreatedAtStoreDate()) ?>formatPrice($_order->getGrandTotal()) ?>getStatusLabel() ?>
    + +getPagerHtml(); ?> + +

    __('You have placed no orders.'); ?>

    + diff --git a/app/design/frontend/default/iphone/template/sales/order/info.phtml b/app/design/frontend/default/iphone/template/sales/order/info.phtml deleted file mode 100644 index 62273fe512..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/info.phtml +++ /dev/null @@ -1,92 +0,0 @@ - -getOrder() ?> -
    -
    -

    __('Order #%s - %s', $_order->getRealOrderId(), $_order->getStatusLabel()) ?>

    -
    -
    - helper('sales/reorder')->canReorder($_order)) : ?> - __('Reorder') ?> - -
    -
    __('Order Date: %s', $this->formatDate($_order->getCreatedAtStoreDate(), 'long')) ?>
    -
    -
    - getStatusHistoryRssUrl($_order) ?> -
    -
    - - - - - - - - - -
    __('About This Order:') ?>
    -
      - getLinks(); ?> - - getUrl()): ?> -
    • getLabel() ?>
    • - -
    • getLabel() ?>
    • - - -
    -
    -
    -
    -getIsVirtual()): ?> -
    -
    -

    __('Shipping Address') ?>

    -
    getShippingAddress()->format('html') ?>
    -
    -
    -

    __('Shipping Method') ?>

    - getShippingDescription()): ?> - getShippingDescription() ?> - - helper('sales')->__('No shipping information available'); ?> - -
    -
    - -
    -
    -

    __('Billing Address') ?>

    -
    getBillingAddress()->format('html') ?>
    -
    -
    -

    __('Payment Method') ?>

    - getPaymentInfoHtml() ?> -
    -
    -
    diff --git a/app/design/frontend/default/iphone/template/sales/order/invoice.phtml b/app/design/frontend/default/iphone/template/sales/order/invoice.phtml deleted file mode 100644 index c6a9610dbc..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/invoice.phtml +++ /dev/null @@ -1,107 +0,0 @@ - -helper('giftmessage/message')->getIsMessagesAvailable('order', $this->getOrder())): ?> - - -getOrder() ?> -__('Print All Invoices') ?> -getInvoiceCollection() as $_invoice): ?> -
    -
    -

    __('Invoice #') ?>getIncrementId(); ?>

    - __('Print Invoice') ?> -
    - -

    __('Items Invoiced') ?>

    - - - - - - - - - - - - - - - - getAllItems(); ?> - - - - $_count ? ' class="last"' : '') ?> id="order-item-row-getId() ?>"> - - - - - - - - - - getInvoiceTotalsHtml($_invoice)?> - -
    __('Product Name') ?>__('SKU') ?>__('Price') ?>__('Qty Invoiced') ?>__('Subtotal') ?>
    - htmlEscape($_item->getName()) ?> - htmlEscape($_item->getDescription()) ?> - htmlEscape($_item->getSku()) ?>formatPrice($_item->getPrice()) ?> getQty()*1 ?> formatPrice($_item->getRowTotal()) ?>
    - - - diff --git a/app/design/frontend/default/iphone/template/sales/order/items.phtml b/app/design/frontend/default/iphone/template/sales/order/items.phtml deleted file mode 100644 index a133f7ec1a..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/items.phtml +++ /dev/null @@ -1,69 +0,0 @@ - -getOrder() ?> - - - - - - - - - - - - - - - - - getChildHtml('order_totals') ?> - - getItemsCollection(); ?> - - count(); ?> - - getParentItem()) continue; ?> - - getItemHtml($_item) ?> - helper('giftmessage/message')->getIsMessagesAvailable('order_item', $_item) && $_item->getGiftMessageId()): ?> - - helper('giftmessage/message')->getGiftMessageForEntity($_item); ?> - - - - - -
    __('Product Name') ?>__('SKU') ?>__('Price') ?>__('Qty') ?>__('Subtotal') ?>
    - diff --git a/app/design/frontend/default/iphone/template/sales/order/items/renderer/default.phtml b/app/design/frontend/default/iphone/template/sales/order/items/renderer/default.phtml deleted file mode 100644 index 7b7e866688..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/items/renderer/default.phtml +++ /dev/null @@ -1,317 +0,0 @@ - -getItem() ?> - -
    htmlEscape($_item->getName()) ?>
    - getItemOptions()): ?> -
    - -
    htmlEscape($_option['label']) ?>
    - getPrintStatus()): ?> - getFormatedOptionValue($_option) ?> - class="truncated"> - - -
    -
    -
    htmlEscape($_option['label']) ?>
    -
    -
    -
    - - - -
    htmlEscape( (isset($_option['print_value']) ? $_option['print_value'] : $_option['value']) ) ?>
    - - -
    - - htmlEscape($_item->getDescription()) ?> - helper('giftmessage/message')->getIsMessagesAvailable('order_item', $_item) && $_item->getGiftMessageId()): ?> -
    __('Gift Message') ?> - - - htmlEscape(Mage::helper('core/string')->splitInjection($this->getSku())) ?> - - helper('tax')->displaySalesBothPrices() || $this->helper('tax')->displaySalesPriceExclTax()): ?> - - helper('tax')->displaySalesBothPrices()): ?> - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - __('Excl. Tax'); ?>: - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - -
    - - - typeOfDisplay($this->getItem(), array(0, 1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> - getOrder()->formatPrice($this->getItem()->getPrice()+$this->getItem()->getWeeeTaxAppliedAmount()+$this->getItem()->getWeeeTaxDisposition()); ?> - - getOrder()->formatPrice($this->getItem()->getPrice()) ?> - - -
    - - - getApplied($this->getItem())): ?> - - - - typeOfDisplay($this->getItem(), 2, 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - __('Total'); ?>:
    getOrder()->formatPrice($this->getItem()->getPrice()+$this->getItem()->getWeeeTaxAppliedAmount()+$this->getItem()->getWeeeTaxDisposition()); ?>
    -
    - - - -
    - - helper('tax')->displaySalesBothPrices() || $this->helper('tax')->displaySalesPriceInclTax()): ?> - - helper('tax')->displaySalesBothPrices()): ?> - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - __('Incl. Tax'); ?>: - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - - helper('checkout')->getPriceInclTax($this->getItem()); ?> - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - -
    - - - typeOfDisplay($this->getItem(), array(0, 1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> - getOrder()->formatPrice($_incl+$this->getItem()->getWeeeTaxAppliedAmount()); ?> - - getOrder()->formatPrice($_incl-$this->getItem()->getWeeeTaxDisposition()) ?> - - -
    - - - getApplied($this->getItem())): ?> - - - - typeOfDisplay($this->getItem(), 2, 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - __('Total incl. tax'); ?>:
    getOrder()->formatPrice($_incl+$this->getItem()->getWeeeTaxAppliedAmount()); ?>
    -
    - - - - - - - - getItem()->getQtyOrdered() > 0): ?> - __('Ordered'); ?>: getItem()->getQtyOrdered()*1 ?>
    - - getItem()->getQtyShipped() > 0): ?> - __('Shipped'); ?>: getItem()->getQtyShipped()*1 ?>
    - - getItem()->getQtyCanceled() > 0): ?> - __('Canceled'); ?>: getItem()->getQtyCanceled()*1 ?>
    - - getItem()->getQtyRefunded() > 0): ?> - __('Refunded'); ?>: getItem()->getQtyRefunded()*1 ?>
    - -
    - - - helper('tax')->displaySalesBothPrices() || $this->helper('tax')->displaySalesPriceExclTax()): ?> - - helper('tax')->displaySalesBothPrices()): ?> - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - __('Excl. Tax'); ?>: - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - -
    - - - typeOfDisplay($this->getItem(), array(0, 1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> - getOrder()->formatPrice($this->getItem()->getRowTotal()+$this->getItem()->getWeeeTaxAppliedRowAmount()+$this->getItem()->getWeeeTaxRowDisposition()); ?> - - getOrder()->formatPrice($this->getItem()->getRowTotal()) ?> - - -
    - - - getApplied($this->getItem())): ?> - - - - typeOfDisplay($this->getItem(), 2, 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - __('Total'); ?>:
    getOrder()->formatPrice($this->getItem()->getRowTotal()+$this->getItem()->getWeeeTaxAppliedRowAmount()+$this->getItem()->getWeeeTaxRowDisposition()); ?>
    -
    - - - -
    - - helper('tax')->displaySalesBothPrices() || $this->helper('tax')->displaySalesPriceInclTax()): ?> - - helper('tax')->displaySalesBothPrices()): ?> - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - __('Incl. Tax'); ?>: - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - - - helper('checkout')->getSubtotalInclTax($this->getItem()); ?> - typeOfDisplay($this->getItem(), array(1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - -
    - - typeOfDisplay($this->getItem(), array(0, 1, 4), 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> - getOrder()->formatPrice($_incl+$this->getItem()->getWeeeTaxAppliedRowAmount()); ?> - - getOrder()->formatPrice($_incl-$this->getItem()->getWeeeTaxRowDisposition()) ?> - - -
    - - - getApplied($this->getItem())): ?> - - - - typeOfDisplay($this->getItem(), 2, 'sales') && (float)$this->getItem()->getWeeeTaxAppliedAmount()): ?> -
    - __('Total incl. tax'); ?>:
    getOrder()->formatPrice($_incl+$this->getItem()->getWeeeTaxAppliedRowAmount()); ?>
    -
    - - - - - - - - - - diff --git a/app/design/frontend/default/iphone/template/sales/order/print.phtml b/app/design/frontend/default/iphone/template/sales/order/print.phtml deleted file mode 100644 index b780867fe3..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/print.phtml +++ /dev/null @@ -1,84 +0,0 @@ - -getOrder() ?> -

    __('Order #%s', $_order->getRealOrderId()) ?>

    -
    -
    -
    -

    __('Shipping Address') ?>

    -
    getShippingAddress()->format('html') ?>
    -
    -
    -

    __('Billing Address') ?>

    -
    getBillingAddress()->format('html') ?>
    -
    -
    -
    -
    -
    -

    __('Shipping Method') ?>

    - getShippingDescription() ?> -
    -
    -

    __('Payment Method') ?>

    - getPaymentInfoHtml() ?> -
    -
    -
    -

    __('Items Ordered') ?>

    - - - - - - - - - - - - getItemsCollection(); ?> - count(); ?> - - - $_count ? ' class="last"' : '') ?>> - - - - - - - - - - getChildHtml('order_totals') ?> - -
    __('Product Name') ?>__('Price') ?>__('Qty Ordered') ?>__('Qty Shipped') ?>__('Subtotal') ?>
    - htmlEscape($_item->getName()) ?> - htmlEscape($_item->getDescription()) ?> - formatPrice($_item->getPrice()) ?>getQtyOrdered()*1 ?>getQtyShipped()*1 ?>formatPrice($_item->getRowTotal()) ?>
    - diff --git a/app/design/frontend/default/iphone/template/sales/order/print/creditmemo.phtml b/app/design/frontend/default/iphone/template/sales/order/print/creditmemo.phtml deleted file mode 100644 index ef034c4db4..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/print/creditmemo.phtml +++ /dev/null @@ -1,112 +0,0 @@ - -getOrder() ?> - -

    __('Order #%s', $_order->getRealOrderId()) ?>

    -getCreditmemo() ?> - - - - getCreditmemosCollection() ?> - - -
    -
    -

    __('Refund #%s', $_creditmemo->getIncrementId()) ?>

    - -
    -
    -
    -

    __('Shipping Address') ?>

    - getShippingAddress() ?> -
    format('html') ?>
    -
    -
    -

    __('Billing Address') ?>

    - getbillingAddress() ?> -
    getBillingAddress()->format('html') ?>
    -
    -
    -
    -
    -
    -

    __('Shipping Method') ?>

    - getShippingDescription() ?> -
    -
    -

    __('Payment Method') ?>

    - getPaymentInfoHtml() ?> -
    -
    -
    -

    __('Items Ordered') ?>

    - - - - - - - - - - - - - - - getAllItems(); ?> - - - - $_count ? ' class="last"' : '') ?> id="order-item-row-getId() ?>"> - - - - - - - - - - - - - - getTotalsHtml($_creditmemo);?> - -
    __('Product Name') ?>__('SKU') ?>__('Price') ?>__('Qty') ?>__('Subtotal') ?>__('Tax Amount') ?>__('Discount Amount') ?>__('Row Total') ?>
    - htmlEscape($_item->getName()) ?> - htmlEscape($_item->getDescription()) ?> - htmlEscape($_item->getSku()) ?>formatPrice($_item->getPrice()) ?> getQty()*1 ?>formatPrice($_item->getRowTotal()) ?>formatPrice($_item->getTaxAmount()) ?>formatPrice(-$_item->getDiscountAmount()) ?> - formatPrice($_item->getRowTotal()-$_item->getDiscountAmount()+$_item->getTaxAmount()) ?> -
    -
    - - diff --git a/app/design/frontend/default/iphone/template/sales/order/print/invoice.phtml b/app/design/frontend/default/iphone/template/sales/order/print/invoice.phtml deleted file mode 100644 index c3edb3ff3f..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/print/invoice.phtml +++ /dev/null @@ -1,95 +0,0 @@ - -getOrder() ?> - -

    __('Order #%s', $_order->getRealOrderId()) ?>

    -getInvoice() ?> - - - - getInvoiceCollection() ?> - - -
    -
    -

    __('Invoice #%s', $_invoice->getIncrementId()) ?>

    - -
    -
    -
    -

    __('Shipping Address') ?>

    - getShippingAddress() ?> -
    format('html') ?>
    -
    -
    -

    __('Billing Address') ?>

    - getbillingAddress() ?> -
    getBillingAddress()->format('html') ?>
    -
    -
    -
    -
    -
    -

    __('Shipping Method') ?>

    - getShippingDescription() ?> -
    -
    -

    __('Payment Method') ?>

    - getPaymentInfoHtml() ?> -
    -
    -
    -

    __('Items Ordered') ?>

    - - - - - - - - - - - - getItemsCollection(); ?> - count(); ?> - - - getOrderItem()->getParentItem()) continue; ?> - getItemHtml($_item) ?> - - - - getInvoiceTotalsHtml($_invoice)?> - -
    __('Product Name') ?>__('Price') ?>__('Qty Ordered') ?>__('Qty Shipped') ?>__('Subtotal') ?>
    -
    - - diff --git a/app/design/frontend/default/iphone/template/sales/order/print/shipment.phtml b/app/design/frontend/default/iphone/template/sales/order/print/shipment.phtml deleted file mode 100644 index 2ed9e2829f..0000000000 --- a/app/design/frontend/default/iphone/template/sales/order/print/shipment.phtml +++ /dev/null @@ -1,117 +0,0 @@ - -getOrder() ?> - -

    __('Order #%s', $_order->getRealOrderId()) ?>

    -getShipment() ?> - - - - getShipmentsCollection() ?> - - - -
    -
    -

    __('Shipment #%s', $_shipment->getIncrementId()) ?>

    -
    -
    -
    -

    __('Shipping Address') ?>

    - getShippingAddress() ?> -
    format('html') ?>
    -
    -
    -

    __('Billing Address') ?>

    - getbillingAddress() ?> -
    getBillingAddress()->format('html') ?>
    -
    -
    -
    -
    -
    -

    __('Shipping Method') ?>

    - getShippingDescription() ?> - getTracksCollection()) > 0): ?> - - - - - - - - - - - getTracksCollection() as $track): ?> - - - - - - -
    __('Title')?>__('Number')?>
    getTitle() ?>getNumber() ?>
    - -
    -
    -

    __('Payment Method') ?>

    - getPaymentInfoHtml() ?> -
    -
    -
    -

    __('Items Ordered') ?>

    - - - - - - - - - - getItemsCollection(); ?> - count(); ?> - - - $_count ? ' class="last"' : '') ?>> - - - - - - - -
    __('Product Name') ?>__('SKU') ?>__('Qty Shipped') ?>
    - htmlEscape($_item->getName()) ?> - htmlEscape($_item->getDescription()) ?> - htmlEscape($_item->getSku()) ?>getQty()*1 ?>
    -
    - - diff --git a/app/design/frontend/default/iphone/template/sales/order/recent.phtml b/app/design/frontend/default/iphone/template/sales/order/recent.phtml index 628ca9e725..fc106e8c71 100644 --- a/app/design/frontend/default/iphone/template/sales/order/recent.phtml +++ b/app/design/frontend/default/iphone/template/sales/order/recent.phtml @@ -24,44 +24,39 @@ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ ?> -