diff --git a/app/code/Magento/Backend/Block/Template/Context.php b/app/code/Magento/Backend/Block/Template/Context.php index 035a909cb3b38c09284c3a1a1fc61ed0c6085b75..c25dc3c944c44e280e759e62381b5ae21d5ca5af 100644 --- a/app/code/Magento/Backend/Block/Template/Context.php +++ b/app/code/Magento/Backend/Block/Template/Context.php @@ -67,6 +67,8 @@ class Context extends \Magento\Framework\View\Element\Template\Context * @param \Magento\Framework\App\State $appState * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\View\Page\Config $pageConfig + * @param \Magento\Framework\View\Element\Template\File\Resolver $resolver + * @param \Magento\Framework\View\Element\Template\File\Validator $validator * @param \Magento\Framework\AuthorizationInterface $authorization * @param \Magento\Backend\Model\Session $backendSession * @param \Magento\Framework\Math\Random $mathRandom @@ -99,6 +101,8 @@ class Context extends \Magento\Framework\View\Element\Template\Context \Magento\Framework\App\State $appState, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\View\Page\Config $pageConfig, + \Magento\Framework\View\Element\Template\File\Resolver $resolver, + \Magento\Framework\View\Element\Template\File\Validator $validator, \Magento\Framework\AuthorizationInterface $authorization, \Magento\Backend\Model\Session $backendSession, \Magento\Framework\Math\Random $mathRandom, @@ -133,7 +137,9 @@ class Context extends \Magento\Framework\View\Element\Template\Context $enginePool, $appState, $storeManager, - $pageConfig + $pageConfig, + $resolver, + $validator ); } diff --git a/app/code/Magento/Backend/Block/Widget/Context.php b/app/code/Magento/Backend/Block/Widget/Context.php index dacc0fe3379c57233c5bdaf4a2c456d4c5544853..83c3f1827877b4e1c8b179f68068e5362d7eefea 100644 --- a/app/code/Magento/Backend/Block/Widget/Context.php +++ b/app/code/Magento/Backend/Block/Widget/Context.php @@ -49,6 +49,9 @@ class Context extends \Magento\Backend\Block\Template\Context * @param \Magento\Framework\View\TemplateEnginePool $enginePool * @param \Magento\Framework\App\State $appState * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param \Magento\Framework\View\Page\Config $pageConfig + * @param \Magento\Framework\View\Element\Template\File\Resolver $resolver + * @param \Magento\Framework\View\Element\Template\File\Validator $validator * @param \Magento\Framework\AuthorizationInterface $authorization * @param \Magento\Backend\Model\Session $backendSession * @param \Magento\Framework\Math\Random $mathRandom @@ -56,7 +59,6 @@ class Context extends \Magento\Backend\Block\Template\Context * @param \Magento\Framework\Code\NameBuilder $nameBuilder * @param \Magento\Backend\Block\Widget\Button\ButtonList $buttonList * @param Button\ToolbarInterface $toolbar - * @param \Magento\Framework\View\Page\Config $pageConfig * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -84,6 +86,8 @@ class Context extends \Magento\Backend\Block\Template\Context \Magento\Framework\App\State $appState, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\View\Page\Config $pageConfig, + \Magento\Framework\View\Element\Template\File\Resolver $resolver, + \Magento\Framework\View\Element\Template\File\Validator $validator, \Magento\Framework\AuthorizationInterface $authorization, \Magento\Backend\Model\Session $backendSession, \Magento\Framework\Math\Random $mathRandom, @@ -116,6 +120,8 @@ class Context extends \Magento\Backend\Block\Template\Context $appState, $storeManager, $pageConfig, + $resolver, + $validator, $authorization, $backendSession, $mathRandom, diff --git a/app/code/Magento/Captcha/Model/Cart/ConfigPlugin.php b/app/code/Magento/Captcha/Model/Cart/ConfigPlugin.php new file mode 100644 index 0000000000000000000000000000000000000000..73046749a66bfae1f68a81376c9d2963ba995ae9 --- /dev/null +++ b/app/code/Magento/Captcha/Model/Cart/ConfigPlugin.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Captcha\Model\Cart; + +class ConfigPlugin +{ + /** + * @var \Magento\Captcha\Model\Checkout\ConfigProvider + */ + protected $configProvider; + + /** + * @param \Magento\Captcha\Model\Checkout\ConfigProvider $configProvider + */ + public function __construct( + \Magento\Captcha\Model\Checkout\ConfigProvider $configProvider + ) { + $this->configProvider = $configProvider; + } + + /** + * @param \Magento\Checkout\Block\Cart\Sidebar $subject + * @param array $result + * @return array + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetConfig(\Magento\Checkout\Block\Cart\Sidebar $subject, array $result) + { + return array_merge_recursive($result, $this->configProvider->getConfig()); + } +} diff --git a/app/code/Magento/Captcha/Model/Checkout/Plugin/Validation.php b/app/code/Magento/Captcha/Model/Checkout/Plugin/Validation.php deleted file mode 100644 index eac1d7a74421e4994531d7cc71858d5690609fed..0000000000000000000000000000000000000000 --- a/app/code/Magento/Captcha/Model/Checkout/Plugin/Validation.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Captcha\Model\Checkout\Plugin; - -use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\Exception\InputException; - -class Validation -{ - /** - * @var \Magento\Captcha\Helper\Data - */ - protected $captchaHelper; - - /** - * @var array - */ - protected $formIds; - - /** - * @param \Magento\Captcha\Helper\Data $captchaHelper - * @param array $formIds - */ - public function __construct( - \Magento\Captcha\Helper\Data $captchaHelper, - array $formIds - ) { - $this->captchaHelper = $captchaHelper; - $this->formIds = $formIds; - } - - /** - * @param \Magento\Quote\Model\AddressAdditionalDataProcessor $subject - * @param \Magento\Quote\Api\Data\AddressAdditionalDataInterface $additionalData - * @throws \Magento\Framework\Exception\NoSuchEntityException - * @throws \Magento\Framework\Exception\InputException - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function beforeProcess( - \Magento\Quote\Model\AddressAdditionalDataProcessor $subject, - \Magento\Quote\Api\Data\AddressAdditionalDataInterface $additionalData - ) { - $formId = $additionalData->getExtensionAttributes()->getCaptchaFormId(); - $captchaText = $additionalData->getExtensionAttributes()->getCaptchaString(); - - if ($formId !== null && !in_array($formId, $this->formIds)) { - throw new NoSuchEntityException(__('Provided form does not exist')); - } - $captchaModel = $this->captchaHelper->getCaptcha($formId); - if ($captchaModel->isRequired()) { - if (!$captchaModel->isCorrect($captchaText)) { - throw new InputException(__('Incorrect CAPTCHA')); - } - } - } -} diff --git a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php index 39edd79861db2de45bc2f3c508c17afb9f3b3cd6..65cb2d8612abd20e6c3cf8a380de5a00f69cdd0c 100644 --- a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php +++ b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php @@ -26,53 +26,67 @@ class AjaxLogin */ protected $resultJsonFactory; + /** + * @var array + */ + protected $formIds; + /** * @param CaptchaHelper $helper * @param SessionManagerInterface $sessionManager * @param JsonFactory $resultJsonFactory + * @param array $formIds */ public function __construct( CaptchaHelper $helper, SessionManagerInterface $sessionManager, - JsonFactory $resultJsonFactory + JsonFactory $resultJsonFactory, + array $formIds ) { $this->helper = $helper; $this->sessionManager = $sessionManager; $this->resultJsonFactory = $resultJsonFactory; + $this->formIds = $formIds; } /** * @param \Magento\Customer\Controller\Ajax\Login $subject * @param callable $proceed - * @return \Magento\Framework\Controller\ResultInterface + * @return $this + * @throws \Magento\Framework\Exception\NoSuchEntityException * @throws \Zend_Json_Exception + * @SuppressWarnings(PHPMD.NPathComplexity) */ public function aroundExecute( \Magento\Customer\Controller\Ajax\Login $subject, \Closure $proceed ) { - $loginFormId = 'user_login'; + $captchaFormIdField = 'captcha_form_id'; $captchaInputName = 'captcha_string'; /** @var \Magento\Framework\App\RequestInterface $request */ $request = $subject->getRequest(); - /** @var \Magento\Captcha\Model\ModelInterface $captchaModel */ - $captchaModel = $this->helper->getCaptcha($loginFormId); - $loginParams = \Zend_Json::decode($request->getContent()); $username = isset($loginParams['username']) ? $loginParams['username'] : null; - $captchaString = isset($loginParams[$captchaInputName]) - ? $loginParams[$captchaInputName] - : null; + $captchaString = isset($loginParams[$captchaInputName]) ? $loginParams[$captchaInputName] : null; + $loginFormId = isset($loginParams[$captchaFormIdField]) ? $loginParams[$captchaFormIdField] : null; - if ($captchaModel->isRequired($username)) { - $captchaModel->logAttempt($username); - if (!$captchaModel->isCorrect($captchaString)) { - $this->sessionManager->setUsername($username); - /** @var \Magento\Framework\Controller\Result\Json $resultJson */ + foreach ($this->formIds as $formId) { + $captchaModel = $this->helper->getCaptcha($formId); + if ($captchaModel->isRequired($username) && !in_array($loginFormId, $this->formIds)) { $resultJson = $this->resultJsonFactory->create(); - return $resultJson->setData(['errors' => true, 'message' => __('Incorrect CAPTCHA')]); + return $resultJson->setData(['errors' => true, 'message' => __('Provided form does not exist')]); + } + + if ($formId == $loginFormId) { + $captchaModel->logAttempt($username); + if (!$captchaModel->isCorrect($captchaString)) { + $this->sessionManager->setUsername($username); + /** @var \Magento\Framework\Controller\Result\Json $resultJson */ + $resultJson = $this->resultJsonFactory->create(); + return $resultJson->setData(['errors' => true, 'message' => __('Incorrect CAPTCHA')]); + } } } return $proceed(); diff --git a/app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php b/app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php new file mode 100644 index 0000000000000000000000000000000000000000..fd47b19ea9038c553c8183b13066421b94236cfa --- /dev/null +++ b/app/code/Magento/Captcha/Test/Unit/Controller/Refresh/IndexTest.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Captcha\Test\Unit\Controller\Refresh; + +class IndexTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $captchaHelperMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $captchaMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $requestMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $responseMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $contextMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $viewMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $layoutMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $flagMock; + + /** + * @var \Magento\Captcha\Controller\Refresh\Index + */ + protected $model; + + protected function setUp() + { + $this->captchaHelperMock = $this->getMock('Magento\Captcha\Helper\Data', [], [], '', false); + $this->captchaMock = $this->getMock('Magento\Captcha\Model\DefaultModel', [], [], '', false); + $this->requestMock = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false); + $this->responseMock = $this->getMock('Magento\Framework\App\Response\Http', [], [], '', false); + $this->contextMock = $this->getMock('Magento\Framework\App\Action\Context', [], [], '', false); + $this->viewMock = $this->getMock('Magento\Framework\App\ViewInterface'); + $this->layoutMock = $this->getMock('Magento\Framework\View\LayoutInterface'); + $this->flagMock = $this->getMock('Magento\Framework\App\ActionFlag', [], [], '', false); + + $this->contextMock->expects($this->any())->method('getRequest')->will($this->returnValue($this->requestMock)); + $this->contextMock->expects($this->any())->method('getView')->will($this->returnValue($this->viewMock)); + $this->contextMock->expects($this->any())->method('getResponse')->will($this->returnValue($this->responseMock)); + $this->contextMock->expects($this->any())->method('getActionFlag')->will($this->returnValue($this->flagMock)); + $this->viewMock->expects($this->any())->method('getLayout')->will($this->returnValue($this->layoutMock)); + + $this->model = new \Magento\Captcha\Controller\Refresh\Index($this->contextMock, $this->captchaHelperMock); + } + + /** + * @dataProvider executeDataProvider + * @param int $formId + * @param int $callsNumber + */ + public function testExecute($formId, $callsNumber) + { + $content = ['formId' => $formId]; + + $blockMethods = ['setFormId', 'setIsAjax', 'toHtml']; + $blockMock = $this->getMock('Magento\Captcha\Block\Captcha', $blockMethods, [], '', false); + + $this->requestMock->expects($this->any())->method('getPost')->with('formId')->will($this->returnValue($formId)); + $this->requestMock->expects($this->exactly($callsNumber))->method('getContent') + ->will($this->returnValue(json_encode($content))); + $this->captchaHelperMock->expects($this->any())->method('getCaptcha')->with($formId) + ->will($this->returnValue($this->captchaMock)); + $this->captchaMock->expects($this->once())->method('generate'); + $this->captchaMock->expects($this->once())->method('getBlockName')->will($this->returnValue('block')); + $this->captchaMock->expects($this->once())->method('getImgSrc')->will($this->returnValue('source')); + $this->layoutMock->expects($this->once())->method('createBlock')->with('block') + ->will($this->returnValue($blockMock)); + $blockMock->expects($this->any())->method('setFormId')->with($formId)->will($this->returnValue($blockMock)); + $blockMock->expects($this->any())->method('setIsAjax')->with(true)->will($this->returnValue($blockMock)); + $blockMock->expects($this->once())->method('toHtml'); + $this->responseMock->expects($this->once())->method('representJson')->with(json_encode(['imgSrc' => 'source'])); + $this->flagMock->expects($this->once())->method('set')->with('', 'no-postDispatch', true); + + $this->model->execute(); + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + [ + 'formId' => null, + 'callsNumber' => 1, + ], + [ + 'formId' => 1, + 'callsNumber' => 0, + ] + ]; + } +} diff --git a/app/code/Magento/Captcha/Test/Unit/Model/Checkout/ConfigProviderTest.php b/app/code/Magento/Captcha/Test/Unit/Model/Checkout/ConfigProviderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..addc768e6c571efc38a2fa613195b6d6b791a5eb --- /dev/null +++ b/app/code/Magento/Captcha/Test/Unit/Model/Checkout/ConfigProviderTest.php @@ -0,0 +1,121 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Captcha\Test\Unit\Model\Checkout; + +class ConfigProviderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $storeManagerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $captchaHelperMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $captchaMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $storeMock; + + /** + * @var integer + */ + protected $formId = 1; + + /** + * @var \Magento\Captcha\Model\Checkout\ConfigProvider + */ + protected $model; + + protected function setUp() + { + $this->storeManagerMock = $this->getMock('Magento\Store\Model\StoreManagerInterface'); + $this->captchaHelperMock = $this->getMock('Magento\Captcha\Helper\Data', [], [], '', false); + $this->captchaMock = $this->getMock('Magento\Captcha\Model\DefaultModel', [], [], '', false); + $this->storeMock = $this->getMock('Magento\Store\Model\Store', [], [], '', false); + $formIds = [$this->formId]; + + $this->model = new \Magento\Captcha\Model\Checkout\ConfigProvider( + $this->storeManagerMock, + $this->captchaHelperMock, + $formIds + ); + } + + /** + * @dataProvider getConfigDataProvider + * @param bool $isRequired + * @param integer $captchaGenerations + * @param array $expectedConfig + */ + public function testGetConfig($isRequired, $captchaGenerations, $expectedConfig) + { + $this->captchaHelperMock->expects($this->any())->method('getCaptcha')->with($this->formId) + ->will($this->returnValue($this->captchaMock)); + + $this->captchaMock->expects($this->any())->method('isCaseSensitive')->will($this->returnValue(1)); + $this->captchaMock->expects($this->any())->method('getHeight')->will($this->returnValue('12px')); + $this->captchaMock->expects($this->any())->method('isRequired')->will($this->returnValue($isRequired)); + + $this->captchaMock->expects($this->exactly($captchaGenerations))->method('generate'); + $this->captchaMock->expects($this->exactly($captchaGenerations))->method('getImgSrc') + ->will($this->returnValue('source')); + + $this->storeManagerMock->expects($this->any())->method('getStore')->will($this->returnValue($this->storeMock)); + $this->storeMock->expects($this->once())->method('isCurrentlySecure')->will($this->returnValue(true)); + $this->storeMock->expects($this->once())->method('getUrl')->with('captcha/refresh', ['_secure' => true]) + ->will($this->returnValue('https://magento.com/captcha')); + + $config = $this->model->getConfig(); + $this->assertEquals($config, $expectedConfig); + } + + /** + * @return array + */ + public function getConfigDataProvider() + { + return [ + [ + 'isRequired' => true, + 'captchaGenerations' => 1, + 'expectedConfig' => [ + 'captcha' => [ + $this->formId => [ + 'isCaseSensitive' => true, + 'imageHeight' => '12px', + 'imageSrc' => 'source', + 'refreshUrl' => 'https://magento.com/captcha', + 'isRequired' => true + ], + ], + ], + ], + [ + 'isRequired' => false, + 'captchaGenerations' => 0, + 'expectedConfig' => [ + 'captcha' => [ + $this->formId => [ + 'isCaseSensitive' => true, + 'imageHeight' => '12px', + 'imageSrc' => '', + 'refreshUrl' => 'https://magento.com/captcha', + 'isRequired' => false + ], + ], + ], + ], + ]; + } +} diff --git a/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7a79969f8ef4f17c760547f7b7496821b18e9fec --- /dev/null +++ b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php @@ -0,0 +1,173 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Captcha\Test\Unit\Model\Customer\Plugin; + +class AjaxLoginTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $sessionManagerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $captchaHelperMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $jsonFactoryMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $captchaMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $resultJsonMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $requestMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $loginControllerMock; + + /** + * @var array + */ + protected $formIds; + + /** + * @var \Magento\Captcha\Model\Customer\Plugin\AjaxLogin + */ + protected $model; + + protected function setUp() + { + $this->sessionManagerMock = $this->getMock('Magento\Checkout\Model\Session', ['setUsername'], [], '', false); + $this->captchaHelperMock = $this->getMock('Magento\Captcha\Helper\Data', [], [], '', false); + $this->captchaMock = $this->getMock('Magento\Captcha\Model\DefaultModel', [], [], '', false); + $this->jsonFactoryMock = $this->getMock( + 'Magento\Framework\Controller\Result\JsonFactory', + ['create'], + [], + '', + false + ); + $this->resultJsonMock = $this->getMock('Magento\Framework\Controller\Result\Json', [], [], '', false); + $this->requestMock = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false); + $this->loginControllerMock = $this->getMock('Magento\Customer\Controller\Ajax\Login', [], [], '', false); + + $this->loginControllerMock->expects($this->any())->method('getRequest') + ->will($this->returnValue($this->requestMock)); + $this->captchaHelperMock->expects($this->once())->method('getCaptcha') + ->with('user_login')->will($this->returnValue($this->captchaMock)); + $this->formIds = ['user_login']; + + $this->model = new \Magento\Captcha\Model\Customer\Plugin\AjaxLogin( + $this->captchaHelperMock, + $this->sessionManagerMock, + $this->jsonFactoryMock, + $this->formIds + ); + } + + public function testAroundExecute() + { + $username = 'name'; + $captchaString = 'string'; + $requestContent = json_encode([ + 'username' => $username, + 'captcha_string' => $captchaString, + 'captcha_form_id' => $this->formIds[0] + ]); + + $this->requestMock->expects($this->once())->method('getContent')->will($this->returnValue($requestContent)); + $this->captchaMock->expects($this->once())->method('isRequired')->with($username) + ->will($this->returnValue(true)); + $this->captchaMock->expects($this->once())->method('logAttempt')->with($username); + $this->captchaMock->expects($this->once())->method('isCorrect')->with($captchaString) + ->will($this->returnValue(true)); + + $closure = function () { + return 'result'; + }; + $this->assertEquals('result', $this->model->aroundExecute($this->loginControllerMock, $closure)); + } + + public function testAroundExecuteIncorrectCaptcha() + { + $username = 'name'; + $captchaString = 'string'; + $requestContent = json_encode([ + 'username' => $username, + 'captcha_string' => $captchaString, + 'captcha_form_id' => $this->formIds[0] + ]); + + $this->requestMock->expects($this->once())->method('getContent')->will($this->returnValue($requestContent)); + $this->captchaMock->expects($this->once())->method('isRequired')->with($username) + ->will($this->returnValue(true)); + $this->captchaMock->expects($this->once())->method('logAttempt')->with($username); + $this->captchaMock->expects($this->once())->method('isCorrect') + ->with($captchaString)->will($this->returnValue(false)); + + $this->sessionManagerMock->expects($this->once())->method('setUsername')->with($username); + $this->jsonFactoryMock->expects($this->once())->method('create') + ->will($this->returnValue($this->resultJsonMock)); + + $this->resultJsonMock->expects($this->once())->method('setData') + ->with(['errors' => true, 'message' => __('Incorrect CAPTCHA')])->will($this->returnValue('response')); + + $closure = function () { + }; + $this->assertEquals('response', $this->model->aroundExecute($this->loginControllerMock, $closure)); + } + + /** + * @dataProvider aroundExecuteCaptchaIsNotRequired + * @param string $username + * @param array $requestContent + */ + public function testAroundExecuteCaptchaIsNotRequired($username, $requestContent) + { + $this->requestMock->expects($this->once())->method('getContent')->will($this->returnValue($requestContent)); + + $this->captchaMock->expects($this->once())->method('isRequired')->with($username) + ->will($this->returnValue(false)); + $this->captchaMock->expects($this->never())->method('logAttempt')->with($username); + $this->captchaMock->expects($this->never())->method('isCorrect'); + + $closure = function () { + return 'result'; + }; + $this->assertEquals('result', $this->model->aroundExecute($this->loginControllerMock, $closure)); + } + + /** + * @return array + */ + public function aroundExecuteCaptchaIsNotRequired() + { + return [ + [ + 'username' => 'name', + 'requestContent' => json_encode(['username' => 'name', 'captcha_string' => 'string']), + ], + [ + 'username' => null, + 'requestContent' => json_encode(['captcha_string' => 'string']), + ], + ]; + } +} diff --git a/app/code/Magento/Captcha/composer.json b/app/code/Magento/Captcha/composer.json index 987ef790dfd28fc18a1e0a87488a86213f350154..a52065c0e94a4ddbcde9e27a053311b619e9519d 100644 --- a/app/code/Magento/Captcha/composer.json +++ b/app/code/Magento/Captcha/composer.json @@ -6,7 +6,6 @@ "magento/module-store": "0.74.0-beta15", "magento/module-customer": "0.74.0-beta15", "magento/module-checkout": "0.74.0-beta15", - "magento/module-quote": "0.74.0-beta15", "magento/module-backend": "0.74.0-beta15", "magento/framework": "0.74.0-beta15", "magento/magento-composer-installer": "*" diff --git a/app/code/Magento/Captcha/etc/di.xml b/app/code/Magento/Captcha/etc/di.xml index 2f150515f4ef38c3d2b14eb746aac1409d422dc6..6dfdcd70b2222544e04939b7eb1aa4404dd07083 100644 --- a/app/code/Magento/Captcha/etc/di.xml +++ b/app/code/Magento/Captcha/etc/di.xml @@ -19,16 +19,15 @@ <type name="Magento\Customer\Controller\Ajax\Login"> <plugin name="configurable_product" type="Magento\Captcha\Model\Customer\Plugin\AjaxLogin" sortOrder="50" /> </type> - <type name="Magento\Quote\Model\AddressAdditionalDataProcessor"> - <plugin name="captcha_validation" type="\Magento\Captcha\Model\Checkout\Plugin\Validation" /> - </type> - <type name="Magento\Captcha\Model\Checkout\Plugin\Validation"> + <type name="Magento\Captcha\Model\Customer\Plugin\AjaxLogin"> <arguments> <argument name="formIds" xsi:type="array"> <item name="user_login" xsi:type="string">user_login</item> <item name="guest_checkout" xsi:type="string">guest_checkout</item> - <item name="register_during_checkout" xsi:type="string">register_during_checkout</item> </argument> </arguments> </type> + <type name="Magento\Checkout\Block\Cart\Sidebar"> + <plugin name="login_captcha" type="\Magento\Captcha\Model\Cart\ConfigPlugin" sortOrder="50" /> + </type> </config> diff --git a/app/code/Magento/Captcha/etc/extension_attributes.xml b/app/code/Magento/Captcha/etc/extension_attributes.xml deleted file mode 100644 index e99af65250102d4db36964850c3ee1d602f08b99..0000000000000000000000000000000000000000 --- a/app/code/Magento/Captcha/etc/extension_attributes.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/extension_attributes.xsd"> - <extension_attributes for="Magento\Quote\Api\Data\AddressAdditionalDataInterface"> - <attribute code="captcha_string" type="string" /> - <attribute code="captcha_form_id" type="string" /> - </extension_attributes> -</config> - - diff --git a/app/code/Magento/Captcha/etc/frontend/di.xml b/app/code/Magento/Captcha/etc/frontend/di.xml index 4807eb77b726076246107bddfc1acbac299d83a6..a768ffac2f67e372ed36af36133105b7ca909f54 100644 --- a/app/code/Magento/Captcha/etc/frontend/di.xml +++ b/app/code/Magento/Captcha/etc/frontend/di.xml @@ -18,7 +18,6 @@ <argument name="formIds" xsi:type="array"> <item name="user_login" xsi:type="string">user_login</item> <item name="guest_checkout" xsi:type="string">guest_checkout</item> - <item name="register_during_checkout" xsi:type="string">register_during_checkout</item> </argument> </arguments> </type> diff --git a/app/code/Magento/Captcha/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Captcha/view/frontend/layout/checkout_onepage_index.xml index 3154d7f81876805131083c4912ab3e0fbf93cc87..d7d6fc551c5ff3f777effb8a6cf3b573c60113a1 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/checkout_onepage_index.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="checkout.root"> <arguments> @@ -13,30 +13,59 @@ <item name="components" xsi:type="array"> <item name="checkout" xsi:type="array"> <item name="children" xsi:type="array"> + <item name="authentication" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="captcha" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/loginCaptcha</item> + <item name="displayArea" xsi:type="string">additional-login-form-fields</item> + <item name="formId" xsi:type="string">user_login</item> + <item name="configSource" xsi:type="string">checkoutConfig</item> + </item> + </item> + </item> <item name="steps" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="authentication" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="captcha" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/loginCaptcha</item> - <item name="displayArea" xsi:type="string">additional-login-form-fields</item> - <item name="formId" xsi:type="string">user_login</item> + <item name="shippingAddress" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="customer-email" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="additional-login-form-fields" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="captcha" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/loginCaptcha</item> + <item name="displayArea" xsi:type="string">additional-login-form-fields</item> + <item name="formId" xsi:type="string">guest_checkout</item> + <item name="configSource" xsi:type="string">checkoutConfig</item> + </item> + </item> + </item> + </item> + </item> + </item> </item> </item> </item> - <item name="billingAddress" xsi:type="array"> + <item name="billing-step" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="captcha_guest_checkout" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/guestCaptcha</item> - <item name="displayArea" xsi:type="string">additional-fieldsets</item> - <item name="formId" xsi:type="string">guest_checkout</item> - <item name="dataScope" xsi:type="string">additionalAddressData</item> - </item> - <item name="captcha_register_during_checkout" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/registerCaptcha</item> - <item name="displayArea" xsi:type="string">additional-fieldsets</item> - <item name="formId" xsi:type="string">register_during_checkout</item> - <item name="dataScope" xsi:type="string">additionalAddressData</item> + <item name="payment" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="customer-email" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="additional-login-form-fields" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="captcha" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/loginCaptcha</item> + <item name="displayArea" xsi:type="string">additional-login-form-fields</item> + <item name="formId" xsi:type="string">guest_checkout</item> + <item name="configSource" xsi:type="string">checkoutConfig</item> + </item> + </item> + </item> + </item> + </item> + </item> </item> </item> </item> @@ -49,4 +78,4 @@ </arguments> </referenceBlock> </body> -</page> \ No newline at end of file +</page> diff --git a/app/code/Magento/Captcha/view/frontend/layout/default.xml b/app/code/Magento/Captcha/view/frontend/layout/default.xml new file mode 100644 index 0000000000000000000000000000000000000000..9e0bf3cc751c5c0b9fad96ea62e3da31b26ed320 --- /dev/null +++ b/app/code/Magento/Captcha/view/frontend/layout/default.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="minicart"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="minicart_content" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="sign-in-popup" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="captcha" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Captcha/js/view/checkout/loginCaptcha</item> + <item name="displayArea" xsi:type="string">additional-login-form-fields</item> + <item name="formId" xsi:type="string">user_login</item> + <item name="configSource" xsi:type="string">checkout</item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/Captcha/view/frontend/web/js/action/refresh.js b/app/code/Magento/Captcha/view/frontend/web/js/action/refresh.js index cc8b2119827216883b9330c5717d5cbf1d460337..b11ae9b1f144aee227da25267b86dd7cc7ed1681 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/action/refresh.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/action/refresh.js @@ -9,9 +9,10 @@ define( function(storage) { "use strict"; return function(refreshUrl, formId, imageSource) { - storage.post( + return storage.post( refreshUrl, - JSON.stringify({'formId': formId}) + JSON.stringify({'formId': formId}), + false ).done( function (response) { if (response.imgSrc) { diff --git a/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js b/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js index a8abae3cc8de7638c7c6414df11a646935e3e715..6a720a8cdeb91879729ecc3ca4aa85f3e497f3bd 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/model/captcha.js @@ -6,10 +6,11 @@ /*global alert*/ define( [ + 'jquery', 'ko', 'Magento_Captcha/js/action/refresh' ], - function(ko, refreshAction) { + function($, ko, refreshAction) { return function (captchaData) { return { formId: captchaData.formId, @@ -20,6 +21,7 @@ define( isCaseSensitive: captchaData.isCaseSensitive, imageHeight: captchaData.imageHeight, refreshUrl: captchaData.refreshUrl, + isLoading: ko.observable(false), getFormId: function () { return this.formId; @@ -70,7 +72,14 @@ define( this.captchaValue(value); }, refresh: function() { - refreshAction(this.getRefreshUrl(), this.getFormId(), this.getImageSource()); + var refresh, + self = this; + this.isLoading(true); + + refresh = refreshAction(this.getRefreshUrl(), this.getFormId(), this.getImageSource()); + $.when(refresh).done(function() { + self.isLoading(false); + }); } }; } diff --git a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js index 5039e6a56a4d254c1f3763c3ead7d62efc481f81..ddb4a6f84ae57bf22a0c9396a5843658813f0785 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/defaultCaptcha.js @@ -7,15 +7,14 @@ define( [ 'jquery', - 'ko', 'uiComponent', - 'Magento_Customer/js/model/customer', 'Magento_Captcha/js/model/captcha', 'Magento_Captcha/js/model/captchaList' ], - function ($, ko, Component, customer, Captcha, captchaList) { - "use strict"; - var captchaConfig = window.checkoutConfig.captcha; + function ($, Component, Captcha, captchaList) { + 'use strict'; + var captchaConfig; + return Component.extend({ defaults: { template: 'Magento_Captcha/checkout/captcha' @@ -26,11 +25,16 @@ define( return this.currentCaptcha.getCaptchaValue(); }, initialize: function() { + this._super(); + captchaConfig = window[this.configSource]['captcha']; + $.each(captchaConfig, function(formId, captchaData) { captchaData.formId = formId; captchaList.add(Captcha(captchaData)); }); - this._super(); + }, + getIsLoading: function() { + return this.currentCaptcha.isLoading }, getCurrentCaptcha: function() { return this.currentCaptcha; diff --git a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/guestCaptcha.js b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/guestCaptcha.js deleted file mode 100644 index eb7e9c806e64bd94da1086bf4e92af253ce8027a..0000000000000000000000000000000000000000 --- a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/guestCaptcha.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true jquery:true*/ -/*global define*/ -define( - [ - 'Magento_Captcha/js/view/checkout/defaultCaptcha', - 'Magento_Checkout/js/model/quote', - 'Magento_Captcha/js/model/captchaList', - 'Magento_Checkout/js/action/select-shipping-address', - 'Magento_Checkout/js/action/select-billing-address', - 'Magento_Checkout/js/model/step-navigator' - ], - function (defaultCaptcha, quote, captchaList, selectShippingAddress, selectBillingAddress, navigator) { - "use strict"; - return defaultCaptcha.extend({ - initialize: function() { - this._super(); - var self = this; - var currentCaptcha = captchaList.getCaptchaByFormId(this.formId); - if (currentCaptcha != null) { - this.setCurrentCaptcha(currentCaptcha); - quote.getCheckoutMethod().subscribe(function(method) { - if (method == 'guest') { - self.setIsVisible(true); - var callback = function(isSuccessful) { - if (!isSuccessful) { - currentCaptcha.setCaptchaValue(null); - currentCaptcha.refresh(); - navigator.goToStep('billingAddress'); - } - }; - selectShippingAddress.setActionCallback(callback); - selectBillingAddress.setActionCallback(callback); - } else { - self.setIsVisible(false); - } - }); - } - } - }); - } -); diff --git a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js index e042e96e850e6558926cd6612a8a9d7526635c77..75f7c4f0071dc96da86f13112f3d8c04190e6a02 100644 --- a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js +++ b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/loginCaptcha.js @@ -7,26 +7,25 @@ define( [ 'Magento_Captcha/js/view/checkout/defaultCaptcha', - 'Magento_Customer/js/model/customer', - 'Magento_Captcha/js/model/captchaList' + 'Magento_Captcha/js/model/captchaList', + 'Magento_Customer/js/action/login' ], - function (defaultCaptcha, customer, captchaList) { - "use strict"; + function (defaultCaptcha, captchaList, loginAction) { + 'use strict'; return defaultCaptcha.extend({ initialize: function() { this._super(); - var currentCaptcha = captchaList.getCaptchaByFormId(this.formId); + var currentCaptcha = captchaList.getCaptchaByFormId(this.formId), + self = this; + if (currentCaptcha != null) { currentCaptcha.setIsVisible(true); this.setCurrentCaptcha(currentCaptcha); - this.updateCaptchaOnFailedLogin(); - } - }, - updateCaptchaOnFailedLogin: function () { - if (this.formId == 'user_login') { - var self = this; - customer.getFailedLoginAttempts().subscribe(function() { - self.refresh(); + + loginAction.registerLoginCallback(function(loginData) { + if (loginData.captcha_form_id && loginData.captcha_form_id == self.formId) { + self.refresh(); + } }); } } diff --git a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/registerCaptcha.js b/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/registerCaptcha.js deleted file mode 100644 index ea284b5fe562483669319af1c308409d4e137358..0000000000000000000000000000000000000000 --- a/app/code/Magento/Captcha/view/frontend/web/js/view/checkout/registerCaptcha.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true jquery:true*/ -/*global define*/ -define( - [ - 'Magento_Captcha/js/view/checkout/defaultCaptcha', - 'Magento_Checkout/js/model/quote', - 'Magento_Captcha/js/model/captchaList', - 'Magento_Checkout/js/action/select-shipping-address', - 'Magento_Checkout/js/action/select-billing-address', - 'Magento_Checkout/js/model/step-navigator' - ], - function (defaultCaptcha, quote, captchaList, selectShippingAddress, selectBillingAddress, navigator) { - "use strict"; - return defaultCaptcha.extend({ - initialize: function() { - this._super(); - var self = this; - var currentCaptcha = captchaList.getCaptchaByFormId(this.formId); - if (currentCaptcha != null) { - this.setCurrentCaptcha(currentCaptcha); - quote.getCheckoutMethod().subscribe(function(method) { - if (method == 'register') { - self.setIsVisible(true); - var callback = function(isSuccessful) { - if (!isSuccessful) { - currentCaptcha.setCaptchaValue(null); - currentCaptcha.refresh(); - navigator.goToStep('billingAddress'); - } - }; - selectShippingAddress.setActionCallback(callback); - selectBillingAddress.setActionCallback(callback); - } else { - self.setIsVisible(false); - } - }); - } - } - }); - } -); diff --git a/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html b/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html index fd345b82386446b5553ef81f3ce56b5e1c70f158..3b294d904b2cbe877dd80763986aa7fa66ecf89b 100644 --- a/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html +++ b/app/code/Magento/Captcha/view/frontend/web/template/checkout/captcha.html @@ -5,7 +5,7 @@ */ --> <!-- ko if: (isRequired() && getIsVisible())--> -<div class="field captcha required"> +<div class="field captcha required" data-bind="blockLoader: getIsLoading()"> <label data-bind="attr: {for: 'captcha_' + formId}" class="label"><span data-bind="text: $t('Please type the letters below')"></span></label> <div class="control captcha"> <input name="captcha_string" type="text" class="input-text required-entry" data-bind="value: captchaValue(), attr: {id: 'captcha_' + formId, 'data-scope': dataScope}" /> diff --git a/app/code/Magento/Catalog/Block/Product/Context.php b/app/code/Magento/Catalog/Block/Product/Context.php index a0d38f5d3c28a751df57aa7e44dbbfcde69847c3..b707ad5848b054ccf20039530499a588365facf7 100644 --- a/app/code/Magento/Catalog/Block/Product/Context.php +++ b/app/code/Magento/Catalog/Block/Product/Context.php @@ -94,6 +94,9 @@ class Context extends \Magento\Framework\View\Element\Template\Context * @param \Magento\Framework\View\TemplateEnginePool $enginePool * @param \Magento\Framework\App\State $appState * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param \Magento\Framework\View\Page\Config $pageConfig + * @param \Magento\Framework\View\Element\Template\File\Resolver $resolver + * @param \Magento\Framework\View\Element\Template\File\Validator $validator * @param \Magento\Catalog\Model\Config $catalogConfig * @param \Magento\Framework\Registry $registry * @param \Magento\Tax\Helper\Data $taxHelper @@ -105,7 +108,6 @@ class Context extends \Magento\Framework\View\Element\Template\Context * @param \Magento\Catalog\Helper\Image $imageHelper * @param ReviewRendererInterface $reviewRenderer * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry - * @param \Magento\Framework\View\Page\Config $pageConfig * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -133,6 +135,8 @@ class Context extends \Magento\Framework\View\Element\Template\Context \Magento\Framework\App\State $appState, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\View\Page\Config $pageConfig, + \Magento\Framework\View\Element\Template\File\Resolver $resolver, + \Magento\Framework\View\Element\Template\File\Validator $validator, \Magento\Catalog\Model\Config $catalogConfig, \Magento\Framework\Registry $registry, \Magento\Tax\Helper\Data $taxHelper, @@ -179,7 +183,9 @@ class Context extends \Magento\Framework\View\Element\Template\Context $enginePool, $appState, $storeManager, - $pageConfig + $pageConfig, + $resolver, + $validator ); } diff --git a/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationPoolTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationPoolTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5b0f7dd0f9340b1c33eb6b1ec0d41b749243e620 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationPoolTest.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Test\Unit\Helper\Product; + +class ConfigurationPoolTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var array + */ + protected $instancesType; + + /** + * @var \Magento\Catalog\Helper\Product\ConfigurationPool + */ + protected $model; + + protected function setUp() + { + $this->instancesType = ['simple' => 'simple', 'default' => 'default']; + + $objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface'); + $this->model = new \Magento\Catalog\Helper\Product\ConfigurationPool($objectManagerMock, $this->instancesType); + } + + /** + * @dataProvider getByProductTypeDataProvider + * @param string $productType + * @param string $expectedResult + */ + public function testGetByProductType($productType, $expectedResult) + { + $this->assertEquals($expectedResult, $this->model->getByProductType($productType)); + } + + /** + * @return array + */ + public function getByProductTypeDataProvider() + { + return [ + [ + 'productType' => 'simple', + 'expectedResult' => 'simple' + ], + [ + 'productType' => 'custom', + 'expectedResult' => 'default' + ], + ]; + } +} diff --git a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Actions.php b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Actions.php index 7eac125efeaa9844f69f5def335f7eece0d5e7f6..ea19e1bee5c9874b40d0e484ff3d82157666961f 100644 --- a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Actions.php +++ b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Actions.php @@ -15,6 +15,7 @@ class Actions extends Generic implements TabInterface * Prepare content for tab * * @return \Magento\Framework\Phrase + * @codeCoverageIgnore */ public function getTabLabel() { @@ -25,6 +26,7 @@ class Actions extends Generic implements TabInterface * Prepare title for tab * * @return \Magento\Framework\Phrase + * @codeCoverageIgnore */ public function getTabTitle() { @@ -35,6 +37,7 @@ class Actions extends Generic implements TabInterface * Returns status flag about this tab can be showen or not * * @return bool + * @codeCoverageIgnore */ public function canShowTab() { @@ -45,6 +48,7 @@ class Actions extends Generic implements TabInterface * Returns status flag about this tab hidden or not * * @return bool + * @codeCoverageIgnore */ public function isHidden() { diff --git a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php index e52687c42cf0a92d72555376807378479b4cb05d..478a5556997cdd03d62195d3039ca35e3ae40f22 100644 --- a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php +++ b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Conditions.php @@ -46,6 +46,7 @@ class Conditions extends Generic implements TabInterface * Prepare content for tab * * @return \Magento\Framework\Phrase + * @codeCoverageIgnore */ public function getTabLabel() { @@ -56,6 +57,7 @@ class Conditions extends Generic implements TabInterface * Prepare title for tab * * @return \Magento\Framework\Phrase + * @codeCoverageIgnore */ public function getTabTitle() { @@ -66,6 +68,7 @@ class Conditions extends Generic implements TabInterface * Returns status flag about this tab can be showen or not * * @return bool + * @codeCoverageIgnore */ public function canShowTab() { @@ -76,6 +79,7 @@ class Conditions extends Generic implements TabInterface * Returns status flag about this tab hidden or not * * @return bool + * @codeCoverageIgnore */ public function isHidden() { diff --git a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Main.php b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Main.php index 9b50207884c18ed1b9a124e751c4a485cf2c347b..c3da800a88d65759a74ea4414d4102a45a52a7d8 100644 --- a/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Main.php +++ b/app/code/Magento/CatalogRule/Block/Adminhtml/Promo/Catalog/Edit/Tab/Main.php @@ -68,6 +68,7 @@ class Main extends Generic implements TabInterface * Prepare content for tab * * @return \Magento\Framework\Phrase + * @codeCoverageIgnore */ public function getTabLabel() { @@ -78,6 +79,7 @@ class Main extends Generic implements TabInterface * Prepare title for tab * * @return \Magento\Framework\Phrase + * @codeCoverageIgnore */ public function getTabTitle() { @@ -88,6 +90,7 @@ class Main extends Generic implements TabInterface * Returns status flag about this tab can be showed or not * * @return bool + * @codeCoverageIgnore */ public function canShowTab() { @@ -98,6 +101,7 @@ class Main extends Generic implements TabInterface * Returns status flag about this tab hidden or not * * @return bool + * @codeCoverageIgnore */ public function isHidden() { diff --git a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog.php b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog.php index f5c53227cf41c7587d110a9b50dab39aae37bd10..775d4ba8dfe6465c05a6a2a47d112a768197f709 100644 --- a/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog.php +++ b/app/code/Magento/CatalogRule/Controller/Adminhtml/Promo/Catalog.php @@ -86,6 +86,7 @@ class Catalog extends Action * * @param string $dirtyRulesNoticeMessage * @return void + * @codeCoverageIgnore */ public function setDirtyRulesNoticeMessage($dirtyRulesNoticeMessage) { diff --git a/app/code/Magento/CatalogRule/Model/Indexer/AbstractIndexer.php b/app/code/Magento/CatalogRule/Model/Indexer/AbstractIndexer.php index dd32624a89912a5a3a8434f2975ed266bda2cb42..cef2b010b1d4070fe0cfc00db054890cb61a6033 100644 --- a/app/code/Magento/CatalogRule/Model/Indexer/AbstractIndexer.php +++ b/app/code/Magento/CatalogRule/Model/Indexer/AbstractIndexer.php @@ -60,6 +60,7 @@ abstract class AbstractIndexer implements IndexerActionInterface, MviewActionInt * Get affected cache tags * * @return array + * @codeCoverageIgnore */ public function getIdentities() { diff --git a/app/code/Magento/CatalogRule/Model/Resource/Rule.php b/app/code/Magento/CatalogRule/Model/Resource/Rule.php index b20a93b2b6f15ee8904c2d8823b58fbd4ca1ef52..fe950295f0781e77ee525a65719883f19411dee2 100644 --- a/app/code/Magento/CatalogRule/Model/Resource/Rule.php +++ b/app/code/Magento/CatalogRule/Model/Resource/Rule.php @@ -135,6 +135,7 @@ class Rule extends \Magento\Rule\Model\Resource\AbstractResource * Initialize main table and table id field * * @return void + * @codeCoverageIgnore */ protected function _construct() { diff --git a/app/code/Magento/CatalogRule/Model/Resource/Rule/Collection.php b/app/code/Magento/CatalogRule/Model/Resource/Rule/Collection.php index d23367451d26ce59315883d507e2cdb2c4fe8a1a..bda374dbafac623adce4a2c9bc7d122575ce9a98 100644 --- a/app/code/Magento/CatalogRule/Model/Resource/Rule/Collection.php +++ b/app/code/Magento/CatalogRule/Model/Resource/Rule/Collection.php @@ -24,6 +24,7 @@ class Collection extends \Magento\Rule\Model\Resource\Rule\Collection\AbstractCo * Set resource model * * @return void + * @codeCoverageIgnore */ protected function _construct() { diff --git a/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price.php b/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price.php index 66f19d5c5234851cec5463701609323bfa382684..3f96fc0775c4bd0a4ec4b2b348520dce447b0bd1 100644 --- a/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price.php +++ b/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price.php @@ -17,6 +17,7 @@ class Price extends \Magento\Framework\Model\Resource\Db\AbstractDb * Initialize connection and define main table * * @return void + * @codeCoverageIgnore */ protected function _construct() { diff --git a/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price/Collection.php b/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price/Collection.php index 8775a9b18f44a17d31493ef9ceb51d4d1237c00a..951b0e593c5407be37d0e356391c25256997750f 100644 --- a/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price/Collection.php +++ b/app/code/Magento/CatalogRule/Model/Resource/Rule/Product/Price/Collection.php @@ -9,6 +9,7 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac { /** * @return void + * @codeCoverageIgnore */ protected function _construct() { diff --git a/app/code/Magento/CatalogRule/Model/Rule.php b/app/code/Magento/CatalogRule/Model/Rule.php index 84bfce2b0c8337189bcc4120e6a1b665b21dbb2c..1bdab229ba82a6d2b5aad2bbc72bf17fc46fa6ed 100644 --- a/app/code/Magento/CatalogRule/Model/Rule.php +++ b/app/code/Magento/CatalogRule/Model/Rule.php @@ -270,6 +270,7 @@ class Rule extends \Magento\Rule\Model\AbstractModel * * @param string $now * @return void + * @codeCoverageIgnore */ public function setNow($now) { @@ -425,6 +426,7 @@ class Rule extends \Magento\Rule\Model\AbstractModel * * @param int|array $productIds * @return void + * @codeCoverageIgnore */ public function setProductsFilter($productIds) { @@ -435,6 +437,7 @@ class Rule extends \Magento\Rule\Model\AbstractModel * Returns products filter * * @return array|int|null + * @codeCoverageIgnore */ public function getProductsFilter() { diff --git a/app/code/Magento/Checkout/Api/Data/PaymentDetailsInterface.php b/app/code/Magento/Checkout/Api/Data/PaymentDetailsInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..ea68c7aa5d85f7b00d7d3c96431c509e8b30388f --- /dev/null +++ b/app/code/Magento/Checkout/Api/Data/PaymentDetailsInterface.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Api\Data; + +interface PaymentDetailsInterface +{ + /**#@+ + * Constants defined for keys of array, makes typos less likely + */ + const PAYMENT_METHODS = 'payment_methods'; + + const TOTALS = 'totals'; + + /**#@-*/ + + /** + * @return \Magento\Quote\Api\Data\PaymentMethodInterface[] + */ + public function getPaymentMethods(); + + /** + * @param \Magento\Quote\Api\Data\PaymentMethodInterface[] $paymentMethods + * @return $this + */ + public function setPaymentMethods($paymentMethods); + + /** + * @return \Magento\Quote\Api\Data\TotalsInterface + */ + public function getTotals(); + + /** + * @param \Magento\Quote\Api\Data\TotalsInterface $totals + * @return $this + */ + public function setTotals($totals); + + /** + * Retrieve existing extension attributes object or create a new one. + * + * @return \Magento\Checkout\Api\Data\PaymentDetailsExtensionInterface|null + */ + public function getExtensionAttributes(); + + /** + * Set an extension attributes object. + * + * @param \Magento\Checkout\Api\Data\PaymentDetailsExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\Checkout\Api\Data\PaymentDetailsExtensionInterface $extensionAttributes + ); +} diff --git a/app/code/Magento/Checkout/Api/Data/ShippingInformationInterface.php b/app/code/Magento/Checkout/Api/Data/ShippingInformationInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..9b2b3710eb3ae4b521e96712312a2f2718cc53e6 --- /dev/null +++ b/app/code/Magento/Checkout/Api/Data/ShippingInformationInterface.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Api\Data; + +interface ShippingInformationInterface extends \Magento\Framework\Api\CustomAttributesDataInterface +{ + /**#@+ + * Constants defined for keys of array, makes typos less likely + */ + const SHIPPING_ADDRESS = 'shipping_address'; + + const SHIPPING_METHOD_CODE = 'shipping_method_code'; + + const SHIPPING_CARRIER_CODE = 'shipping_carrier_code'; + + /**#@-*/ + + /** + * Returns shipping address + * + * @return \Magento\Quote\Api\Data\AddressInterface + */ + public function getShippingAddress(); + + /** + * Set shipping address + * + * @param \Magento\Quote\Api\Data\AddressInterface $address + * @return $this + */ + public function setShippingAddress(\Magento\Quote\Api\Data\AddressInterface $address); + + /** + * Returns shipping method code + * + * @return string + */ + public function getShippingMethodCode(); + + /** + * Set shipping method code + * + * @param string $code + * @return $this + */ + public function setShippingMethodCode($code); + + /** + * Returns carrier code + * + * @return string + */ + public function getShippingCarrierCode(); + + /** + * Set carrier code + * + * @param string $code + * @return $this + */ + public function setShippingCarrierCode($code); + + /** + * Retrieve existing extension attributes object or create a new one. + * + * @return \Magento\Checkout\Api\Data\ShippingInformationExtensionInterface|null + */ + public function getExtensionAttributes(); + + /** + * Set an extension attributes object. + * + * @param \Magento\Checkout\Api\Data\ShippingInformationExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\Checkout\Api\Data\ShippingInformationExtensionInterface $extensionAttributes + ); +} diff --git a/app/code/Magento/Checkout/Api/GuestPaymentInformationManagementInterface.php b/app/code/Magento/Checkout/Api/GuestPaymentInformationManagementInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..7a2b178aa6691c64a9e00618c30f8717006a0220 --- /dev/null +++ b/app/code/Magento/Checkout/Api/GuestPaymentInformationManagementInterface.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Api; + +interface GuestPaymentInformationManagementInterface +{ + /** + * Set payment information and place order for a specified cart. + * + * @param string $cartId + * @param string $email + * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod + * @param \Magento\Quote\Api\Data\AddressInterface $billingAddress + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @return int Order ID. + */ + public function savePaymentInformationAndPlaceOrder( + $cartId, + $email, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ); + + /** + * Set payment information for a specified cart. + * + * @param string $cartId + * @param string $email + * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod + * @param \Magento\Quote\Api\Data\AddressInterface $billingAddress + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @return int Order ID. + */ + public function savePaymentInformation( + $cartId, + $email, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ); +} diff --git a/app/code/Magento/Checkout/Api/GuestShippingInformationManagementInterface.php b/app/code/Magento/Checkout/Api/GuestShippingInformationManagementInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..c52ee4a7766b8b8dfa6e6b55b76a16a4d2e8a786 --- /dev/null +++ b/app/code/Magento/Checkout/Api/GuestShippingInformationManagementInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Api; + +interface GuestShippingInformationManagementInterface +{ + /** + * @param string $cartId + * @param \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation + * @return \Magento\Checkout\Api\Data\PaymentDetailsInterface + */ + public function saveAddressInformation( + $cartId, + \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation + ); +} diff --git a/app/code/Magento/Checkout/Api/PaymentInformationManagementInterface.php b/app/code/Magento/Checkout/Api/PaymentInformationManagementInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..bac301c7ab3695bc691aa74e5b9b764a366427a1 --- /dev/null +++ b/app/code/Magento/Checkout/Api/PaymentInformationManagementInterface.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Api; + +interface PaymentInformationManagementInterface +{ + /** + * Set payment information and place order for a specified cart. + * + * @param int $cartId + * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod + * @param \Magento\Quote\Api\Data\AddressInterface $billingAddress + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @return int Order ID. + */ + public function savePaymentInformationAndPlaceOrder( + $cartId, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ); + + /** + * Set payment information for a specified cart. + * + * @param int $cartId + * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod + * @param \Magento\Quote\Api\Data\AddressInterface $billingAddress + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @return int Order ID. + */ + public function savePaymentInformation( + $cartId, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ); +} diff --git a/app/code/Magento/Checkout/Api/ShippingInformationManagementInterface.php b/app/code/Magento/Checkout/Api/ShippingInformationManagementInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..4f39b764b35b9c3b7bbedbaf4914b7c6a732d77f --- /dev/null +++ b/app/code/Magento/Checkout/Api/ShippingInformationManagementInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Api; + +interface ShippingInformationManagementInterface +{ + /** + * @param int $cartId + * @param \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation + * @return \Magento\Checkout\Api\Data\PaymentDetailsInterface + */ + public function saveAddressInformation( + $cartId, + \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation + ); +} diff --git a/app/code/Magento/Checkout/Block/Cart/Sidebar.php b/app/code/Magento/Checkout/Block/Cart/Sidebar.php index 593f1bd35806d975c41fba9806a6586c538a2950..a754a3c6582c58f3a1dcd4ec8f90f234a2ffaeff 100644 --- a/app/code/Magento/Checkout/Block/Cart/Sidebar.php +++ b/app/code/Magento/Checkout/Block/Cart/Sidebar.php @@ -52,6 +52,25 @@ class Sidebar extends AbstractCart $this->imageView = $imageView; } + /** + * Returns minicart config + * + * @return array + */ + public function getConfig() + { + return [ + 'shoppingCartUrl' => $this->getShoppingCartUrl(), + 'checkoutUrl' => $this->getCheckoutUrl(), + 'updateItemQtyUrl' => $this->getUpdateItemQtyUrl(), + 'removeItemUrl' => $this->getRemoveItemUrl(), + 'imageTemplate' => $this->getImageHtmlTemplate(), + 'customerRegisterUrl' => $this->getCustomerRegisterUrlUrl(), + 'customerForgotPasswordUrl' => $this->getCustomerForgotPasswordUrl(), + 'baseUrl' => $this->getBaseUrl() + ]; + } + /** * @return string */ @@ -139,4 +158,34 @@ class Sidebar extends AbstractCart { return $this->getLayout()->getBlock('checkout.cart.minicart.totals')->toHtml(); } + + /** + * Get customer register url + * + * @return string + */ + public function getCustomerRegisterUrlUrl() + { + return $this->getUrl('customer/account/create'); + } + + /** + * Get customer forgot password url + * + * @return string + */ + public function getCustomerForgotPasswordUrl() + { + return $this->getUrl('customer/account/forgotpassword'); + } + + /** + * Return base url. + * + * @return string + */ + public function getBaseUrl() + { + return $this->_storeManager->getStore()->getBaseUrl(); + } } diff --git a/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php b/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php index 224079faff6ff237b82ffa3ddf482d83d486a62f..32609252f0552023241063773f18a2f61c82fe02 100644 --- a/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php +++ b/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php @@ -125,6 +125,9 @@ class AttributeMerger 'elementTmpl' => isset($additionalConfig['config']['elementTmpl']) ? $additionalConfig['config']['elementTmpl'] : $elementTemplate, + 'tooltip' => isset($additionalConfig['config']['tooltip']) + ? $additionalConfig['config']['tooltip'] + : null ], 'dataScope' => $dataScopePrefix . '.' . $attributeCode, 'label' => $attributeConfig['label'], @@ -141,7 +144,7 @@ class AttributeMerger $defaultValue = $this->getDefaultValue($attributeCode); if (null !== $defaultValue) { - $element['default'] = $defaultValue; + $element['value'] = $defaultValue; } return $element; } diff --git a/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php b/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php index 9f5ffc3f6ef6dca215aaa6c100d57d4b4009dc8b..20332513a009f078db5fc7cd3468894ccaaac593 100644 --- a/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php +++ b/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php @@ -60,26 +60,29 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso } // The following code is a workaround for custom address attributes - if (isset($jsLayout['components']['checkout']['children']['steps']['children']['billingAddress'] - ['children']['billing-address-fieldset']['children'] + if (isset($jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children'] + ['payment']['children'] )) { - $fields = $jsLayout['components']['checkout']['children']['steps']['children']['billingAddress'] - ['children']['billing-address-fieldset']['children']; - $jsLayout['components']['checkout']['children']['steps']['children']['billingAddress'] - ['children']['billing-address-fieldset']['children'] = $this->merger->merge( - $elements, - 'checkoutProvider', - 'billingAddress', - $fields - ); + $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children'] + ['payment']['children']['payments-list']['children'] = + array_merge_recursive( + $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children'] + ['payment']['children']['payments-list']['children'], + $this->processPaymentConfiguration( + $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children'] + ['payment']['children']['renders']['children'], + $elements + ) + ); } - if (isset($jsLayout['components']['checkout']['children']['steps']['children']['shippingAddress'] - ['children']['shipping-address-fieldset']['children'] + + if (isset($jsLayout['components']['checkout']['children']['steps']['children']['shipping-step'] + ['children']['shippingAddress']['children']['shipping-address-fieldset']['children'] )) { - $fields = $jsLayout['components']['checkout']['children']['steps']['children']['shippingAddress'] - ['children']['shipping-address-fieldset']['children']; - $jsLayout['components']['checkout']['children']['steps']['children']['shippingAddress'] - ['children']['shipping-address-fieldset']['children'] = $this->merger->merge( + $fields = $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step'] + ['children']['shippingAddress']['children']['shipping-address-fieldset']['children']; + $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step'] + ['children']['shippingAddress']['children']['shipping-address-fieldset']['children'] = $this->merger->merge( $elements, 'checkoutProvider', 'shippingAddress', @@ -88,4 +91,90 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso } return $jsLayout; } + + /** + * Inject billing address component into every payment component + * + * @param array $configuration list of payment components + * @param array $elements attributes that must be displayed in address form + * @return array + */ + private function processPaymentConfiguration(array &$configuration, array $elements) + { + $output = []; + foreach ($configuration as $paymentGroup => $groupConfig) { + foreach ($groupConfig['methods'] as $paymentCode => $paymentComponent) { + if (empty($paymentComponent['isBillingAddressRequired'])) { + continue; + } + $output[$paymentCode . '-form'] = [ + 'component' => 'Magento_Checkout/js/view/billing-address', + 'displayArea' => 'billing-address-form-' . $paymentCode, + 'provider' => 'checkoutProvider', + 'dataScopePrefix' => 'billingAddress' . $paymentCode, + 'sortOrder' => 1, + 'children' => [ + 'form-fields' => [ + 'component' => 'uiComponent', + 'displayArea' => 'additional-fieldsets', + 'children' => $this->merger->merge( + $elements, + 'checkoutProvider', + 'billingAddress' . $paymentCode, + [ + 'country_id' => [ + 'sortOrder' => 115, + ], + 'region' => [ + 'visible' => false, + ], + 'region_id' => [ + 'component' => 'Magento_Ui/js/form/element/region', + 'config' => [ + 'template' => 'ui/form/field', + 'elementTmpl' => 'ui/form/element/select', + 'customEntry' => 'billingAddress' . $paymentCode . '.region', + ], + 'validation' => [ + 'validate-select' => true, + ], + 'filterBy' => [ + 'target' => '${ $.provider }:${ $.parentScope }.country_id', + 'field' => 'country_id', + ], + ], + 'postcode' => [ + 'component' => 'Magento_Ui/js/form/element/post-code', + 'validation' => [ + 'required-entry' => true, + ], + ], + 'company' => [ + 'validation' => [ + 'min_text_length' => 0, + ], + ], + 'fax' => [ + 'validation' => [ + 'min_text_length' => 0, + ], + ], + 'telephone' => [ + 'config' => [ + 'tooltip' => [ + 'description' => 'For delivery Questions', + ], + ], + ], + ] + ), + ], + ], + ]; + } + unset($configuration[$paymentGroup]['methods']); + } + + return $output; + } } diff --git a/app/code/Magento/Checkout/Block/Checkout/TotalsProcessor.php b/app/code/Magento/Checkout/Block/Checkout/TotalsProcessor.php new file mode 100644 index 0000000000000000000000000000000000000000..af5a8a51dd456490a1e1f66329cb1f83f94cc088 --- /dev/null +++ b/app/code/Magento/Checkout/Block/Checkout/TotalsProcessor.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Block\Checkout; + +use Magento\Framework\App\Config\ScopeConfigInterface; + +class TotalsProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcessorInterface +{ + /** + * Core store config + * + * @var ScopeConfigInterface + */ + protected $scopeConfig; + + /** + * @param ScopeConfigInterface $scopeConfig + */ + public function __construct( + ScopeConfigInterface $scopeConfig + ) { + $this->scopeConfig = $scopeConfig; + } + + /** + * {@inheritdoc} + */ + public function process($jsLayout) + { + $configData = $this->scopeConfig->getValue('sales/totals_sort'); + $totals = $jsLayout['components']['checkout']['children']['summary']['children']['totals']['children']; + foreach ($totals as $code => &$total) { + //convert JS naming style to config naming style + $code = str_replace('-', '_', $code); + if (array_key_exists($code, $configData)) { + $total['sortOrder'] = $configData[$code]; + } + } + $jsLayout['components']['checkout']['children']['summary']['children']['totals']['children'] = $totals; + + return array_merge_recursive($jsLayout, $totals); + } +} diff --git a/app/code/Magento/Checkout/Block/Onepage/Success.php b/app/code/Magento/Checkout/Block/Onepage/Success.php index 3f128226841f42e6526add15cb828d448359c047..46f85df2019ef53debf6b5583bffb9c7c264e6b0 100644 --- a/app/code/Magento/Checkout/Block/Onepage/Success.php +++ b/app/code/Magento/Checkout/Block/Onepage/Success.php @@ -104,9 +104,10 @@ class Success extends \Magento\Framework\View\Element\Template { $orderId = $this->_checkoutSession->getLastOrderId(); if ($orderId) { - $order = $this->_orderFactory->create()->load($orderId); - if ($order->getId()) { - $isVisible = !in_array($order->getStatus(), $this->_orderConfig->getInvisibleOnFrontStatuses()); + $incrementId = $this->_checkoutSession->getLastRealOrderId(); + $status = $this->_checkoutSession->getLastOrderStatus(); + if ($status && $incrementId) { + $isVisible = !in_array($status, $this->_orderConfig->getInvisibleOnFrontStatuses()); $canView = $this->httpContext->getValue(Context::CONTEXT_AUTH) && $isVisible; $this->addData( [ @@ -115,7 +116,7 @@ class Success extends \Magento\Framework\View\Element\Template 'print_url' => $this->getUrl('sales/order/print', ['order_id' => $orderId]), 'can_print_order' => $isVisible, 'can_view_order' => $canView, - 'order_id' => $order->getIncrementId(), + 'order_id' => $incrementId, ] ); } diff --git a/app/code/Magento/Checkout/Controller/Onepage/Index.php b/app/code/Magento/Checkout/Controller/Onepage/Index.php index 991511fc02267a4d6a250fb78576b0feaa08ad14..7fa9fa794c5fb5ab4441324cc716e26bec15c987 100644 --- a/app/code/Magento/Checkout/Controller/Onepage/Index.php +++ b/app/code/Magento/Checkout/Controller/Onepage/Index.php @@ -15,11 +15,19 @@ class Index extends \Magento\Checkout\Controller\Onepage */ public function execute() { - if (!$this->_objectManager->get('Magento\Checkout\Helper\Data')->canOnepageCheckout()) { + $checkoutHelper = $this->_objectManager->get('Magento\Checkout\Helper\Data'); + if (!$checkoutHelper->canOnepageCheckout()) { $this->messageManager->addError(__('One-page checkout is turned off.')); return $this->resultRedirectFactory->create()->setPath('checkout/cart'); } + $quote = $this->getOnepage()->getQuote(); + + if (!$this->_customerSession->isLoggedIn() && !$checkoutHelper->isAllowedGuestCheckout($quote)) { + $this->messageManager->addError(__('Guest checkout is disabled.')); + return $this->resultRedirectFactory->create()->setPath('checkout/cart'); + } + if (!$quote->hasItems() || $quote->getHasError() || !$quote->validateMinimumAmount()) { return $this->resultRedirectFactory->create()->setPath('checkout/cart'); } diff --git a/app/code/Magento/Checkout/CustomerData/Cart.php b/app/code/Magento/Checkout/CustomerData/Cart.php index ae306dc9439a26fedb5282ced36980fd55476887..55fd454db8aeb8d42bb6674d6ad0336f9e45c1ff 100644 --- a/app/code/Magento/Checkout/CustomerData/Cart.php +++ b/app/code/Magento/Checkout/CustomerData/Cart.php @@ -94,6 +94,7 @@ class Cart extends \Magento\Framework\Object implements SectionSourceInterface 'possible_onepage_checkout' => $this->isPossibleOnepageCheckout(), 'items' => $this->getRecentItems(), 'extra_actions' => $this->layout->createBlock('Magento\Catalog\Block\ShortcutButtons')->toHtml(), + 'isGuestCheckoutAllowed' => $this->isGuestCheckoutAllowed(), ]; } @@ -173,4 +174,14 @@ class Cart extends \Magento\Framework\Object implements SectionSourceInterface } return $this->getQuote()->getAllVisibleItems(); } + + /** + * Check if guest checkout is allowed + * + * @return bool + */ + public function isGuestCheckoutAllowed() + { + return $this->checkoutHelper->isAllowedGuestCheckout($this->checkoutSession->getQuote()); + } } diff --git a/app/code/Magento/Checkout/Model/Cart/ImageProvider.php b/app/code/Magento/Checkout/Model/Cart/ImageProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..f49b267b88a8ea7441b817fdb5a9fe42fe13b187 --- /dev/null +++ b/app/code/Magento/Checkout/Model/Cart/ImageProvider.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Model\Cart; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ImageProvider +{ + /** + * @var \Magento\Quote\Api\CartItemRepositoryInterface + */ + protected $itemRepository; + + /** + * @var \Magento\Checkout\CustomerData\ItemPoolInterface + */ + protected $itemPool; + + /** + * @param \Magento\Quote\Api\CartItemRepositoryInterface $itemRepository + * @param \Magento\Checkout\CustomerData\ItemPoolInterface $itemPool + */ + public function __construct( + \Magento\Quote\Api\CartItemRepositoryInterface $itemRepository, + \Magento\Checkout\CustomerData\ItemPoolInterface $itemPool + ) { + $this->itemRepository = $itemRepository; + $this->itemPool = $itemPool; + } + + /** + * {@inheritdoc} + */ + public function getImages($cartId) + { + $itemData = []; + + /** @see code/Magento/Catalog/Helper/Product.php */ + $items = $this->itemRepository->getList($cartId); + /** @var \Magento\Quote\Model\Quote\Item $cartItem */ + foreach ($items as $cartItem) { + $allData = $this->itemPool->getItemData($cartItem); + $itemData[$cartItem->getItemId()] = $allData['product_image']; + } + return $itemData; + } +} diff --git a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php index 08de243b3a16294460af5e94807652592114ab90..21911aec850fcdc82c6163d2684fc10869fa8421 100644 --- a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php +++ b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php @@ -6,7 +6,6 @@ namespace Magento\Checkout\Model; use Magento\Checkout\Helper\Data as CheckoutHelper; -use Magento\Checkout\Model\Type\Onepage as OnepageCheckout; use Magento\Checkout\Model\Session as CheckoutSession; use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository; use Magento\Customer\Model\Context as CustomerContext; @@ -23,6 +22,9 @@ use Magento\Catalog\Helper\Product\ConfigurationPool; use Magento\Quote\Model\QuoteIdMaskFactory; use Magento\Framework\Locale\FormatInterface as LocaleFormat; use Magento\Framework\UrlInterface; +use Magento\Quote\Api\CartTotalRepositoryInterface; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Store\Model\ScopeInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -120,6 +122,53 @@ class DefaultConfigProvider implements ConfigProviderInterface */ protected $viewConfig; + /** + * @var \Magento\Directory\Model\Country\Postcode\ConfigInterface + */ + protected $postCodesConfig; + + /** + * @var \Magento\Directory\Helper\Data + */ + protected $directoryHelper; + + /** + * @var Cart\ImageProvider + */ + protected $imageProvider; + + /** + * @var CartTotalRepositoryInterface + */ + protected $cartTotalRepository; + + /** + * Shipping method data factory. + * + * @var \Magento\Quote\Api\Data\EstimateAddressInterfaceFactory + */ + protected $estimatedAddressFactory; + + /** + * @var ScopeConfigInterface + */ + protected $scopeConfig; + + /** + * @var \Magento\Shipping\Model\Config + */ + protected $shippingMethodConfig; + + /** + * @var \Magento\Store\Model\StoreManagerInterface + */ + protected $storeManager; + + /** + * @var \Magento\Quote\Api\PaymentMethodManagementInterface + */ + protected $paymentMethodManagement; + /** * @param CheckoutHelper $checkoutHelper * @param Session $checkoutSession @@ -139,6 +188,15 @@ class DefaultConfigProvider implements ConfigProviderInterface * @param FormKey $formKey * @param \Magento\Catalog\Helper\Image $imageHelper * @param \Magento\Framework\View\ConfigInterface $viewConfig + * @param \Magento\Directory\Model\Country\Postcode\ConfigInterface $postCodesConfig + * @param Cart\ImageProvider $imageProvider + * @param \Magento\Directory\Helper\Data $directoryHelper + * @param CartTotalRepositoryInterface $cartTotalRepository + * @param \Magento\Quote\Api\Data\EstimateAddressInterfaceFactory $estimatedAddressFactory + * @param ScopeConfigInterface $scopeConfig + * @param \Magento\Shipping\Model\Config $shippingMethodConfig + * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -159,7 +217,16 @@ class DefaultConfigProvider implements ConfigProviderInterface \Magento\Customer\Model\Address\Config $addressConfig, FormKey $formKey, \Magento\Catalog\Helper\Image $imageHelper, - \Magento\Framework\View\ConfigInterface $viewConfig + \Magento\Framework\View\ConfigInterface $viewConfig, + \Magento\Directory\Model\Country\Postcode\ConfigInterface $postCodesConfig, + Cart\ImageProvider $imageProvider, + \Magento\Directory\Helper\Data $directoryHelper, + CartTotalRepositoryInterface $cartTotalRepository, + \Magento\Quote\Api\Data\EstimateAddressInterfaceFactory $estimatedAddressFactory, + ScopeConfigInterface $scopeConfig, + \Magento\Shipping\Model\Config $shippingMethodConfig, + \Magento\Store\Model\StoreManagerInterface $storeManager, + \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement ) { $this->checkoutHelper = $checkoutHelper; $this->checkoutSession = $checkoutSession; @@ -179,6 +246,15 @@ class DefaultConfigProvider implements ConfigProviderInterface $this->formKey = $formKey; $this->imageHelper = $imageHelper; $this->viewConfig = $viewConfig; + $this->postCodesConfig = $postCodesConfig; + $this->imageProvider = $imageProvider; + $this->directoryHelper = $directoryHelper; + $this->cartTotalRepository = $cartTotalRepository; + $this->estimatedAddressFactory = $estimatedAddressFactory; + $this->scopeConfig = $scopeConfig; + $this->shippingMethodConfig = $shippingMethodConfig; + $this->storeManager = $storeManager; + $this->paymentMethodManagement = $paymentMethodManagement; } /** @@ -186,6 +262,7 @@ class DefaultConfigProvider implements ConfigProviderInterface */ public function getConfig() { + $quoteId = $this->checkoutSession->getQuote()->getId(); return [ 'formKey' => $this->formKey->getFormKey(), 'customerData' => $this->getCustomerData(), @@ -207,10 +284,72 @@ class DefaultConfigProvider implements ConfigProviderInterface 'basePriceFormat' => $this->localeFormat->getPriceFormat( null, $this->currencyManager->getDefaultCurrency() - ) + ), + 'postCodes' => $this->postCodesConfig->getPostCodes(), + 'imageData' => $this->imageProvider->getImages($quoteId), + 'countryData' => $this->getCountryData(), + 'totalsData' => $this->getTotalsData(), + 'shippingRates' => $this->getDefaultShippingRates(), + 'shippingPolicy' => [ + 'isEnabled' => $this->scopeConfig->isSetFlag( + 'shipping/shipping_policy/enable_shipping_policy', + ScopeInterface::SCOPE_STORE + ), + 'shippingPolicyContent' => nl2br( + $this->scopeConfig->getValue( + 'shipping/shipping_policy/shipping_policy_content', + ScopeInterface::SCOPE_STORE + ) + ) + ], + 'activeCarriers' => $this->getActiveCarriers(), + 'originCountryCode' => $this->getOriginCountryCode(), + 'paymentMethods' => $this->getPaymentMethods() ]; } + /** + * Get default shipping rates + * + * @return array + */ + private function getDefaultShippingRates() + { + $output = []; + $addressKey = null; + if ($this->checkoutSession->getQuote()->getId()) { + $quote = $this->quoteRepository->get($this->checkoutSession->getQuote()->getId()); + /** @var \Magento\Quote\Api\Data\EstimateAddressInterface $estimatedAddress */ + $estimatedAddress = $this->estimatedAddressFactory->create(); + + $address = $quote->getShippingAddress(); + if ($address && + ($address->getCountryId() + || $address->getPostcode() + || $address->getRegion() + || $address->getRegionId() + ) + ) { + $estimatedAddress->setCountryId($address->getCountryId()); + $estimatedAddress->setPostcode($address->getPostcode()); + $estimatedAddress->setRegion($address->getRegion()); + $estimatedAddress->setRegionId($address->getRegionId()); + } else { + $estimatedAddress->setCountryId($this->directoryHelper->getDefaultCountry()); + } + $rates = $this->shippingMethodManager->estimateByAddress($quote->getId(), $estimatedAddress); + foreach ($rates as $rate) { + $output[] = $rate->__toArray(); + } + + if ($address->getCustomerAddressId()) { + $addressKey = 'customer-address' . $address->getCustomerAddressId(); + } + }; + return ['key' => $addressKey, 'data' => $output]; + + } + /** * Retrieve customer data * @@ -270,13 +409,6 @@ class DefaultConfigProvider implements ConfigProviderInterface $quoteData = []; if ($this->checkoutSession->getQuote()->getId()) { $quote = $this->quoteRepository->get($this->checkoutSession->getQuote()->getId()); - // the following condition is a legacy logic left here for compatibility - if (!$quote->getCustomer()->getId()) { - $this->quoteRepository->save($this->checkoutSession->getQuote()->setCheckoutMethod('guest')); - } else { - $this->quoteRepository->save($this->checkoutSession->getQuote()->setCheckoutMethod(null)); - } - $quoteData = $quote->toArray(); $quoteData['is_virtual'] = $quote->getIsVirtual(); @@ -357,22 +489,21 @@ class DefaultConfigProvider implements ConfigProviderInterface /** * Retrieve selected shipping method * - * @return string + * @return array|null */ private function getSelectedShippingMethod() { - // Shipping method ID contains carrier code and shipping method code - $shippingMethodId = ''; + $shippingMethodData = null; try { $quoteId = $this->checkoutSession->getQuote()->getId(); $shippingMethod = $this->shippingMethodManager->get($quoteId); if ($shippingMethod) { - $shippingMethodId = $shippingMethod->getCarrierCode() . '_' . $shippingMethod->getMethodCode(); + $shippingMethodData = $shippingMethod->__toArray(); } } catch (\Exception $exception) { - $shippingMethodId = ''; + $shippingMethodData = null; } - return $shippingMethodId; + return $shippingMethodData; } /** @@ -434,4 +565,97 @@ class DefaultConfigProvider implements ConfigProviderInterface { return $this->checkoutSession->getQuote()->getStore()->getBaseUrl(UrlInterface::URL_TYPE_STATIC); } + + /** + * Return countries data + * @return array + */ + private function getCountryData() + { + $country = []; + $regionsData = $this->directoryHelper->getRegionData(); + foreach ($this->directoryHelper->getCountryCollection() as $code => $data) { + $country[$code]['name'] = $data->getName(); + if (array_key_exists($code, $regionsData)) { + foreach ($regionsData[$code] as $key => $region) { + $country[$code]['regions'][$key]['code'] = $region['code']; + $country[$code]['regions'][$key]['name'] = $region['name']; + } + } + + } + return $country; + } + + /** + * Return quote totals data + * @return array + */ + private function getTotalsData() + { + /** @var \Magento\Quote\Api\Data\TotalsInterface $totals */ + $totals = $this->cartTotalRepository->get($this->checkoutSession->getQuote()->getId()); + $items = []; + /** @var \Magento\Quote\Model\Cart\Totals\Item $item */ + foreach ($totals->getItems() as $item) { + $items[] = $item->__toArray(); + } + $totalSegmentsData = []; + /** @var \Magento\Quote\Model\Cart\TotalSegment $totalSegment */ + foreach ($totals->getTotalSegments() as $totalSegment) { + $totalSegmentsData[] = $totalSegment->toArray(); + } + $totals->setItems($items); + $totals->setTotalSegments($totalSegmentsData); + $totalsArray = $totals->toArray(); + if (is_object($totals->getExtensionAttributes())) { + $totalsArray['extension_attributes'] = $totals->getExtensionAttributes()->__toArray(); + } + return $totalsArray; + } + + /** + * Returns active carriers codes + * @return array + */ + private function getActiveCarriers() + { + $activeCarriers = []; + foreach ($this->shippingMethodConfig->getActiveCarriers() as $carrier) { + $activeCarriers[] = $carrier->getCarrierCode(); + } + return $activeCarriers; + } + + /** + * Returns origin country code + * @return string + */ + private function getOriginCountryCode() + { + return $this->scopeConfig->getValue( + \Magento\Shipping\Model\Config::XML_PATH_ORIGIN_COUNTRY_ID, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + $this->storeManager->getStore() + ); + } + + /** + * Returns array of payment methods + * @return array + */ + private function getPaymentMethods() + { + $paymentMethods = []; + $quote = $this->checkoutSession->getQuote(); + if ($quote->getIsVirtual()) { + foreach ($this->paymentMethodManagement->getList($quote->getId()) as $paymentMethod) { + $paymentMethods[] = [ + 'code' => $paymentMethod->getCode(), + 'title' => $paymentMethod->getTitle() + ]; + } + } + return $paymentMethods; + } } diff --git a/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php b/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php new file mode 100644 index 0000000000000000000000000000000000000000..75e2539835e50cad7c7ff97d185044196423bf5d --- /dev/null +++ b/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Model; + +class GuestPaymentInformationManagement implements \Magento\Checkout\Api\GuestPaymentInformationManagementInterface +{ + + /** + * @var \Magento\Quote\Api\GuestBillingAddressManagementInterface + */ + protected $billingAddressManagement; + + /** + * @var \Magento\Quote\Api\GuestPaymentMethodManagementInterface + */ + protected $paymentMethodManagement; + + /** + * @var \Magento\Quote\Api\GuestCartManagementInterface + */ + protected $cartManagement; + + /** + * @param \Magento\Quote\Api\GuestBillingAddressManagementInterface $billingAddressManagement + * @param \Magento\Quote\Api\GuestPaymentMethodManagementInterface $paymentMethodManagement + * @param \Magento\Quote\Api\GuestCartManagementInterface $cartManagement + */ + public function __construct( + \Magento\Quote\Api\GuestBillingAddressManagementInterface $billingAddressManagement, + \Magento\Quote\Api\GuestPaymentMethodManagementInterface $paymentMethodManagement, + \Magento\Quote\Api\GuestCartManagementInterface $cartManagement + ) { + $this->billingAddressManagement = $billingAddressManagement; + $this->paymentMethodManagement = $paymentMethodManagement; + $this->cartManagement = $cartManagement; + } + + /** + * {@inheritDoc} + */ + public function savePaymentInformationAndPlaceOrder( + $cartId, + $email, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ) { + $this->savePaymentInformation($cartId, $email, $paymentMethod, $billingAddress); + return $this->cartManagement->placeOrder($cartId); + } + + /** + * {@inheritDoc} + */ + public function savePaymentInformation( + $cartId, + $email, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ) { + $billingAddress->setEmail($email); + $this->billingAddressManagement->assign($cartId, $billingAddress); + $this->paymentMethodManagement->set($cartId, $paymentMethod); + return true; + } +} diff --git a/app/code/Magento/Checkout/Model/GuestShippingInformationManagement.php b/app/code/Magento/Checkout/Model/GuestShippingInformationManagement.php new file mode 100644 index 0000000000000000000000000000000000000000..475bc915bf90ce15e48972dcc03979a02abc3a55 --- /dev/null +++ b/app/code/Magento/Checkout/Model/GuestShippingInformationManagement.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Model; + +class GuestShippingInformationManagement implements \Magento\Checkout\Api\GuestShippingInformationManagementInterface +{ + /** + * @var \Magento\Quote\Model\QuoteIdMaskFactory + */ + protected $quoteIdMaskFactory; + + /** + * @var ShippingInformationManagement + */ + protected $shippingInformationManagement; + + /** + * @param \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory + * @param ShippingInformationManagement $shippingInformationManagement + */ + public function __construct( + \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory, + \Magento\Checkout\Model\ShippingInformationManagement $shippingInformationManagement + ) { + $this->quoteIdMaskFactory = $quoteIdMaskFactory; + $this->shippingInformationManagement = $shippingInformationManagement; + } + + /** + * {@inheritDoc} + */ + public function saveAddressInformation( + $cartId, + \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation + ) { + /** @var $quoteIdMask \Magento\Quote\Model\QuoteIdMask */ + $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); + return $this->shippingInformationManagement->saveAddressInformation( + $quoteIdMask->getQuoteId(), + $addressInformation + ); + } +} diff --git a/app/code/Magento/Checkout/Model/PaymentDetails.php b/app/code/Magento/Checkout/Model/PaymentDetails.php new file mode 100644 index 0000000000000000000000000000000000000000..add196487ae989ccc195e557ee3c6f5e3de7177e --- /dev/null +++ b/app/code/Magento/Checkout/Model/PaymentDetails.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Model; + +/** + * @codeCoverageIgnoreStart + */ +class PaymentDetails extends \Magento\Framework\Model\AbstractExtensibleModel implements + \Magento\Checkout\Api\Data\PaymentDetailsInterface +{ + /** + * @{inheritdoc} + */ + public function getPaymentMethods() + { + return $this->getData(self::PAYMENT_METHODS); + } + + /** + * @{inheritdoc} + */ + public function setPaymentMethods($paymentMethods) + { + return $this->setData(self::PAYMENT_METHODS, $paymentMethods); + } + + /** + * @{inheritdoc} + */ + public function getTotals() + { + return $this->getData(self::TOTALS); + } + + /** + * @{inheritdoc} + */ + public function setTotals($totals) + { + return $this->setData(self::TOTALS, $totals); + } + + /** + * {@inheritdoc} + * + * @return \Magento\Checkout\Api\Data\PaymentDetailsExtensionInterface|null + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + * + * @param \Magento\Checkout\Api\Data\PaymentDetailsExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\Checkout\Api\Data\PaymentDetailsExtensionInterface $extensionAttributes + ) { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php new file mode 100644 index 0000000000000000000000000000000000000000..ff4b973c6298e3b95265a2d121aa51bac501804f --- /dev/null +++ b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Model; + +class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInformationManagementInterface +{ + + /** + * @var \Magento\Quote\Api\BillingAddressManagementInterface + */ + protected $billingAddressManagement; + + /** + * @var \Magento\Quote\Api\PaymentMethodManagementInterface + */ + protected $paymentMethodManagement; + + /** + * @var \Magento\Quote\Api\CartManagementInterface + */ + protected $cartManagement; + + /** + * @param \Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement + * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement + * @param \Magento\Quote\Api\CartManagementInterface $cartManagement + */ + public function __construct( + \Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement, + \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement, + \Magento\Quote\Api\CartManagementInterface $cartManagement + ) { + $this->billingAddressManagement = $billingAddressManagement; + $this->paymentMethodManagement = $paymentMethodManagement; + $this->cartManagement = $cartManagement; + } + + /** + * {@inheritDoc} + */ + public function savePaymentInformationAndPlaceOrder( + $cartId, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ) { + $this->savePaymentInformation($cartId, $paymentMethod, $billingAddress); + return $this->cartManagement->placeOrder($cartId); + } + + /** + * {@inheritDoc} + */ + public function savePaymentInformation( + $cartId, + \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, + \Magento\Quote\Api\Data\AddressInterface $billingAddress + ) { + $this->billingAddressManagement->assign($cartId, $billingAddress); + $this->paymentMethodManagement->set($cartId, $paymentMethod); + return true; + } +} diff --git a/app/code/Magento/Checkout/Model/ShippingInformation.php b/app/code/Magento/Checkout/Model/ShippingInformation.php new file mode 100644 index 0000000000000000000000000000000000000000..44d024c7171f587514efb03446cd2480f6b29364 --- /dev/null +++ b/app/code/Magento/Checkout/Model/ShippingInformation.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Model; + +use Magento\Framework\Model\AbstractExtensibleModel; +use Magento\Checkout\Api\Data\ShippingInformationInterface; + +/** + * @codeCoverageIgnoreStart + */ +class ShippingInformation extends AbstractExtensibleModel implements ShippingInformationInterface +{ + /** + * {@inheritdoc} + */ + public function getShippingAddress() + { + return $this->getData(self::SHIPPING_ADDRESS); + } + + /** + * {@inheritdoc} + */ + public function setShippingAddress(\Magento\Quote\Api\Data\AddressInterface $address) + { + return $this->setData(self::SHIPPING_ADDRESS, $address); + } + + /** + * {@inheritdoc} + */ + public function getShippingMethodCode() + { + return $this->getData(self::SHIPPING_METHOD_CODE); + } + + /** + * {@inheritdoc} + */ + public function setShippingMethodCode($code) + { + return $this->setData(self::SHIPPING_METHOD_CODE, $code); + } + + /** + * {@inheritdoc} + */ + public function getShippingCarrierCode() + { + return $this->getData(self::SHIPPING_CARRIER_CODE); + } + + /** + * {@inheritdoc} + */ + public function setShippingCarrierCode($code) + { + return $this->setData(self::SHIPPING_CARRIER_CODE, $code); + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes( + \Magento\Checkout\Api\Data\ShippingInformationExtensionInterface $extensionAttributes + ) { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Checkout/Model/ShippingInformationManagement.php b/app/code/Magento/Checkout/Model/ShippingInformationManagement.php new file mode 100644 index 0000000000000000000000000000000000000000..4cf21372af8943caf46bafa3812898e5715c57d0 --- /dev/null +++ b/app/code/Magento/Checkout/Model/ShippingInformationManagement.php @@ -0,0 +1,178 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Model; + +use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\StateException; +use Magento\Framework\Exception\NoSuchEntityException; +use Psr\Log\LoggerInterface as Logger; +use \Magento\Quote\Model\QuoteAddressValidator; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ShippingInformationManagement implements \Magento\Checkout\Api\ShippingInformationManagementInterface +{ + /** + * @var \Magento\Quote\Api\PaymentMethodManagementInterface + */ + protected $paymentMethodManagement; + + /** + * @var PaymentDetailsFactory + */ + protected $paymentDetailsFactory; + + /** + * @var \Magento\Quote\Api\CartTotalRepositoryInterface + */ + protected $cartTotalsRepository; + + /** + * Quote repository. + * + * @var \Magento\Quote\Model\QuoteRepository + */ + protected $quoteRepository; + + /** + * Logger. + * + * @var Logger + */ + protected $logger; + + /** + * Validator. + * + * @var QuoteAddressValidator + */ + protected $addressValidator; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + protected $addressRepository; + + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface + */ + protected $scopeConfig; + + /** + * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement + * @param \Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory + * @param \Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository + * @param \Magento\Quote\Model\QuoteRepository $quoteRepository + * @param \Magento\Quote\Model\QuoteAddressValidator $addressValidator + * @param Logger $logger + * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + */ + public function __construct( + \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement, + \Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory, + \Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository, + \Magento\Quote\Model\QuoteRepository $quoteRepository, + QuoteAddressValidator $addressValidator, + Logger $logger, + \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + ) { + $this->paymentMethodManagement = $paymentMethodManagement; + $this->paymentDetailsFactory = $paymentDetailsFactory; + $this->cartTotalsRepository = $cartTotalsRepository; + $this->quoteRepository = $quoteRepository; + $this->addressValidator = $addressValidator; + $this->logger = $logger; + $this->addressRepository = $addressRepository; + $this->scopeConfig = $scopeConfig; + } + + /** + * {@inheritDoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function saveAddressInformation( + $cartId, + \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation + ) { + $address = $addressInformation->getShippingAddress(); + $carrierCode = $addressInformation->getShippingCarrierCode(); + $methodCode = $addressInformation->getShippingMethodCode(); + + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $this->quoteRepository->getActive($cartId); + if ($quote->isVirtual()) { + throw new NoSuchEntityException( + __('Cart contains virtual product(s) only. Shipping address is not applicable.') + ); + } + + if (0 == $quote->getItemsCount()) { + throw new InputException(__('Shipping method is not applicable for empty cart')); + } + + $saveInAddressBook = $address->getSaveInAddressBook() ? 1 : 0; + $sameAsBilling = $address->getSameAsBilling() ? 1 : 0; + $customerAddressId = $address->getCustomerAddressId(); + $this->addressValidator->validate($address); + $quote->setShippingAddress($address); + $address = $quote->getShippingAddress(); + + if ($customerAddressId) { + $addressData = $this->addressRepository->getById($customerAddressId); + $address = $quote->getShippingAddress()->importCustomerAddressData($addressData); + } + $address->setSameAsBilling($sameAsBilling); + $address->setSaveInAddressBook($saveInAddressBook); + $address->setCollectShippingRates(true); + + if (!$address->getCountryId()) { + throw new StateException(__('Shipping address is not set')); + } + + $address->setShippingMethod($carrierCode . '_' . $methodCode); + + try { + $address->save(); + $address->collectTotals(); + } catch (\Exception $e) { + $this->logger->critical($e); + throw new InputException(__('Unable to save address. Please, check input data.')); + } + + if (!$address->getShippingRateByCode($address->getShippingMethod())) { + throw new NoSuchEntityException( + __('Carrier with such method not found: %1, %2', $carrierCode, $methodCode) + ); + } + + if (!$quote->validateMinimumAmount($quote->getIsMultiShipping())) { + throw new InputException($this->scopeConfig->getValue( + 'sales/minimum_order/error_message', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + $quote->getStoreId() + )); + } + + try { + $address->save(); + $quote->collectTotals(); + $this->quoteRepository->save($quote); + } catch (\Exception $e) { + $this->logger->critical($e); + throw new InputException(__('Unable to save shipping information. Please, check input data.')); + } + + /** @var \Magento\Checkout\Api\Data\PaymentDetailsInterface $paymentDetails */ + $paymentDetails = $this->paymentDetailsFactory->create(); + $paymentDetails->setPaymentMethods($this->paymentMethodManagement->getList($cartId)); + $paymentDetails->setTotals($this->cartTotalsRepository->get($cartId)); + return $paymentDetails; + } +} diff --git a/app/code/Magento/Checkout/Model/Type/Onepage.php b/app/code/Magento/Checkout/Model/Type/Onepage.php index dae0433f518ad6d159a555a88a883ec78dc516cf..2f7b71dc698be94e4bb8a17ef81815e8611381d7 100644 --- a/app/code/Magento/Checkout/Model/Type/Onepage.php +++ b/app/code/Magento/Checkout/Model/Type/Onepage.php @@ -983,14 +983,18 @@ class Onepage $redirectUrl )->setLastRealOrderId( $order->getIncrementId() + )->setLastOrderStatus( + $order->getStatus() ); } $this->_eventManager->dispatch( 'checkout_submit_all_after', - ['order' => $order, 'quote' => $this->getQuote()] + [ + 'order' => $order, + 'quote' => $this->getQuote() + ] ); - return $this; } diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php index 919a4de1157f216db27acd8aa1b6f25520c3f956..54c8fee91f2c411fd470716906dc89087d403914 100644 --- a/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php @@ -21,11 +21,6 @@ class SuccessTest extends \PHPUnit_Framework_TestCase */ protected $orderConfig; - /** - * @var \Magento\Sales\Model\OrderFactory | \PHPUnit_Framework_MockObject_MockObject - */ - protected $orderFactory; - /** * @var \Magento\Checkout\Model\Session | \PHPUnit_Framework_MockObject_MockObject */ @@ -36,14 +31,19 @@ class SuccessTest extends \PHPUnit_Framework_TestCase $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->orderConfig = $this->getMock('Magento\Sales\Model\Order\Config', [], [], '', false); - $this->orderFactory = $this->getMock('Magento\Sales\Model\OrderFactory', ['create'], [], '', false); - $this->checkoutSession = $this->getMock('Magento\Checkout\Model\Session', ['getLastOrderId'], [], '', false); + + $this->checkoutSession = $this->getMock( + 'Magento\Checkout\Model\Session', + ['getLastOrderId', 'getLastRealOrderId', 'getLastOrderStatus'], + [], + '', + false + ); $this->block = $objectManager->getObject( 'Magento\Checkout\Block\Onepage\Success', [ 'orderConfig' => $this->orderConfig, - 'orderFactory' => $this->orderFactory, 'checkoutSession' => $this->checkoutSession ] ); @@ -74,28 +74,21 @@ class SuccessTest extends \PHPUnit_Framework_TestCase public function testToHtmlOrderVisibleOnFront(array $invisibleStatuses, $orderStatus, $expectedResult) { $orderId = 5; - $order = $this->getMock('Magento\Sales\Model\Order', ['getId', '__wakeup', 'load', 'getStatus'], [], '', false); - - $order->expects($this->any()) - ->method('load') - ->with($orderId) - ->will($this->returnValue($order)); - $order->expects($this->any()) - ->method('getId') - ->will($this->returnValue($orderId)); - $order->expects($this->any()) - ->method('getStatus') - ->will($this->returnValue($orderStatus)); + $realOrderId = 100003332; $this->checkoutSession->expects($this->once()) ->method('getLastOrderId') ->will($this->returnValue($orderId)); + $this->checkoutSession->expects($this->once()) + ->method('getLastRealOrderId') + ->will($this->returnValue($realOrderId)); + $this->checkoutSession->expects($this->once()) + ->method('getLastOrderStatus') + ->will($this->returnValue($orderStatus)); + $this->orderConfig->expects($this->any()) ->method('getInvisibleOnFrontStatuses') ->will($this->returnValue($invisibleStatuses)); - $this->orderFactory->expects($this->once()) - ->method('create') - ->will($this->returnValue($order)); $this->block->toHtml(); diff --git a/app/code/Magento/Checkout/Test/Unit/Controller/Onepage/IndexTest.php b/app/code/Magento/Checkout/Test/Unit/Controller/Onepage/IndexTest.php index f3a3f246ec1ee9acff0150dd74735d03a4be9dc5..5159d70026cbc5c902e6adc3c3b80d21e22ea64e 100644 --- a/app/code/Magento/Checkout/Test/Unit/Controller/Onepage/IndexTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Controller/Onepage/IndexTest.php @@ -188,6 +188,7 @@ class IndexTest extends \PHPUnit_Framework_TestCase $this->basicStub($this->quoteMock, 'hasItems')->willReturn(true); $this->basicStub($this->quoteMock, 'getHasError')->willReturn(false); $this->basicStub($this->quoteMock, 'validateMinimumAmount')->willReturn(true); + $this->basicStub($this->sessionMock, 'isLoggedIn')->willReturn(true); //Expected outcomes $this->sessionMock->expects($this->once())->method('regenerateId'); diff --git a/app/code/Magento/Checkout/Test/Unit/Model/Cart/ImageProviderTest.php b/app/code/Magento/Checkout/Test/Unit/Model/Cart/ImageProviderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..29b91231adb10d532df997da73c74117859b5098 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Unit/Model/Cart/ImageProviderTest.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Test\Unit\Model\Cart; + +class ImageProviderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Checkout\Model\Cart\ImageProvider + */ + public $model; + + /** + * @var \PHPUnit_Framework_Mockobject_Mockobject | \Magento\Quote\Api\CartItemRepositoryInterface + */ + protected $itemRepositoryMock; + + /** + * @var \PHPUnit_Framework_Mockobject_Mockobject | \Magento\Checkout\CustomerData\ItemPoolInterface + */ + protected $itemPoolMock; + + protected function setUp() + { + $this->itemRepositoryMock = $this->getMock('Magento\Quote\Api\CartItemRepositoryInterface', [], [], '', false); + $this->itemPoolMock = $this->getMock('Magento\Checkout\CustomerData\ItemPoolInterface', [], [], '', false); + $this->model = new \Magento\Checkout\Model\Cart\ImageProvider( + $this->itemRepositoryMock, + $this->itemPoolMock + ); + } + + public function testGetImages() + { + $cartId = 42; + $itemId = 74; + $itemData = ['product_image' => 'Magento.png', 'random' => '3.1415926535']; + $itemMock = $this->getMock('Magento\Quote\Model\Quote\Item', [], [], '', false); + $itemMock->expects($this->once())->method('getItemId')->willReturn($itemId); + + $expectedResult = [$itemId => $itemData['product_image']]; + + $this->itemRepositoryMock->expects($this->once())->method('getList')->with($cartId)->willReturn([$itemMock]); + $this->itemPoolMock->expects($this->once())->method('getItemData')->with($itemMock)->willReturn($itemData); + + $this->assertEquals($expectedResult, $this->model->getImages($cartId)); + } +} diff --git a/app/code/Magento/Checkout/etc/di.xml b/app/code/Magento/Checkout/etc/di.xml index 42d589f77e2dc1d49c5bcfdb09b5f65c3fd331f3..085ff442d7f75790df42f626a68a4cc886154fb4 100644 --- a/app/code/Magento/Checkout/etc/di.xml +++ b/app/code/Magento/Checkout/etc/di.xml @@ -16,4 +16,10 @@ <argument name="storage" xsi:type="object">Magento\Checkout\Model\Session\Storage</argument> </arguments> </type> + <preference for="Magento\Checkout\Api\GuestShippingInformationManagementInterface" type="Magento\Checkout\Model\GuestShippingInformationManagement" /> + <preference for="Magento\Checkout\Api\ShippingInformationManagementInterface" type="Magento\Checkout\Model\ShippingInformationManagement" /> + <preference for="Magento\Checkout\Api\Data\ShippingInformationInterface" type="Magento\Checkout\Model\ShippingInformation" /> + <preference for="Magento\Checkout\Api\Data\PaymentDetailsInterface" type="Magento\Checkout\Model\PaymentDetails" /> + <preference for="Magento\Checkout\Api\GuestPaymentInformationManagementInterface" type="Magento\Checkout\Model\GuestPaymentInformationManagement" /> + <preference for="Magento\Checkout\Api\PaymentInformationManagementInterface" type="Magento\Checkout\Model\PaymentInformationManagement" /> </config> diff --git a/app/code/Magento/Checkout/etc/frontend/di.xml b/app/code/Magento/Checkout/etc/frontend/di.xml index 3399782763bea132a2c807f956f6323ce84016c7..20f146cc353ce63add45e00f3fc083c28cdb2768 100644 --- a/app/code/Magento/Checkout/etc/frontend/di.xml +++ b/app/code/Magento/Checkout/etc/frontend/di.xml @@ -43,6 +43,7 @@ <arguments> <argument name="layoutProcessors" xsi:type="array"> <item name="addressFormAttributes" xsi:type="object">Magento\Checkout\Block\Checkout\LayoutProcessor</item> + <item name="totalsSortOrder" xsi:type="object">Magento\Checkout\Block\Checkout\TotalsProcessor</item> </argument> </arguments> </type> diff --git a/app/code/Magento/Checkout/etc/webapi.xml b/app/code/Magento/Checkout/etc/webapi.xml new file mode 100644 index 0000000000000000000000000000000000000000..28598faec5913a1a3d30af16084b9a2ac0d64bf0 --- /dev/null +++ b/app/code/Magento/Checkout/etc/webapi.xml @@ -0,0 +1,64 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../app/code/Magento/Webapi/etc/webapi.xsd"> + + <!-- Managing shipping guest information --> + <route url="/V1/carts/:cartId/shipping-information" method="POST"> + <service class="Magento\Checkout\Api\GuestShippingInformationManagementInterface" method="saveAddressInformation"/> + <resources> + <resource ref="anonymous" /> + </resources> + </route> + + <!-- Managing My shipping information --> + <route url="/V1/carts/mine/shipping-information" method="POST"> + <service class="Magento\Checkout\Api\ShippingInformationManagementInterface" method="saveAddressInformation"/> + <resources> + <resource ref="self" /> + </resources> + <data> + <parameter name="cartId" force="true">%cart_id%</parameter> + </data> + </route> + <!-- Guest place order with payment information saving --> + <route url="/V1/guest-carts/:cartId/payment-information" method="POST"> + <service class="Magento\Checkout\Api\GuestPaymentInformationManagementInterface" method="savePaymentInformationAndPlaceOrder"/> + <resources> + <resource ref="anonymous" /> + </resources> + </route> + <!-- My place order with payment information saving --> + <route url="/V1/carts/mine/payment-information" method="POST"> + <service class="Magento\Checkout\Api\PaymentInformationManagementInterface" method="savePaymentInformationAndPlaceOrder"/> + <resources> + <resource ref="self" /> + </resources> + <data> + <parameter name="cartId" force="true">%cart_id%</parameter> + </data> + </route> + + <!-- Managing payment guest information --> + <route url="/V1/guest-carts/:cartId/set-payment-information" method="POST"> + <service class="Magento\Checkout\Api\GuestPaymentInformationManagementInterface" method="savePaymentInformation"/> + <resources> + <resource ref="anonymous" /> + </resources> + </route> + <!-- Managing My shipping information --> + <route url="/V1/carts/mine/set-payment-information" method="POST"> + <service class="Magento\Checkout\Api\PaymentInformationManagementInterface" method="savePaymentInformation"/> + <resources> + <resource ref="self" /> + </resources> + <data> + <parameter name="cartId" force="true">%cart_id%</parameter> + </data> + </route> +</routes> diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_onepage_index.xml index 5db66984f7812e8bd62978befb585a2eaa8434f9..a40e65477410eef2cfebf8e9c39203ed88070605 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_onepage_index.xml @@ -23,155 +23,233 @@ </item> <item name="components" xsi:type="array"> <item name="checkout" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/onepage</item> + <item name="component" xsi:type="string">uiComponent</item> + <item name="config" xsi:type="array"> + <item name="template" xsi:type="string">Magento_Checkout/onepage</item> + </item> <item name="children" xsi:type="array"> - <item name="progress" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/progress</item> - <item name="displayArea" xsi:type="string">progress</item> + <item name="errors" xsi:type="array"> + <item name="sortOrder" xsi:type="string">0</item> + <item name="component" xsi:type="string">Magento_Ui/js/view/messages</item> + <item name="displayArea" xsi:type="string">messages</item> + </item> + <item name="authentication" xsi:type="array"> + <item name="sortOrder" xsi:type="string">1</item> + <item name="component" xsi:type="string">Magento_Checkout/js/view/authentication</item> + <item name="displayArea" xsi:type="string">authentication</item> <item name="children" xsi:type="array"> - <item name="shipping" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/shipping_method/price</item> - <item name="displayArea" xsi:type="string">shipping</item> - </item> + <!--Additional authentication fields--> </item> </item> - <item name="errors" xsi:type="array"> + <item name="progressBar" xsi:type="array"> <item name="sortOrder" xsi:type="string">0</item> - <item name="component" xsi:type="string">Magento_Ui/js/view/errors</item> - <item name="displayArea" xsi:type="string">errors</item> + <item name="component" xsi:type="string">Magento_Checkout/js/view/progress-bar</item> + <item name="displayArea" xsi:type="string">progressBar</item> </item> <item name="steps" xsi:type="array"> <item name="component" xsi:type="string">uiComponent</item> <item name="displayArea" xsi:type="string">steps</item> <item name="children" xsi:type="array"> - <item name="authentication" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/authentication</item> + <item name="shipping-step" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> <item name="sortOrder" xsi:type="string">1</item> <item name="children" xsi:type="array"> - <item name="before" xsi:type="array"> + <item name="step-config" xsi:type="array"> <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">before</item> <item name="children" xsi:type="array"> - <!-- merge additional data before authentication here --> + <item name="shipping-rates-validation" xsi:type="array"> + <item name="children" xsi:type="array"> + <!--Step configuration components--> + </item> + </item> </item> </item> - </item> - </item> - <item name="billingAddress" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/billing-address</item> - <item name="provider" xsi:type="string">checkoutProvider</item> - <item name="sortOrder" xsi:type="string">2</item> - <item name="children" xsi:type="array"> - <item name="billing-address-fieldset" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">additional-fieldsets</item> - <item name="children" xsi:type="array"> - <!-- The following items override configuration of corresponding address attributes --> - <item name="region" xsi:type="array"> - <!-- Make region attribute invisible on frontend. Corresponding input element is created by region_id field --> - <item name="visible" xsi:type="boolean">false</item> - </item> - <item name="region_id" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Ui/js/form/element/region</item> - <item name="config" xsi:type="array"> - <item name="template" xsi:type="string">ui/form/field</item> - <item name="elementTmpl" xsi:type="string">ui/form/element/select</item> - <item name="customEntry" xsi:type="string">billingAddress.region</item> - </item> - <item name="validation" xsi:type="array"> - <item name="validate-select" xsi:type="string">true</item> - </item> - <!-- Value of region_id field is filtered by the value of county_id attribute --> - <item name="filterBy" xsi:type="array"> - <item name="target" xsi:type="string">${ $.provider }:${ $.parentScope }.country_id</item> - <item name="field" xsi:type="string">country_id</item> + <item name="shippingAddress" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="deps" xsi:type="string">checkout.steps.shipping-step.step-config</item> + <item name="popUpForm" xsi:type="array"> + <item name="element" xsi:type="string">#opc-new-shipping-address</item> + <item name="options" xsi:type="array"> + <item name="type" xsi:type="string">popup</item> + <item name="responsive" xsi:type="boolean">true</item> + <item name="innerScroll" xsi:type="boolean">true</item> + <item name="title" xsi:type="string">Shipping Address</item> + <item name="trigger" xsi:type="string">opc-new-shipping-address</item> + <item name="buttons" xsi:type="array"> + <item name="save" xsi:type="array"> + <item name="text" xsi:type="string">Save Address</item> + <item name="class" xsi:type="string">action primary action-save-address</item> + </item> + <item name="cancel" xsi:type="array"> + <item name="text" xsi:type="string">Cancel</item> + <item name="class" xsi:type="string">action secondary action-hide-popup</item> + </item> + </item> </item> </item> - <item name="postcode" xsi:type="array"> - <!-- post-code field has custom UI component --> - <item name="component" xsi:type="string">Magento_Ui/js/form/element/post-code</item> - <item name="validation" xsi:type="array"> - <item name="required-entry" xsi:type="string">true</item> + </item> + <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping</item> + <item name="provider" xsi:type="string">checkoutProvider</item> + <item name="sortOrder" xsi:type="string">1</item> + <item name="children" xsi:type="array"> + <item name="customer-email" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Customer/js/view/customer-email</item> + <item name="displayArea" xsi:type="string">customer-email</item> + <item name="tooltip" xsi:type="array"> + <item name="description" xsi:type="string">We'll send your order confirmation here.</item> + </item> + <item name="children" xsi:type="array"> + <item name="before-login-form" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">before-login-form</item> + <item name="children" xsi:type="array"> + <!-- before login form fields --> + </item> + </item> + <item name="additional-login-form-fields" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">additional-login-form-fields</item> + <item name="children" xsi:type="array"> + <!-- additional login form fields --> + </item> + </item> </item> </item> - <item name="company" xsi:type="array"> - <item name="validation" xsi:type="array"> - <item name="min_text_length" xsi:type="number">0</item> + <item name="before-form" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">before-form</item> + <item name="children" xsi:type="array"> + <!-- before form fields --> </item> </item> - <item name="fax" xsi:type="array"> - <item name="validation" xsi:type="array"> - <item name="min_text_length" xsi:type="number">0</item> + <item name="before-fields" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">before-fields</item> + <item name="children" xsi:type="array"> + <!-- before fields --> </item> </item> - <item name="country_id" xsi:type="array"> - <item name="sortOrder" xsi:type="string">115</item> + <item name="address-list" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-address/list</item> + <item name="displayArea" xsi:type="string">address-list</item> </item> - <!-- The following items describe fields that are not directly related to address but must be shown in address form --> - <item name="email" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Ui/js/form/element/abstract</item> - <item name="config" xsi:type="array"> - <item name="template" xsi:type="string">ui/form/field</item> - <item name="elementTmpl" xsi:type="string">ui/form/element/email</item> - <item name="customScope" xsi:type="string">customerDetails</item> + <item name="address-list-additional-addresses" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">address-list-additional-addresses</item> + <item name="children" xsi:type="array"> + <!-- address-list-additional-addresses --> </item> - <item name="label" xsi:type="string">Email</item> - <item name="dataScope" xsi:type="string">customerDetails.email</item> - <item name="provider" xsi:type="string">checkoutProvider</item> - <item name="sortOrder" xsi:type="string">45</item> - <item name="validation" xsi:type="array"> - <item name="required-entry" xsi:type="boolean">true</item> - <item name="validate-email" xsi:type="boolean">true</item> + </item> + <item name="before-shipping-method-form" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">before-shipping-method-form</item> + <item name="children" xsi:type="array"> + <!-- address-list-additional-addresses --> </item> </item> - <item name="save_in_address_book" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Ui/js/form/element/abstract</item> - <item name="config" xsi:type="array"> - <item name="template" xsi:type="string">ui/form/field</item> - <item name="elementTmpl" xsi:type="string">ui/form/element/checkbox</item> + <item name="shipping-address-fieldset" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">additional-fieldsets</item> + <item name="children" xsi:type="array"> + <!-- The following items override configuration of corresponding address attributes --> + <item name="region" xsi:type="array"> + <!-- Make region attribute invisible on frontend. Corresponding input element is created by region_id field --> + <item name="visible" xsi:type="boolean">false</item> + </item> + <item name="region_id" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Ui/js/form/element/region</item> + <item name="config" xsi:type="array"> + <item name="template" xsi:type="string">ui/form/field</item> + <item name="elementTmpl" xsi:type="string">ui/form/element/select</item> + <item name="customEntry" xsi:type="string">shippingAddress.region</item> + </item> + <item name="validation" xsi:type="array"> + <item name="validate-select" xsi:type="string">true</item> + </item> + <!-- Value of region_id field is filtered by the value of county_id attribute --> + <item name="filterBy" xsi:type="array"> + <item name="target" xsi:type="string"><![CDATA[${ $.provider }:${ $.parentScope }.country_id]]></item> + <item name="field" xsi:type="string">country_id</item> + </item> + </item> + <item name="postcode" xsi:type="array"> + <!-- post-code field has custom UI component --> + <item name="component" xsi:type="string">Magento_Ui/js/form/element/post-code</item> + <item name="validation" xsi:type="array"> + <item name="required-entry" xsi:type="string">true</item> + </item> + </item> + <item name="company" xsi:type="array"> + <item name="validation" xsi:type="array"> + <item name="min_text_length" xsi:type="number">0</item> + </item> + </item> + <item name="fax" xsi:type="array"> + <item name="validation" xsi:type="array"> + <item name="min_text_length" xsi:type="number">0</item> + </item> + </item> + <item name="country_id" xsi:type="array"> + <item name="sortOrder" xsi:type="string">115</item> + </item> + <item name="telephone" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="tooltip" xsi:type="array"> + <item name="description" xsi:type="string">For delivery Questions</item> + </item> + </item> + </item> </item> - <item name="description" xsi:type="string">Save in address book</item> - <item name="provider" xsi:type="string">checkoutProvider</item> - <item name="dataScope" xsi:type="string">billingAddress.save_in_address_book</item> </item> </item> </item> - <item name="billing-address-choice" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">additional-field-choice</item> - <item name="children" xsi:type="array"> - <!-- this region for different choice --> - </item> - </item> </item> </item> - <item name="shippingAddress" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-address</item> - <item name="provider" xsi:type="string">checkoutProvider</item> - <item name="sortOrder" xsi:type="string">3</item> + <item name="billing-step" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="sortOrder" xsi:type="string">2</item> <item name="children" xsi:type="array"> - <item name="before-fields" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">before-fields</item> - <item name="children" xsi:type="array"> - <!-- before fields --> + <item name="payment" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/payment</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string">Payment</item> </item> - </item> - <item name="shipping-address-fieldset" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">additional-fieldsets</item> <item name="children" xsi:type="array"> - <!-- The following items override configuration of corresponding address attributes --> - <item name="region" xsi:type="array"> - <!-- Make region attribute invisible on frontend. Corresponding input element is created by region_id field --> - <item name="visible" xsi:type="boolean">false</item> + <item name="renders" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="children" xsi:type="array"> + <!-- merge payment method renders here --> + </item> </item> - <item name="region_id" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Ui/js/form/element/region</item> - <item name="config" xsi:type="array"> - <item name="template" xsi:type="string">ui/form/field</item> - <item name="elementTmpl" xsi:type="string">ui/form/element/select</item> - <item name="customEntry" xsi:type="string">shippingAddress.region</item> + <item name="customer-email" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Customer/js/view/customer-email</item> + <item name="displayArea" xsi:type="string">customer-email</item> + <item name="tooltip" xsi:type="array"> + <item name="description" xsi:type="string">(You can create an account to track your order after checkout)</item> + </item> + <item name="children" xsi:type="array"> + <item name="before-login-form" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">before-login-form</item> + <item name="children" xsi:type="array"> + <!-- before login form fields --> + </item> + </item> + <item name="additional-login-form-fields" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">additional-login-form-fields</item> + <item name="children" xsi:type="array"> + <!-- additional login form fields --> + </item> + </item> + </item> + </item> + <!-- TODO: add billing address form --> + <item name="beforeMethods" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">beforeMethods</item> + <item name="children" xsi:type="array"> + <!-- merge additional data before payment methods here --> </item> <item name="validation" xsi:type="array"> <item name="validate-select" xsi:type="string">true</item> @@ -182,135 +260,107 @@ <item name="field" xsi:type="string">country_id</item> </item> </item> - <item name="postcode" xsi:type="array"> - <!-- post-code field has custom UI component --> - <item name="component" xsi:type="string">Magento_Ui/js/form/element/post-code</item> - <item name="validation" xsi:type="array"> - <item name="required-entry" xsi:type="string">true</item> - </item> - </item> - <item name="company" xsi:type="array"> - <item name="validation" xsi:type="array"> - <item name="min_text_length" xsi:type="number">0</item> + <item name="payments-list" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/payment/list</item> + <item name="displayArea" xsi:type="string">payment-methods-list</item> + <item name="config" xsi:type="array"> + <item name="deps" xsi:type="string">checkout.steps.billing-step.payment.renders</item> </item> </item> - <item name="fax" xsi:type="array"> - <item name="validation" xsi:type="array"> - <item name="min_text_length" xsi:type="number">0</item> + <!-- merge your payment methods here --> + <item name="afterMethods" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">afterMethods</item> + <item name="children" xsi:type="array"> + <!-- merge additional data after payment methods here --> </item> </item> - <item name="country_id" xsi:type="array"> - <item name="sortOrder" xsi:type="string">115</item> - </item> - <item name="save_in_address_book" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Ui/js/form/element/abstract</item> - <item name="config" xsi:type="array"> - <item name="template" xsi:type="string">ui/form/field</item> - <item name="elementTmpl" xsi:type="string">ui/form/element/checkbox</item> - </item> - <item name="description" xsi:type="string">Save in address book</item> - <item name="provider" xsi:type="string">checkoutProvider</item> - <item name="dataScope" xsi:type="string">shippingAddress.save_in_address_book</item> - </item> </item> </item> </item> </item> - <item name="shipping" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-method</item> - <item name="sortOrder" xsi:type="string">4</item> - <item name="additional" xsi:type="array"> - <!-- merge your shipping methods here --> + </item> + </item> + <item name="summary" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary</item> + <item name="displayArea" xsi:type="string">summary</item> + <item name="config" xsi:type="array"> + <item name="template" xsi:type="string">Magento_Checkout/summary</item> + </item> + <item name="children" xsi:type="array"> + <item name="totals" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="displayArea" xsi:type="string">totals</item> + <item name="config" xsi:type="array"> + <item name="template" xsi:type="string">Magento_Checkout/summary/totals</item> </item> <item name="children" xsi:type="array"> - <item name="afterSelect" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">afterSelect</item> - <item name="children" xsi:type="array"> - <!-- merge additional data after shipping methods here --> + <!-- sort order for this totals is configured on admin panel--> + <!-- Stores->Configuration->SALES->Sales->General->Checkout Totals Sort Order --> + <item name="subtotal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/subtotal</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string">Cart Subtotal</item> </item> </item> - </item> - </item> - <item name="payment" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/payment</item> - <item name="sortOrder" xsi:type="string">5</item> - <item name="children" xsi:type="array"> - <item name="beforeMethods" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">beforeMethods</item> - <item name="children" xsi:type="array"> - <!-- merge additional data before payment methods here --> + <item name="shipping" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/shipping</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string">Shipping</item> + <item name="notCalculatedMessage" xsi:type="string">Not yet calculated</item> </item> </item> - <!-- merge your payment methods here --> - <item name="afterMethods" xsi:type="array"> - <item name="component" xsi:type="string">uiComponent</item> - <item name="displayArea" xsi:type="string">afterMethods</item> - <item name="children" xsi:type="array"> - <!-- merge additional data after payment methods here --> + <item name="grand-total" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/grand-total</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string">Order Total</item> </item> </item> </item> </item> - <item name="review" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/review</item> - <item name="sortOrder" xsi:type="string">6</item> + <item name="itemsBefore" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> <item name="children" xsi:type="array"> - <item name="columns" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/columns</item> - <item name="children" xsi:type="array"> - <item name="name" xsi:type="array"><item name="component" xsi:type="string">Magento_Checkout/js/view/review/item/columns/name</item></item> - <item name="price" xsi:type="array"><item name="component" xsi:type="string">Magento_Checkout/js/view/review/item/columns/price</item></item> - <item name="qty" xsi:type="array"><item name="component" xsi:type="string">Magento_Checkout/js/view/review/item/columns/qty</item></item> - <item name="subtotal" xsi:type="array"><item name="component" xsi:type="string">Magento_Checkout/js/view/review/item/columns/subtotal</item></item> - </item> - </item> - <item name="itemsBefore" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/itemsBefore</item> - <item name="children" xsi:type="array"> - <!-- merge your components here --> - </item> - </item> - <item name="itemsAfter" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/itemsAfter</item> - <item name="children" xsi:type="array"> - <!-- merge your components here --> - </item> - </item> - <item name="beforePlaceOrder" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/beforePlaceOrder</item> - <item name="children" xsi:type="array"> - <!-- merge your components here --> - </item> - </item> - <item name="totals" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/totals</item> + <!-- merge your components here --> + </item> + </item> + <item name="cart_items" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/cart-items</item> + <item name="children" xsi:type="array"> + <item name="details" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details</item> <item name="children" xsi:type="array"> - <item name="subtotal" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/subtotal</item> - </item> - <item name="discount" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/discount</item> + <item name="thumbnail" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details/thumbnail</item> + <item name="displayArea" xsi:type="string">before_details</item> </item> - </item> - </item> - <item name="actions" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/review/actions</item> - <item name="children" xsi:type="array"> - <item name="@default" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/review/actions/default</item> - <item name="config" xsi:type="array"> - <item name="isDefault" xsi:type="boolean">true</item> - </item> + <item name="subtotal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details/subtotal</item> + <item name="displayArea" xsi:type="string">after_details</item> </item> - <!-- merge your components here --> </item> </item> + + </item> + </item> + <item name="itemsAfter" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="children" xsi:type="array"> + <!-- merge your components here --> </item> </item> </item> </item> + <item name="shipping-information" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-information</item> + <item name="displayArea" xsi:type="string">shipping-information</item> + <item name="children" xsi:type="array"> + <item name="ship-to" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/shipping-information/list</item> + <item name="displayArea" xsi:type="string">ship-to</item> + </item> + </item> + </item> </item> </item> <item name="checkoutProvider" xsi:type="array"> @@ -321,5 +371,6 @@ </arguments> </block> </referenceContainer> + <remove name="page.messages" /> </body> </page> diff --git a/app/code/Magento/Checkout/view/frontend/layout/default.xml b/app/code/Magento/Checkout/view/frontend/layout/default.xml index 2ac27890ca18a2a79b604c647abe24eb95f14625..da1007040f6a19ab02d2f794b2df8ac4e93df719 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/default.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/default.xml @@ -51,6 +51,19 @@ <item name="displayArea" xsi:type="string">promotion</item> </item> </item> + <item name="sign-in-popup" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/cart/authentication</item> + <item name="config" xsi:type="array"> + <item name="displayArea" xsi:type="string">sign-in-popup</item> + <item name="template" xsi:type="string">Magento_Checkout/cart/authentication</item> + </item> + <item name="children" xsi:type="array"> + <item name="messages" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Ui/js/view/messages</item> + <item name="displayArea" xsi:type="string">messages</item> + </item> + </item> + </item> </item> </item> </item> diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/minicart.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/minicart.phtml index d515d34169278ca83c7d361c5e43fcd51f9840ae..6d08bcb4bbf500ef2f823c46e8074640099f07d6 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/minicart.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/minicart.phtml @@ -42,18 +42,15 @@ </div> <?php endif ?> <script> - window.checkout = { - shoppingCartUrl: '<?=$block->getShoppingCartUrl()?>', - checkoutUrl: '<?=$block->getCheckoutUrl()?>', - updateItemQtyUrl: '<?=$block->getUpdateItemQtyUrl()?>', - removeItemUrl: '<?=$block->getRemoveItemUrl()?>', - imageTemplate: '<?= $block->getImageHtmlTemplate()?>' - }; + window.checkout = <?php echo \Zend_Json::encode($block->getConfig()); ?>; </script> <script type="text/x-magento-init"> { "[data-block='minicart']": { "Magento_Ui/js/core/app": <?php echo $block->getJsLayout();?> + }, + "*": { + "Magento_Ui/js/block-loader": "<?php echo $block->getViewFileUrl('images/loader-1.gif'); ?>" } } </script> diff --git a/app/code/Magento/Checkout/view/frontend/templates/onepage.phtml b/app/code/Magento/Checkout/view/frontend/templates/onepage.phtml index 7e8fe0c43edb0dd18ac6ac63ceae182267a1de08..1f05ef68ff3a41b882e7342dc6c271ea2a9eb670 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/onepage.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/onepage.phtml @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ ?> - <div id="checkout" data-bind="scope:'checkout'"> + <div id="checkout" data-bind="scope:'checkout'" class="checkout-container"> <!-- ko template: getTemplate() --><!-- /ko --> <script type="text/x-magento-init"> { @@ -20,8 +20,13 @@ window.customerData = window.checkoutConfig.customerData; </script> <script> - require(['mage/url', 'Magento_Checkout/js/model/step-loader'], function(url, loader) { + require([ + 'mage/url', + 'Magento_Checkout/js/model/step-loader', + 'Magento_Ui/js/block-loader' + ], function(url, loader, blockLoader) { loader.registerLoader(); + blockLoader("<?php echo $block->getViewFileUrl('images/loader-1.gif'); ?>"); return url.setBaseUrl('<?php echo $block->getBaseUrl();?>'); }) </script> diff --git a/app/code/Magento/Checkout/view/frontend/templates/onepage/link.phtml b/app/code/Magento/Checkout/view/frontend/templates/onepage/link.phtml index 25d144d746d4a42020cce13217abb4b831e90d81..72b8a5bf5023ad578385467538fdb88299bce81e 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/onepage/link.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/onepage/link.phtml @@ -5,18 +5,14 @@ */ // @codingStandardsIgnoreFile - -/** - * @deprecated - * @removeCandidate - */ ?> <?php if ($block->isPossibleOnepageCheckout()):?> <button type="button" + data-role="proceed-to-checkout" title="<?php echo __('Proceed to Checkout') ?>" + data-mage-init='{"Magento_Checkout/js/proceed-to-checkout":{}}' class="action primary checkout<?php echo($block->isDisabled()) ? ' disabled' : ''; ?>" - <?php if ($block->isDisabled()):?>disabled="disabled"<?php endif; ?> - onclick="window.location='<?php echo $block->getCheckoutUrl() ?>';"> - <span><?php echo __('Proceed to Checkout') ?></span> + <?php if ($block->isDisabled()):?>disabled="disabled"<?php endif; ?>> + <span><?php echo __('Proceed to Checkout') ?></span> </button> <?php endif?> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js b/app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js new file mode 100644 index 0000000000000000000000000000000000000000..a48f92659f46a3f0d2d8bb76d5cb2920182643be --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js @@ -0,0 +1,17 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'Magento_Checkout/js/model/address-converter' + ], + function(addressConverter) { + "use strict"; + return function(addressData) { + var address = addressConverter.formAddressDataToQuoteAddress(addressData); + return address; + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/create-shipping-address.js b/app/code/Magento/Checkout/view/frontend/web/js/action/create-shipping-address.js new file mode 100644 index 0000000000000000000000000000000000000000..d4225a3166057fabbcc83ebf01530ffae7601167 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/create-shipping-address.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'Magento_Customer/js/model/address-list', + 'Magento_Checkout/js/model/address-converter' + ], + function(addressList, addressConverter) { + "use strict"; + return function(addressData) { + var address = addressConverter.formAddressDataToQuoteAddress(addressData); + var isAddressUpdated = addressList().some(function(currentAddress, index, addresses) { + if (currentAddress.getKey() == address.getKey()) { + addresses[index] = address; + return true; + } + return false; + }); + if (!isAddressUpdated) { + addressList.push(address); + } else { + addressList.valueHasMutated(); + } + return address; + }; + } +); \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/get-totals.js b/app/code/Magento/Checkout/view/frontend/web/js/action/get-totals.js new file mode 100644 index 0000000000000000000000000000000000000000..57524a7cb404576bc19da11b30b54452833f5ab9 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/get-totals.js @@ -0,0 +1,47 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/*global define,alert*/ +define( + [ + 'jquery', + '../model/quote', + 'Magento_Checkout/js/model/resource-url-manager', + 'Magento_Ui/js/model/messageList', + 'mage/storage', + 'Magento_Checkout/js/model/totals' + ], + function ($, quote, resourceUrlManager, messageList, storage, totals) { + "use strict"; + return function (callbacks, deferred) { + deferred = deferred || $.Deferred(); + totals.isLoading(true); + return storage.get( + resourceUrlManager.getUrlForCartTotals(quote), + false + ).done( + function (response) { + totals.isLoading(false); + var proceed = true; + $.each(callbacks, function(index, callback) { + proceed = proceed && callback(); + }); + if (proceed) { + quote.setTotals(response); + deferred.resolve(); + } + } + ).error( + function (response) { + totals.isLoading(false); + var error = JSON.parse(response.responseText); + messageList.addErrorMessage(error); + deferred.reject(); + } + ); + + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/place-order.js b/app/code/Magento/Checkout/view/frontend/web/js/action/place-order.js index ee6bf6d67d3396bf764b2f39ac1c275ab464b1f5..eabe01078de5e0bbeb9a788c30c21f6e313977ec 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/action/place-order.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/place-order.js @@ -2,48 +2,56 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*global define*/ define( [ - '../model/quote', - '../model/url-builder', - '../model/payment-service', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/url-builder', 'mage/storage', 'mage/url', - 'Magento_Ui/js/model/errorlist', + 'Magento_Ui/js/model/messageList', 'Magento_Customer/js/model/customer', 'underscore' ], - function(quote, urlBuilder, paymentService, storage, url, errorList, customer, _) { - "use strict"; - return function(customParams, callback) { - var payload; - customParams = customParams || { - cartId: quote.getQuoteId(), - paymentMethod: paymentService.getSelectedPaymentData() - }; + function (quote, urlBuilder, storage, url, messageList, customer, _) { + 'use strict'; + + return function (paymentData, redirectOnSuccess) { + var serviceUrl, payload; + + redirectOnSuccess = redirectOnSuccess === false ? false : true; /** * Checkout for guest and registered customer. */ - var serviceUrl; - if (quote.getCheckoutMethod()() === 'guest') { - serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/order', {quoteId: quote.getQuoteId()}); + if (!customer.isLoggedIn()) { + serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/payment-information', { + quoteId: quote.getQuoteId() + }); + payload = { + cartId: quote.getQuoteId(), + email: quote.guestEmail, + paymentMethod: paymentData, + billingAddress: quote.billingAddress() + }; } else { - serviceUrl = urlBuilder.createUrl('/carts/mine/order', {}); + serviceUrl = urlBuilder.createUrl('/carts/mine/payment-information', {}); + payload = { + cartId: quote.getQuoteId(), + paymentMethod: paymentData, + billingAddress: quote.billingAddress() + }; } - payload = customParams; - storage.put( + storage.post( serviceUrl, JSON.stringify(payload) ).done( - function() { - if (!_.isFunction(callback) || callback()) { + function () { + if (redirectOnSuccess) { window.location.replace(url.build('checkout/onepage/success/')); } } ).fail( - function(response) { + function (response) { var error = JSON.parse(response.responseText); - errorList.add(error); + messageList.addErrorMessage(error); } ); }; diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/select-billing-address.js b/app/code/Magento/Checkout/view/frontend/web/js/action/select-billing-address.js index 635f6797f40750b26511d8c686c4227b7420b433..da290fc1aa214d38d38deb8ca5b68805e66962f5 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/action/select-billing-address.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/select-billing-address.js @@ -2,88 +2,15 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*jshint browser:true*/ -/*global define, alert*/ +/*global define*/ define( [ - '../model/quote', - '../model/addresslist', - '../model/step-navigator', - './select-shipping-address', - 'uiRegistry', - '../model/url-builder', - 'mage/storage', - '../model/payment-service', - 'underscore' + '../model/quote' ], - function (quote, addressList, navigator, selectShippingAddress, registry, urlBuilder, storage, paymentService, _) { + function(quote) { "use strict"; - var actionCallback; - var result = function (billingAddress, useForShipping, additionalData) { - var copyBillingToShipping = function() { - var shippingAddressSource = registry.get('checkoutProvider'), - shippingAddress = shippingAddressSource.get('shippingAddress'); - for (var property in billingAddress) { - if (billingAddress.hasOwnProperty(property) && shippingAddress.hasOwnProperty(property)) { - if (typeof billingAddress[property] === 'string') { - shippingAddressSource.set('shippingAddress.' + property, billingAddress[property]); - } else { - shippingAddressSource.set('shippingAddress.' + property, _.clone(billingAddress[property])); - } - } - } - }; - additionalData = additionalData || {}; - quote.setBillingAddress(billingAddress); - if (useForShipping() === '1' && !quote.isVirtual()) { - if (!billingAddress.customerAddressId) { - copyBillingToShipping(); - } - selectShippingAddress(billingAddress, useForShipping, additionalData); - } else if (quote.isVirtual()) { - var serviceUrl; - if (quote.getCheckoutMethod()() === 'guest') { - serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/addresses', {quoteId: quote.getQuoteId()}); - } else { - serviceUrl = urlBuilder.createUrl('/carts/mine/addresses', {}); - } - storage.post( - serviceUrl, - JSON.stringify({ - billingAddress: quote.getBillingAddress()(), - additionalData: {extensionAttributes : additionalData}, - checkoutMethod: quote.getCheckoutMethod()() - }) - ).done( - function (result) { - paymentService.setPaymentMethods(result.payment_methods); - quote.setFormattedBillingAddress(result.formatted_billing_address); - quote.setTotals(result.totals); - navigator.setCurrent('billingAddress').goNext(); - if (typeof actionCallback == 'function') { - actionCallback(true); - } - } - ).fail( - function (response) { - var error = JSON.parse(response.responseText); - errorList.add(error); - quote.setBillingAddress(null); - if (typeof actionCallback == 'function') { - actionCallback(false); - } - } - ); - } else { - navigator.setCurrent('billingAddress').goNext(); - if (addressList.isBillingSameAsShipping) { - copyBillingToShipping(); - } - } + return function(billingAddress) { + quote.billingAddress(billingAddress); }; - result.setActionCallback = function (value) { - actionCallback = value; - }; - return result; } ); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/select-payment-method.js b/app/code/Magento/Checkout/view/frontend/web/js/action/select-payment-method.js index f0fe5a55aa3af0016a1a4e78dd15d7ae66295400..c6d9c56528efb47d0364a769b3a0a56d7d2d0016 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/action/select-payment-method.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/select-payment-method.js @@ -5,96 +5,12 @@ /*global define*/ define( [ - '../model/quote', - '../model/url-builder', - '../model/step-navigator', - '../model/payment-service', - 'Magento_Ui/js/model/errorlist', - 'mage/storage', - 'underscore' + '../model/quote' ], - function(quote, urlBuilder, navigator, service, errorList, storage, _) { - "use strict"; - return function (methodData, methodInfo, callbacks) { - var paymentMethodData = { - "cartId": quote.getQuoteId(), - "paymentMethod": methodData - }; - - var shippingMethodCode = quote.getSelectedShippingMethod()().slice(0).split("_"), - shippingMethodData = { - "shippingCarrierCode" : shippingMethodCode.shift(), - "shippingMethodCode" : shippingMethodCode.join('_') - }, - serviceUrl; - if (quote.getCheckoutMethod()() === 'guest') { - serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/collect-totals', {quoteId: quote.getQuoteId()}); - } else { - serviceUrl = urlBuilder.createUrl('/carts/mine/collect-totals', {}); - } - - if (quote.isVirtual()) { - return storage.put( - serviceUrl, - JSON.stringify(paymentMethodData) - ).done( - function (response) { - var proceed = true; - _.each(callbacks, function(callback) { - proceed = proceed && callback(); - }); - if (proceed) { - quote.setPaymentMethod(methodData.method); - service.setSelectedPaymentData(methodData); - service.setSelectedPaymentInfo(methodInfo); - quote.setTotals(response); - navigator.setCurrent('paymentMethod').goNext(); - } - } - ).error( - function (response) { - var error = JSON.parse(response.responseText); - errorList.add(error); - quote.setPaymentMethod(null); - } - ); - } else { - if (!_.isEmpty(quote.getShippingCustomOptions()())) { - shippingMethodData = _.extend( - shippingMethodData, - { - additionalData: { - extension_attributes: quote.getShippingCustomOptions()() - } - } - ); - } - return storage.put( - serviceUrl, - JSON.stringify(_.extend(paymentMethodData, shippingMethodData)) - ).done( - function (response) { - var proceed = true; - _.each(callbacks, function(callback) { - proceed = proceed && callback(); - }); - if (proceed) { - quote.setPaymentMethod(methodData.method); - //set the totals before setting PaymentData - quote.setTotals(response); - service.setSelectedPaymentData(methodData); - service.setSelectedPaymentInfo(methodInfo); - navigator.setCurrent('paymentMethod').goNext(); - } - } - ).error( - function (response) { - var error = JSON.parse(response.responseText); - errorList.add(error); - quote.setPaymentMethod(null); - } - ); - } - }; + function(quote) { + 'use strict'; + return function (paymentMethod) { + quote.paymentMethod(paymentMethod); + } } ); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-address.js b/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-address.js index c9f87d1594b7aa201bee919e37ba79ca4c3d21a6..5247cef00fb03ac61bf36e29f7e6655fee7605cd 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-address.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-address.js @@ -4,69 +4,16 @@ */ /*global define*/ define( - [ - '../model/quote', - '../model/addresslist', - '../model/url-builder', - '../model/step-navigator', - '../model/shipping-service', - '../model/payment-service', - 'mage/storage', - 'Magento_Ui/js/model/errorlist' + ['../model/quote', + 'Magento_Checkout/js/model/shipping-rate-service' ], - function(quote, addressList, urlBuilder, navigator, shippingService, paymentService, storage, errorList) { + function(quote, shippingRateService) { "use strict"; - var actionCallback; - var result = function(shippingAddress, sameAsBilling, additionalData) { - var serviceUrl; - if (quote.getCheckoutMethod()() === 'guest') { - serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/addresses', {quoteId: quote.getQuoteId()}); - } else { - serviceUrl = urlBuilder.createUrl('/carts/mine/addresses', {}); - } - - errorList.clear(); - additionalData = additionalData || {}; - shippingAddress['same_as_billing'] = (sameAsBilling) ? 1 : 0; - quote.setShippingAddress(shippingAddress); - - storage.post( - serviceUrl, - JSON.stringify({ - shippingAddress: quote.getShippingAddress()(), - billingAddress: quote.getBillingAddress()(), - additionalData: {extensionAttributes : additionalData}, - checkoutMethod: quote.getCheckoutMethod()() - }) - ).done( - function(result) { - shippingService.setShippingRates(result.shipping_methods); - paymentService.setPaymentMethods(result.payment_methods); - quote.setFormattedBillingAddress(result.formatted_billing_address); - quote.setFormattedShippingAddress(result.formatted_shipping_address); - quote.setTotals(result.totals); - navigator.setCurrent('shippingAddress').goNext(); - if (typeof actionCallback == 'function') { - actionCallback(true); - } - } - ).fail( - function(response) { - var error = JSON.parse(response.responseText); - errorList.add(error); - quote.setShippingAddress(null); - quote.setBillingAddress(null); - quote.setFormattedBillingAddress(null); - quote.setFormattedShippingAddress(null); - if (typeof actionCallback == 'function') { - actionCallback(false); - } - } - ); + quote.shippingAddress.subscribe(function () { + shippingRateService.getRates(quote.shippingAddress()) + }); + return function(shippingAddress) { + quote.shippingAddress(shippingAddress); }; - result.setActionCallback = function (value) { - actionCallback = value; - }; - return result; } ); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-method.js b/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-method.js index f00e2e86670c8e145fc67b33ec8a3fe7f1bcbf47..30f629cfc09e52343b5fe41343c8229f3e0e9abf 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-method.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/select-shipping-method.js @@ -5,36 +5,12 @@ /*global define,alert*/ define( [ - '../model/quote', - '../model/url-builder', - '../model/step-navigator', - 'Magento_Checkout/js/model/shipping-service', - 'mage/translate', - 'ko' + '../model/quote' ], - function (quote, urlBuilder, navigator, shippingService, $t, ko) { + function (quote) { "use strict"; - return function (code, customOptions, callbacks) { - if (!code) { - alert($t('Please specify a shipping method')); - return; - } - - var proceed = true; - _.each(callbacks, function (callback) { - proceed = proceed && callback(); - }); - - if (proceed) { - var shippingMethodCode = code.split("_"), - shippingRate = shippingService.getRateByCode(shippingMethodCode)[0]; - - quote.setShippingMethod(shippingMethodCode); - quote.setSelectedShippingMethod(code); - quote.setShippingCustomOptions(customOptions); - quote.setCollectedTotals('shipping', shippingRate.amount); - navigator.setCurrent('shippingMethod').goNext(); - } - }; + return function (shippingMethod) { + quote.shippingMethod(shippingMethod) + } } ); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information.js b/app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information.js new file mode 100644 index 0000000000000000000000000000000000000000..4f1167970a41e3af06ac108be3e60aa44d63ad20 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information.js @@ -0,0 +1,56 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/url-builder', + 'mage/storage', + 'Magento_Ui/js/model/messageList', + 'Magento_Customer/js/model/customer' + ], + function (quote, urlBuilder, storage, messageList, customer) { + 'use strict'; + + return function () { + var serviceUrl, + payload, + paymentData = quote.paymentMethod(); + + /** + * Checkout for guest and registered customer. + */ + if (!customer.isLoggedIn()) { + serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/set-payment-information', { + quoteId: quote.getQuoteId() + }); + payload = { + cartId: quote.getQuoteId(), + email: quote.guestEmail, + paymentMethod: paymentData, + billingAddress: quote.billingAddress() + }; + } else { + serviceUrl = urlBuilder.createUrl('/carts/mine/set-payment-information', {}); + payload = { + cartId: quote.getQuoteId(), + paymentMethod: paymentData, + billingAddress: quote.billingAddress() + }; + } + return storage.post( + serviceUrl, JSON.stringify(payload) + ).done( + function () { + //do nothing + } + ).fail( + function (response) { + var error = JSON.parse(response.responseText); + messageList.addErrorMessage(error); + } + ); + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/set-shipping-information.js b/app/code/Magento/Checkout/view/frontend/web/js/action/set-shipping-information.js new file mode 100644 index 0000000000000000000000000000000000000000..918f5201012f1eb933940b8a10e817b3a67387b4 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/action/set-shipping-information.js @@ -0,0 +1,17 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define,alert*/ +define( + [ + '../model/quote', + 'Magento_Checkout/js/model/shipping-save-processor' + ], + function (quote, shippingSaveProcessor) { + 'use strict'; + return function () { + return shippingSaveProcessor.saveShippingInformation(quote.shippingAddress().getType()); + } + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js new file mode 100644 index 0000000000000000000000000000000000000000..896f38b9648aa27bee9050378c445d6a7e664ce5 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js @@ -0,0 +1,85 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'jquery', + 'Magento_Checkout/js/model/new-customer-address', + 'mage/utils/objects' + ], + function($, address, mageUtils) { + 'use strict'; + var countryData = window.checkoutConfig.countryData; + + return { + /** + * Convert address form data to Address object + * @param {Object} formData + * @returns {Object} + */ + formAddressDataToQuoteAddress: function(formData) { + // clone address form data to new object + var addressData = $.extend(true, {}, formData), + region; + + if (mageUtils.isObject(addressData.street)) { + addressData.street = this.objectToArray(addressData.street); + } + + addressData.region = { + region_id: null, + region_code: null, + region: null + }; + + if (addressData.region_id) { + region = countryData[addressData.country_id]['regions'][addressData.region_id]; + if (region) { + addressData.region.region_id = addressData['region_id']; + addressData.region.region_code = region['code']; + addressData.region.region = region['name']; + } + } + delete addressData.region_id; + + return address(addressData); + }, + + formDataProviderToFlatData: function(formProviderData, formIndex) { + var addressData = {}; + $.each(formProviderData, function(path, value) { + var pathComponents = path.split('.'); + pathComponents.splice(pathComponents.indexOf(formIndex), 1); + pathComponents.reverse(); + var dataObject = {}; + $.each(pathComponents, function(index, pathPart) { + if (index == 0) { + dataObject[pathPart] = value; + } else { + var parent = {}; + parent[pathPart] = dataObject; + dataObject = parent; + } + }); + $.extend(true, addressData, dataObject); + }); + return addressData; + }, + + /** + * Convert object to array + * @param {Object} object + * @returns {Array} + */ + objectToArray: function (object) { + var convertedArray = []; + $.each(object, function (key) { + return object[key].length ? convertedArray.push(object[key]) : false; + }); + + return convertedArray.slice(0); + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/addresslist.js b/app/code/Magento/Checkout/view/frontend/web/js/model/addresslist.js deleted file mode 100644 index 62bc28d2527638c59a8f629f09448279187a74d4..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/addresslist.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true*/ -/*global define*/ -define(['jquery'], function($) { - "use strict"; - var addresses = []; - return { - add: function (address) { - addresses.push(address); - }, - getAddressById: function(id) { - var address = null; - $.each(addresses, function(key, item) { - if (id === item.customerAddressId) { - address = item; - return false; - } - }); - return address; - }, - getAddresses: function() { - return addresses.slice(0); - }, - isBillingSameAsShipping: false - }; -}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/authentication-popup.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/authentication-popup.js new file mode 100644 index 0000000000000000000000000000000000000000..e448a1c30b07da31ae1f26aaecb0477bade09b65 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/authentication-popup.js @@ -0,0 +1,37 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'jquery', + 'Magento_Ui/js/modal/modal' + ], + function ($, modal) { + 'use strict'; + return { + modalWindow: null, + + /** Create popUp window for provided element */ + createPopUp: function(element) { + this.modalWindow = element; + var options = { + 'type': 'popup', + 'modalClass': 'popup-authentication', + 'responsive': true, + 'innerScroll': true, + 'trigger': '.proceed-to-checkout', + 'buttons': [] + }; + modal(options, $(this.modalWindow)); + }, + + /** Show login popup window */ + showModal: function() { + $(this.modalWindow).modal('openModal'); + } + } + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js new file mode 100644 index 0000000000000000000000000000000000000000..7f64f87e3e4c6cb7308f6a441faed2e13a74589a --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js @@ -0,0 +1,58 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define([], function() { + /** + * @param addressData + * Returns new address object + */ + return function (addressData) { + var identifier = Date.now(); + return { + email: addressData.email, + countryId: addressData.country_id, + regionId: (addressData.region) ? addressData.region.region_id : null, + regionCode: (addressData.region) ? addressData.region.region_code : null, + region: (addressData.region) ? addressData.region.region : null, + customerId: addressData.customer_id, + street: addressData.street, + company: addressData.company, + telephone: addressData.telephone, + fax: addressData.fax, + postcode: addressData.postcode, + city: addressData.city, + firstname: addressData.firstname, + lastname: addressData.lastname, + middlename: addressData.middlename, + prefix: addressData.prefix, + suffix: addressData.suffix, + vatId: addressData.vat_id, + sameAsBilling: addressData.same_as_billing, + saveInAddressBook: addressData.save_in_address_book, + isDefaultShipping: function() { + return addressData.default_shipping; + }, + isDefaultBilling: function() { + return addressData.default_billing; + }, + getType: function() { + return 'new-customer-address' + }, + getKey: function() { + return this.getType(); + }, + getCacheKey: function() { + return this.getType() + identifier; + }, + isEditable: function() { + return true; + }, + canUseForBilling: function() { + return true; + } + } + } +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/payment-service.js b/app/code/Magento/Checkout/view/frontend/web/js/model/payment-service.js index 9b6fc75a216c506964c20ee938f60ee1677de823..77841ad3b0632b0d155c7618039ea15fdc5776e9 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/payment-service.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/payment-service.js @@ -2,67 +2,72 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*jshint browser:true jquery:true*/ -/*global alert*/ define( [ - 'ko', - 'jquery', - 'Magento_Checkout/js/model/quote' + 'underscore', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/payment/method-list', + 'Magento_Checkout/js/action/select-payment-method' ], - function (ko, $, quote) { + function (_, quote, methodList, selectPaymentMethod) { + 'use strict'; + var freeMethodCode = 'free'; + return { - paymentMethods: ko.observableArray([]), - availablePaymentMethods: ko.observableArray([]), - selectedPaymentData: ko.observableArray(), - selectedPaymentInfo: ko.observableArray([]), - setPaymentMethods: function(methods) { - this.paymentMethods(methods); + isFreeAvailable: false, + /** + * Populate the list of payment methods + * @param {Array} methods + */ + setPaymentMethods: function (methods) { + var self = this, + freeMethod, + filteredMethods, + methodIsAvailable; + + freeMethod = _.find(methods, function (method) { + return method.method === freeMethodCode; + }); + this.isFreeAvailable = freeMethod ? true : false; + + if (self.isFreeAvailable && freeMethod && quote.totals().grand_total <= 0) { + methods.splice(0, methods.length, freeMethod); + selectPaymentMethod(freeMethod); + } + filteredMethods = _.without(methods, freeMethod); + + if (filteredMethods.length === 1) { + selectPaymentMethod(filteredMethods[0]); + } else if (quote.paymentMethod()) { + methodIsAvailable = methods.some(function (item) { + return item.method === quote.paymentMethod().method; + }); + //Unset selected payment method if not available + if (!methodIsAvailable) { + selectPaymentMethod(null); + } + } + methodList(methods); }, + /** + * Get the list of available payment methods. + * @returns {Array} + */ getAvailablePaymentMethods: function () { var methods = [], self = this; - $.each(this.paymentMethods(), function (key, method) { - if (self.isFreeMethodActive() && ( - quote.getCalculatedTotal() <= 0 && method['code'] == 'free' - || quote.getCalculatedTotal() > 0 && method['code'] != 'free' - ) || !self.isFreeMethodActive() + _.each(methodList(), function (method) { + if (self.isFreeAvailable && ( + quote.totals().grand_total <= 0 && method.method === freeMethodCode || + quote.totals().grand_total > 0 && method.method !== freeMethodCode + ) || !self.isFreeAvailable ) { methods.push(method); } }); + return methods; - }, - isFreeMethodActive: function () { - var isAvailable = false; - $.each(this.paymentMethods(), function (key, method) { - if (method['code'] == 'free') { - isAvailable = true; - } - }); - return isAvailable; - }, - setSelectedPaymentData: function(data) { - this.selectedPaymentData(data); - }, - getSelectedPaymentData: function () { - return this.selectedPaymentData(); - }, - setSelectedPaymentInfo: function(data) { - this.selectedPaymentInfo(data); - }, - getSelectedPaymentInfo: function () { - return this.selectedPaymentInfo(); - }, - getTitleByCode: function(code) { - var methodTitle = ''; - $.each(this.getAvailablePaymentMethods(), function (key, entity) { - if (entity['code'] == code) { - methodTitle = entity['title']; - } - }); - return methodTitle; } - } + }; } ); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-converter.js b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-converter.js new file mode 100644 index 0000000000000000000000000000000000000000..794f7d9a38b01fc043414adb8fdb2714f0aeac42 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-converter.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'underscore' + ], + function (_) { + 'use strict'; + + return function (methods) { + _.each(methods, function(method) { + if (method.hasOwnProperty('code')) { + method.method = method.code; + delete method.code; + } + }); + + return methods; + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-list.js b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-list.js new file mode 100644 index 0000000000000000000000000000000000000000..9b234d7572c8efdfafc4c71456491edfb811b71d --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/method-list.js @@ -0,0 +1,13 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'ko' + ], + function(ko) { + 'use strict'; + return ko.observableArray([]); + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/view/payment/free-method.js b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/renderer-list.js similarity index 51% rename from app/code/Magento/Payment/view/frontend/web/js/view/payment/free-method.js rename to app/code/Magento/Checkout/view/frontend/web/js/model/payment/renderer-list.js index 44285074df09ad9fa0d14f8f94a69c8c8782ba11..1966d296a9ef06c2df54a5c22c6cbe1364e74655 100644 --- a/app/code/Magento/Payment/view/frontend/web/js/view/payment/free-method.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/renderer-list.js @@ -2,14 +2,13 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*browser:true*/ /*global define*/ define( [ - 'Magento_Checkout/js/view/payment/method-info' + 'ko' ], - function (method) { - return method.extend({ - }); + function(ko) { + 'use strict'; + return ko.observableArray([]); } ); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/postcode-validator.js b/app/code/Magento/Checkout/view/frontend/web/js/model/postcode-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..1cc970630a39c7c4509450c921c98cab0886db7f --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/postcode-validator.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define(['mageUtils'], function (utils) { + 'use strict'; + return { + validatedPostCodeExample: [], + validate: function(postCode, countryId) { + var patterns = window.checkoutConfig.postCodes[countryId]; + this.validatedPostCodeExample = []; + + if (!utils.isEmpty(postCode) && !utils.isEmpty(patterns)) { + for (var pattern in patterns) { + if (patterns.hasOwnProperty(pattern)) { + this.validatedPostCodeExample.push(patterns[pattern]['example']); + var regex = new RegExp(patterns[pattern]['pattern']); + if (regex.test(postCode)) { + return true; + } + } + } + return false; + } + return true; + } + } +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/quote.js b/app/code/Magento/Checkout/view/frontend/web/js/model/quote.js index 650a8b053f7a2c14d07cce94e578e3b1dde6c48f..2ba260a0495c1bd483b291d90988a68cffc48f8d 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/quote.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/quote.js @@ -2,11 +2,10 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*jshint browser:true jquery:true*/ -/*global alert*/ define( ['ko'], - function(ko) { + function (ko) { + 'use strict'; var billingAddress = ko.observable(null); var shippingAddress = ko.observable(null); var shippingMethod = ko.observable(null); @@ -14,15 +13,21 @@ define( var quoteData = window.checkoutConfig.quoteData; var basePriceFormat = window.checkoutConfig.basePriceFormat; var priceFormat = window.checkoutConfig.priceFormat; - var selectedShippingMethod = ko.observable(window.checkoutConfig.selectedShippingMethod); var storeCode = window.checkoutConfig.storeCode; - var totals = ko.observable({}); - var checkoutMethod = ko.observable(null); + var totalsData = window.checkoutConfig.totalsData; + var totals = ko.observable(totalsData); var shippingCustomOptions = ko.observable(null); var formattedShippingAddress = ko.observable(null); var formattedBillingAddress = ko.observable(null); var collectedTotals = ko.observable({}); return { + totals: totals, + shippingAddress: shippingAddress, + shippingMethod: shippingMethod, + billingAddress: billingAddress, + paymentMethod: paymentMethod, + guestEmail: null, + getQuoteId: function() { return quoteData.entity_id; }, @@ -39,7 +44,7 @@ define( return window.checkoutConfig.quoteItemData; }, getTotals: function() { - return totals + return totals; }, setTotals: function(totalsData) { if (_.isObject(totalsData.extension_attributes)) { @@ -50,18 +55,6 @@ define( totals(totalsData); this.setCollectedTotals('subtotal_with_discount', parseFloat(totalsData.subtotal_with_discount)); }, - setBillingAddress: function (address) { - billingAddress(address); - }, - getBillingAddress: function() { - return billingAddress; - }, - setShippingAddress: function (address) { - shippingAddress(address); - }, - getShippingAddress: function() { - return shippingAddress; - }, setFormattedBillingAddress: function (address) { formattedBillingAddress(address); }, @@ -80,27 +73,9 @@ define( getPaymentMethod: function() { return paymentMethod; }, - setShippingMethod: function(shippingMethodCode) { - shippingMethod(shippingMethodCode); - }, - getShippingMethod: function() { - return shippingMethod; - }, - getSelectedShippingMethod: function() { - return selectedShippingMethod; - }, - setSelectedShippingMethod: function(shippingMethod) { - selectedShippingMethod(shippingMethod); - }, getStoreCode: function() { return storeCode; }, - getCheckoutMethod: function() { - return checkoutMethod; - }, - setCheckoutMethod: function(method) { - checkoutMethod(method); - }, setShippingCustomOptions: function(customOptions) { shippingCustomOptions(customOptions); }, diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/resource-url-manager.js b/app/code/Magento/Checkout/view/frontend/web/js/model/resource-url-manager.js new file mode 100644 index 0000000000000000000000000000000000000000..b84e16a80bff26af12a7698631259f901cc5dd4f --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/resource-url-manager.js @@ -0,0 +1,90 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'Magento_Customer/js/model/customer', + 'Magento_Checkout/js/model/url-builder', + 'mageUtils' + ], + function(customer, urlBuilder, utils) { + "use strict"; + return { + getUrlForEstimationShippingMethodsForNewAddress: function(quote) { + var params = (this.getCheckoutMethod() == 'guest') ? {quoteId: quote.getQuoteId()} : {}; + var urls = { + 'guest': '/guest-carts/:quoteId/estimate-shipping-methods', + 'customer': '/carts/mine/estimate-shipping-methods' + }; + return this.getUrl(urls, params); + }, + + getUrlForEstimationShippingMethodsByAddressId: function(quote) { + var params = (this.getCheckoutMethod() == 'guest') ? {quoteId: quote.getQuoteId()} : {}; + var urls = { + 'default': '/carts/mine/estimate-shipping-methods-by-address-id' + }; + return this.getUrl(urls, params); + }, + + getApplyCouponUrl: function(couponCode, quoteId) { + var params = (this.getCheckoutMethod() == 'guest') ? {quoteId: quoteId} : {}; + var urls = { + 'guest': '/guest-carts/' + quoteId + '/coupons/' + couponCode, + 'customer': '/carts/mine/coupons/' + couponCode + }; + return this.getUrl(urls, params); + }, + + getCancelCouponUrl: function(quoteId) { + var params = (this.getCheckoutMethod() == 'guest') ? {quoteId: quoteId} : {}; + var urls = { + 'guest': '/guest-carts/' + quoteId + '/coupons/', + 'customer': '/carts/mine/coupons/' + }; + return this.getUrl(urls, params); + }, + + getUrlForCartTotals: function(quote) { + var params = (this.getCheckoutMethod() == 'guest') ? {quoteId: quote.getQuoteId()} : {}; + var urls = { + 'guest': '/guest-carts/:quoteId/totals', + 'customer': '/carts/mine/totals' + }; + return this.getUrl(urls, params); + }, + + getUrlForSetShippingInformation: function(quote) { + var params = (this.getCheckoutMethod() == 'guest') ? {cartId: quote.getQuoteId()} : {}; + var urls = { + 'guest': '/carts/:cartId/shipping-information', + 'customer': '/carts/mine/shipping-information' + }; + return this.getUrl(urls, params); + }, + + /** Get url for service */ + getUrl: function(urls, urlParams) { + var url; + + if (utils.isEmpty(urls)) { + return 'Provided service call does not exist.'; + } + + if (!utils.isEmpty(urls['default'])) { + url = urls['default']; + } else { + url = urls[this.getCheckoutMethod()]; + } + return urlBuilder.createUrl(url, urlParams); + }, + + getCheckoutMethod: function() { + return customer.isLoggedIn() ? 'customer' : 'guest'; + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-address/form-popup-state.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-address/form-popup-state.js new file mode 100644 index 0000000000000000000000000000000000000000..d23e82ca703bab7e787a5f47b0027612b4111998 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-address/form-popup-state.js @@ -0,0 +1,16 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'ko' + ], + function(ko) { + 'use strict'; + return { + isVisible: ko.observable(false) + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/customer-address.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/customer-address.js new file mode 100644 index 0000000000000000000000000000000000000000..068891a5286964d5dedb4b8812669e45a6f3b5ca --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/customer-address.js @@ -0,0 +1,51 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'Magento_Checkout/js/model/resource-url-manager', + 'Magento_Checkout/js/model/quote', + 'mage/storage', + 'Magento_Checkout/js/model/shipping-service', + 'Magento_Checkout/js/model/shipping-rate-registry', + 'Magento_Ui/js/model/messageList' + ], + function (resourceUrlManager, quote, storage, shippingService, rateRegistry, messageList) { + "use strict"; + return { + getRates: function(address) { + var cache = rateRegistry.get(address.getKey()); + if (cache) { + shippingService.setShippingRates(cache); + } else { + shippingService.isLoading(true); + storage.post( + resourceUrlManager.getUrlForEstimationShippingMethodsByAddressId(), + JSON.stringify({ + addressId: address.customerAddressId + }), + false + ).done( + function(result) { + rateRegistry.set(address.getKey(), result); + shippingService.setShippingRates(result); + } + + ).fail( + function(response) { + var error = JSON.parse(response.responseText); + messageList.addErrorMessage(error); + shippingService.setShippingRates([]) + } + ).always( + function () { + shippingService.isLoading(false); + } + ); + } + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/new-address.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/new-address.js new file mode 100644 index 0000000000000000000000000000000000000000..db5052ca0c39f44ddf2ed115ac1d7d94631f2c34 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-processor/new-address.js @@ -0,0 +1,61 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'Magento_Checkout/js/model/resource-url-manager', + 'Magento_Checkout/js/model/quote', + 'mage/storage', + 'Magento_Checkout/js/model/shipping-service', + 'Magento_Checkout/js/model/shipping-rate-registry', + 'Magento_Ui/js/model/messageList' + ], + function (resourceUrlManager, quote, storage, shippingService, rateRegistry, messageList) { + 'use strict'; + + return { + /** + * Get shipping rates for specified address. + * @param {Object} address + */ + getRates: function (address) { + var cache = rateRegistry.get(address.getCacheKey()), + serviceUrl = resourceUrlManager.getUrlForEstimationShippingMethodsForNewAddress(quote), + payload = JSON.stringify({ + address: { + country_id: address.countryId, + region_id: address.regionId, + region: address.region, + postcode: address.postcode + } + } + ); + + if (cache) { + shippingService.setShippingRates(cache); + } else { + shippingService.isLoading(true); + storage.post( + serviceUrl, payload, false + ).done( + function (result) { + rateRegistry.set(address.getCacheKey(), result); + shippingService.setShippingRates(result); + } + ).fail( + function (response) { + var error = JSON.parse(response.responseText); + messageList.addErrorMessage(error); + shippingService.setShippingRates([]); + } + ).always( + function () { + shippingService.isLoading(false); + } + ); + } + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-registry.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-registry.js new file mode 100644 index 0000000000000000000000000000000000000000..e5bd1104b1714d89fa4db7bc2893e604e3ea633a --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-registry.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function() { + "use strict"; + var cache = []; + return { + get: function(addressKey) { + if (cache[addressKey]) { + return cache[addressKey]; + } + return false; + }, + set: function(addressKey, data) { + cache[addressKey] = data; + } + }; + } +); \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-service.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-service.js new file mode 100644 index 0000000000000000000000000000000000000000..68bc173215923fff08510790811e5270f4ef5328 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rate-service.js @@ -0,0 +1,34 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true*/ +/*global define*/ +define( + [ + 'Magento_Checkout/js/model/shipping-rate-processor/new-address', + 'Magento_Checkout/js/model/shipping-rate-processor/customer-address' + ], + function(defaultProcessor, customerAddressProcessor) { + "use strict"; + var processors = []; + processors['default'] = defaultProcessor; + processors['customer-address'] = customerAddressProcessor; + + return { + registerProcessor: function(type, processor) { + processors[type] = processor; + }, + getRates: function (address) { + var type = address.getType(); + var rates = []; + if (processors[type]) { + rates = processors[type].getRates(address); + } else { + rates = processors['default'].getRates(address); + } + return rates; + } + } + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validation-rules.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validation-rules.js new file mode 100644 index 0000000000000000000000000000000000000000..e6eafeee848e544635b8bb1b97ac345b76b52854 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validation-rules.js @@ -0,0 +1,35 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + ['jquery'], + function ($) { + "use strict"; + var ratesRules = {}; + var checkoutConfig = window.checkoutConfig; + return { + registerRules: function(carrier, rules) { + if (checkoutConfig.activeCarriers.indexOf(carrier) != -1) { + ratesRules[carrier] = rules.getRules(); + } + }, + getRules: function() { + return ratesRules; + }, + getObservableFields: function() { + var self = this; + var observableFields = []; + $.each(self.getRules(), function(carrier, fields) { + $.each(fields, function(field, rules) { + if (observableFields.indexOf(field) == -1) { + observableFields.push(field); + } + }); + }); + return observableFields; + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..7bd072008705968c57080a089666f07968355fb8 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-rates-validator.js @@ -0,0 +1,122 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'ko', + './shipping-rates-validation-rules', + '../model/address-converter', + '../action/select-shipping-address', + './postcode-validator', + 'mage/translate' + ], + function ($, ko, shippingRatesValidationRules, addressConverter, selectShippingAddress, postcodeValidator, $t) { + 'use strict'; + var checkoutConfig = window.checkoutConfig; + var validators = []; + var observedElements = []; + var postcodeElement = null; + + return { + validateAddressTimeout: 0, + validateDelay: 2000, + + registerValidator: function(carrier, validator) { + if (checkoutConfig.activeCarriers.indexOf(carrier) != -1) { + validators.push(validator); + } + }, + + validateAddressData: function(address) { + return validators.some(function(validator) { + return validator.validate(address); + }); + }, + + bindChangeHandlers: function(elements) { + var self = this; + var observableFields = shippingRatesValidationRules.getObservableFields(); + $.each(elements, function(index, elem) { + if (elem && observableFields.indexOf(elem.index) != -1) { + if (elem.index !== 'postcode') { + self.bindHandler(elem); + } + } + + if (elem.index === 'postcode') { + self.bindHandler(elem); + postcodeElement = elem; + } + }); + }, + + bindHandler: function(element) { + var self = this; + if (element.component.indexOf('/group') != -1) { + $.each(element.elems(), function(index, elem) { + self.bindHandler(elem); + }); + } else { + element.on('value', function() { + clearTimeout(self.validateAddressTimeout); + self.validateAddressTimeout = setTimeout(function() { + if (self.postcodeValidation()) { + self.validateFields(); + } + }, self.validateDelay); + }); + observedElements.push(element); + } + }, + + postcodeValidation: function() { + if (postcodeElement == null || postcodeElement.value() == null) { + return true; + } + + var countryId = $('select[name="shippingAddress[country_id]"]').val(); + var validationResult = postcodeValidator.validate(postcodeElement.value(), countryId); + + postcodeElement.error(null); + if (!validationResult) { + var errorMessage = $t('Invalid Zip/Postal code for current country!'); + if (postcodeValidator.validatedPostCodeExample.length) { + errorMessage += $t(' Example: ') + postcodeValidator.validatedPostCodeExample.join('; '); + } + postcodeElement.error(errorMessage); + } + return validationResult; + }, + + /** + * Convert form data to quote address and validate fields for shipping rates + */ + validateFields: function() { + var addressFlat = addressConverter.formDataProviderToFlatData( + this.collectObservedData(), + 'shippingAddress' + ); + if (this.validateAddressData(addressFlat)) { + var address = addressConverter.formAddressDataToQuoteAddress(addressFlat); + selectShippingAddress(address); + } + }, + + /** + * Collect observed fields data to object + * + * @returns {*} + */ + collectObservedData: function() { + var observedValues = {}; + $.each(observedElements, function(index, field) { + observedValues[field.dataScope] = field.value(); + }); + return observedValues; + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor.js new file mode 100644 index 0000000000000000000000000000000000000000..8789ad0ccb38841da2fa7c900e1bee380fbc19e7 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor.js @@ -0,0 +1,31 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true*/ +/*global define*/ +define( + [ + 'Magento_Checkout/js/model/shipping-save-processor/default' + ], + function(defaultProcessor) { + 'use strict'; + var processors = []; + processors['default'] = defaultProcessor; + + return { + registerProcessor: function(type, processor) { + processors[type] = processor; + }, + saveShippingInformation: function (type) { + var rates = []; + if (processors[type]) { + rates = processors[type].saveShippingInformation(); + } else { + rates = processors['default'].saveShippingInformation(); + } + return rates; + } + } + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js new file mode 100644 index 0000000000000000000000000000000000000000..7233d429dc0691907a04b174452db883dbdc24df --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js @@ -0,0 +1,46 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define,alert*/ +define( + [ + 'ko', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/resource-url-manager', + 'mage/storage', + 'Magento_Checkout/js/model/payment-service', + 'Magento_Checkout/js/model/payment/method-converter', + 'Magento_Ui/js/model/messageList' + ], + function (ko, quote, resourceUrlManager, storage, paymentService, methodConverter, messageList) { + 'use strict'; + + return { + saveShippingInformation: function() { + var payload = { + addressInformation: { + shipping_address: quote.shippingAddress(), + shipping_method_code: quote.shippingMethod().method_code, + shipping_carrier_code: quote.shippingMethod().carrier_code + } + }; + + return storage.post( + resourceUrlManager.getUrlForSetShippingInformation(quote), + JSON.stringify(payload) + ).done( + function (response) { + quote.setTotals(response.totals); + paymentService.setPaymentMethods(methodConverter(response.payment_methods)); + } + ).fail( + function (response) { + var error = JSON.parse(response.responseText); + messageList.addErrorMessage(error); + } + ); + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-service.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-service.js index 8bb0366111a7aa7002bf81a1932cbea8ec1582de..f03da90e2fade9119bbfb16dbcced239f13572c8 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-service.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-service.js @@ -4,46 +4,63 @@ */ /*global define*/ define( - ['ko', 'jquery'], - function (ko, $) { + [ + 'ko', + 'Magento_Checkout/js/action/select-shipping-method', + 'Magento_Checkout/js/model/quote', + 'jquery' + ], + function (ko, selectShippingMethodAction, quote, $) { "use strict"; - var rates = ko.observable([]); + var shippingRates = ko.observableArray([]); return { - shippingRates: ko.observableArray([]), + isLoading: ko.observable(false), + /** + * Set shipping rates + * + * @param ratesData + */ setShippingRates: function(ratesData) { - var self = this; - rates(ratesData); - self.shippingRates([]); - $.each(ratesData, function (key, entity) { - var rateEntity = {}; - rateEntity.items = []; - if (!ratesData.hasOwnProperty(entity.carrier_code)) { - rateEntity['carrier_code'] = entity.carrier_code; - rateEntity['carrier_title'] = entity.carrier_title; - } - rateEntity.items.push(entity); - self.shippingRates.push(rateEntity); - }); + shippingRates(ratesData); + shippingRates.valueHasMutated(); + if (ratesData.length == 1) { + //set shipping rate if we have only one available shipping rate + selectShippingMethodAction(ratesData[0]); + } else if(quote.shippingMethod()) { + var rateIsAvailable = ratesData.some(function (rate) { + if (rate.carrier_code == quote.shippingMethod().carrier_code + && rate.method_code == quote.shippingMethod().method_code) { + return true; + } + return false; + }); + //Unset selected shipping shipping method if not available + if (!rateIsAvailable) { + selectShippingMethodAction(null); + } + } }, + + /** + * Get shipping rates + * + * @returns {*} + */ getSippingRates: function() { - return this.shippingRates; + return shippingRates; }, - getTitleByCode: function(methodCodeParts) { - var shippingMethodTitle = '', shippingMethodCode, carrierCode, methodCode; - if (!methodCodeParts) { - return shippingMethodTitle; - } - shippingMethodCode = methodCodeParts.slice(0); - carrierCode = shippingMethodCode.shift(); - methodCode = shippingMethodCode.join('_'); - $.each(rates(), function (key, entity) { - if (entity['carrier_code'] === carrierCode && entity['method_code'] === methodCode) { - shippingMethodTitle = entity['carrier_title'] + " - " + entity['method_title']; - } - }); - return shippingMethodTitle; + + /** + * Get shipping method title + * + * @param shippingMethod + * @returns {string} + */ + getTitleByCode: function(shippingMethod) { + return shippingMethod ? shippingMethod.carrier_title + " - " + shippingMethod.method_title : ''; }, + getRateByCode : function(methodCodeParts) { var shippingRates = [], shippingMethodCode = methodCodeParts.slice(0), diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/step-navigator.js b/app/code/Magento/Checkout/view/frontend/web/js/model/step-navigator.js index 44a48fa893285ea45161b23c6a402466921a1f06..0ce40c7999a80c32cfdb08b3c0ece8a261df3bdb 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/step-navigator.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/step-navigator.js @@ -7,198 +7,89 @@ define( [ 'jquery', - 'ko', - 'Magento_Customer/js/model/customer', - 'Magento_Ui/js/model/errorlist' + 'ko' ], - function($, ko, customer, errorList) { - var customerIsLoggedIn = customer.isLoggedIn()(); - var defaultStepClass = 'section'; - var allowedStepClass = 'allow'; - var activeStepClass = 'active'; + function($, ko) { + var steps = ko.observableArray(); + return { - currentStep: null, - steps: [ - { - name: 'authentication', - isVisible: ko.observable(!customerIsLoggedIn), - isEnabled: true, - number: ko.observable(1), - classAttributes: ko.observable(defaultStepClass) - }, - { - name: 'billingAddress', - isVisible: ko.observable(customerIsLoggedIn), - isEnabled: true, - number: ko.observable(2), - classAttributes: ko.observable(defaultStepClass) - }, - { - name: 'shippingAddress', - isVisible: ko.observable(false), - isEnabled: true, - number: ko.observable(3), - classAttributes: ko.observable(defaultStepClass) - }, - { - name: 'shippingMethod', - isVisible: ko.observable(false), - isEnabled: true, - number: ko.observable(4), - classAttributes: ko.observable(defaultStepClass) - }, - { - name: 'paymentMethod', - isVisible: ko.observable(false), - isEnabled: true, - number: ko.observable(5), - classAttributes: ko.observable(defaultStepClass) - }, - { - name: 'review', - isVisible: ko.observable(false), - isEnabled: true, - number: ko.observable(6), - classAttributes: ko.observable(defaultStepClass) - } - ], - setCurrent: function(step) { - this.currentStep = step; - return this; - }, - getCurrentStep: function() { - if (!this.currentStep) { - alert('Current step not set.'); - return; - } - var self = this; - var currentStep = null; - $.each(this.steps, function(key, step) { - if (self.currentStep == step.name) { - currentStep = step; - } + steps: steps, + stepCodes: [], + registerStep: function(code, title, isVisible, sortOrder) { + steps.push({ + code: code, + title : title, + isVisible: isVisible, + sortOrder: sortOrder }); - return currentStep; - }, - goNext: function() { - var currentStep = this.getCurrentStep(); - var nextStepOrder = currentStep.number() + 1; - var nextStep = null; - $.each(this.steps, function(key, item) { - if (nextStepOrder == item.number()) { - nextStep = item; - return false; + this.stepCodes.push(code); + }, + + sortItems: function(itemOne, itemTwo) { + return itemOne.sortOrder > itemTwo.sortOrder ? 1 : -1 + }, + + getActiveItemIndex: function() { + var activeIndex = 0; + steps.sort(this.sortItems).forEach(function(element, index) { + if (element.isVisible()) { + activeIndex = index; } }); - if (nextStep) { - this.toStep(nextStep.name); - } - }, - goBack: function() { - var currentStep = this.getCurrentStep(); - var prevStepOrder = currentStep.number() - 1; - var previousStep = null; - $.each(this.steps, function(key, item) { - if (prevStepOrder == item.number()) { - previousStep = item; - return false; - } - }); - if (previousStep) { - this.toStep(previousStep.name); - } - }, - getStepClassAttributes: function(name) { - return this.findStepByName(name).classAttributes; - }, - setStepClassAttributes: function(name) { - var stepClass = defaultStepClass; - var step = this.findStepByName(name); - if (step.isVisible()) { - stepClass += ' ' + activeStepClass; - } - if (this.isStepAvailable(step.name)) { - stepClass += ' ' + allowedStepClass; - } - step.classAttributes(stepClass); - }, - updateStepsClassAttributes: function() { - var self = this; - $.each(this.steps, function(key, step) { - var stepClass = defaultStepClass; - if (step.isVisible()) { - stepClass += ' ' + activeStepClass; - } - if (self.isStepAvailable(step.name)) { - stepClass += ' ' + allowedStepClass; + return activeIndex; + }, + + isProcessed: function(code) { + var activeItemIndex = this.getActiveItemIndex(); + var sortedItems = steps.sort(this.sortItems); + var requestedItemIndex = -1; + sortedItems.forEach(function(element, index) { + if (element.code == code) { + requestedItemIndex = index; } - step.classAttributes(stepClass); }); + return activeItemIndex > requestedItemIndex; }, - isStepAvailable: function(name) { - var visibleStep = this.getCurrentVisibleStep(); - var step = this.findStepByName(name); - return (step.number() < visibleStep.number()); - }, - goToStep: function(name) { - if (this.isStepAvailable(name)) { - this.toStep(name); - } - }, - toStep: function(name) { - if (name) { - $.each(this.steps, function(key, step) { - step.isVisible(false); - }); - this.findStepByName(name).isVisible(true); - this.updateStepsClassAttributes(); - errorList.clear(); + + navigateTo: function(step) { + var sortedItems = steps.sort(this.sortItems); + if (!this.isProcessed(step.code)) { + return; } - }, - findStepByName: function(name) { - var step = null; - $.each(this.steps, function(key, currentStep) { - if (name == currentStep.name) { - step = currentStep; - return false; + sortedItems.forEach(function(element) { + if (element.code == step.code) { + element.isVisible(true); + } else { + element.isVisible(false); } + }); - return step; }, - isStepVisible: function(step) { - this.setStepClassAttributes(step); - return this.findStepByName(step).isVisible; - }, - setStepVisible: function(step, flag) { - this.findStepByName(step).isVisible(flag); - }, - getCurrentVisibleStep: function() { - var step = null; - $.each(this.steps, function(key, currentStep) { - if (currentStep.isVisible()) { - step = currentStep; - return false; + + next: function() { + var activeIndex = 0; + steps.sort(this.sortItems).forEach(function(element, index) { + if (element.isVisible()) { + element.isVisible(false); + activeIndex = index; } }); - return step; - }, - setStepEnabled: function(step, flag) { - this.findStepByName(step).isEnabled = flag; - this.refreshStepsNumbers(); + if (steps().length > activeIndex + 1) { + steps()[activeIndex + 1].isVisible(true); + } }, - refreshStepsNumbers: function() { - var numb = 1; - $.each(this.steps, function(key, item) { - if (item.isEnabled) { - item.number(numb); - numb++; - } else { - item.number(null); + + back: function() { + var activeIndex = 0; + steps.sort(this.sortItems).forEach(function(element, index) { + if (element.isVisible()) { + element.isVisible(false); + activeIndex = index; } }); - }, - getStepNumber: function(name) { - return this.findStepByName(name).number; + if (steps()[activeIndex - 1]) { + steps()[activeIndex - 1].isVisible(true); + } } }; } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js b/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js new file mode 100644 index 0000000000000000000000000000000000000000..f32c0d2c15f3c40a2ea1468ac5c13d0e4b74da90 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js @@ -0,0 +1,37 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'ko', + 'Magento_Checkout/js/model/quote' + ], + function(ko, quote) { + + return { + totals: quote.totals, + isLoading: ko.observable(false), + getItems: function() { + if (!this.totals() || !this.totals().items) { + return []; + } + return this.totals().items; + }, + getSegment: function(code) { + if (!this.totals()) { + return null; + } + for (var i in this.totals().total_segments) { + var total = this.totals().total_segments[i]; + if (total.code == code) { + return total; + } + } + return null; + } + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/proceed-to-checkout.js b/app/code/Magento/Checkout/view/frontend/web/js/proceed-to-checkout.js new file mode 100644 index 0000000000000000000000000000000000000000..87794967ddff9501e2fba69a01fa8644decf056c --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/proceed-to-checkout.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'Magento_Checkout/js/model/cart/authentication-popup', + 'Magento_Customer/js/customer-data' + ], + function($, authenticationPopup, customerData) { + return function (config, element) { + $(element).click(function(event) { + event.preventDefault(); + var cart = customerData.get('cart'), + customer = customerData.get('customer'); + + if (customer() == false && !cart().isGuestCheckoutAllowed) { + authenticationPopup.showModal(); + return false; + } + location.href = window.checkout.checkoutUrl; + }); + + }; + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js index 2455c3932eabaeee72ba2ec5997a0ed9a35b5732..5f93022da11a9089f3ef90ebef20ef2057529a56 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js @@ -6,9 +6,11 @@ /*global confirm:true*/ define([ "jquery", + 'Magento_Checkout/js/model/cart/authentication-popup', + 'Magento_Customer/js/customer-data', "jquery/ui", "mage/decorate" -], function($){ +], function($, authenticationPopup, customerData){ $.widget('mage.sidebar', { options: { @@ -32,6 +34,13 @@ define([ }); $(this.options.button.checkout).on('click', $.proxy(function() { + var cart = customerData.get('cart'), + customer = customerData.get('customer'); + + if (customer() == false && !cart().isGuestCheckoutAllowed) { + authenticationPopup.showModal(); + return false; + } location.href = this.options.url.checkout; }, this)); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/authentication.js b/app/code/Magento/Checkout/view/frontend/web/js/view/authentication.js index 44018161f3eeabaf1969bd9e06558db266b13fd7..b921592e718ca5fc134113209f8a39e2624f68d3 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/authentication.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/authentication.js @@ -6,66 +6,43 @@ /*global alert*/ define( [ - "jquery", - 'ko', + 'jquery', 'Magento_Ui/js/form/form', 'Magento_Customer/js/action/login', 'Magento_Customer/js/model/customer', - 'Magento_Checkout/js/model/step-navigator', - '../model/quote', 'mage/validation' ], - function($, ko, Component, login, customer, navigator, quote) { - "use strict"; - var stepName = 'authentication'; + function($, Component, loginAction, customer) { + 'use strict'; + var checkoutConfig = window.checkoutConfig; + return Component.extend({ - stepNumber: navigator.getStepNumber(stepName), - isGuestCheckoutAllowed: window.checkoutConfig.isGuestCheckoutAllowed, - isCustomerLoginRequired: window.checkoutConfig.isCustomerLoginRequired, - registerUrl: window.checkoutConfig.registerUrl, - forgotPasswordUrl: window.checkoutConfig.forgotPasswordUrl, - username: '', - password: '', - isVisible: navigator.isStepVisible(stepName), + isGuestCheckoutAllowed: checkoutConfig.isGuestCheckoutAllowed, + isCustomerLoginRequired: checkoutConfig.isCustomerLoginRequired, + registerUrl: checkoutConfig.registerUrl, + forgotPasswordUrl: checkoutConfig.forgotPasswordUrl, defaults: { template: 'Magento_Checkout/authentication' }, + + /** Is login form enabled for current customer */ + isActive: function() { + return !customer.isLoggedIn(); + }, + + /** Provide login action */ login: function(loginForm) { - var loginData = {}; - var formDataArray = $(loginForm).serializeArray(); - var loginFormSelector = 'form[data-role=login]'; + var loginData = {}, + formDataArray = $(loginForm).serializeArray(); + formDataArray.forEach(function (entry) { loginData[entry.name] = entry.value; }); - if($(loginFormSelector).validation() && $(loginFormSelector).validation('isValid')) { - login(loginData); - } - }, - stepClassAttributes: function() { - return navigator.getStepClassAttributes(stepName); - }, - isActive: function() { - if (customer.isLoggedIn()()) { - navigator.setStepEnabled(stepName, false); - } - return !customer.isLoggedIn()(); - }, - isChecked: function() { - if (!isGuestCheckoutAllowed) { - return 'register'; - } - return false; - }, - setCheckoutMethod: function() { - quote.setCheckoutMethod('guest'); - $('[name="customerDetails.password"]').hide(); - $('[name="customerDetails.confirm_password"]').hide(); - $('[name*=".save_in_address_book"]').hide(); - navigator.setCurrent('authentication').goNext(); - }, - navigateToCurrentStep: function() { - if (!navigator.isStepVisible(stepName)()) { - navigator.goToStep(stepName); + + if($(loginForm).validation() + && $(loginForm).validation('isValid') + ) { + loginAction(loginData); } } }); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/beforePlaceOrder.js b/app/code/Magento/Checkout/view/frontend/web/js/view/beforePlaceOrder.js index b84bed5619b32ec51ddd662dee71f4c65926f0c7..8424c7a9161db3a2eaefb81515920bc1d8202b9f 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/beforePlaceOrder.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/beforePlaceOrder.js @@ -9,7 +9,6 @@ define( "use strict"; return Component.extend({ defaults: { - template: 'Magento_Checkout/review/iterator', displayArea: 'beforePlaceOrder' } }); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js b/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js index ebb20378def25789c4011acbd530a9b6e62da8ee..2ca86001d726002b81df9f2c6adc83bac7443080 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js @@ -6,127 +6,112 @@ /*global define*/ define( [ - "jquery", - 'Magento_Ui/js/form/form', 'ko', + 'Magento_Ui/js/form/form', 'Magento_Customer/js/model/customer', - '../action/select-billing-address', - '../model/step-navigator', - '../model/quote', - '../model/addresslist' + 'Magento_Customer/js/model/address-list', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/action/create-billing-address', + 'Magento_Checkout/js/action/select-billing-address', + 'mage/translate' ], - function ($, Component, ko, customer, selectBillingAddress, navigator, quote, addressList) { + function (ko, Component, customer, addressList, quote, createBillingAddress, selectBillingAddress, $t) { "use strict"; - var stepName = 'billingAddress'; - var newAddressSelected = ko.observable(false); - var billingFormSelector = '#co-billing-form'; + + var newAddressOption = { + getAddressInline: function() { + return $t('New Address'); + }, + customerAddressId: null + }; + var addressOptions = addressList().filter(function(address, index, addresses) { + return address.getType() == 'customer-address'; + }); + addressOptions.push(newAddressOption); return Component.extend({ defaults: { template: 'Magento_Checkout/billing-address' }, + initObservable: function () { - this._super().observe('useForShipping'); + this._super() + .observe({ + selectedAddress: null, + isAddressDetailsVisible: quote.shippingAddress() != null, + isAddressFormVisible: !customer.isLoggedIn() || addressOptions.length == 1, + isAddressSameAsShipping: false + }); + quote.billingAddress.subscribe(function(newAddress) { + this.isAddressSameAsShipping(newAddress == quote.shippingAddress() && !quote.isVirtual()); + this.isAddressDetailsVisible(true); + }, this); return this; }, - stepClassAttributes: function() { - return navigator.getStepClassAttributes(stepName); - }, - stepNumber: navigator.getStepNumber(stepName), - billingAddresses: function() { - var newAddress = { - getAddressInline: function() { - return $.mage.__('New address'); - }, - customerAddressId: null - }, - addresses = addressList.getAddresses(); - addresses.push(newAddress); - return addresses; - }, - selectedBillingAddressId: ko.observable( - addressList.getAddresses().length ? addressList.getAddresses()[0].customerAddressId : null - ), - isVisible: navigator.isStepVisible(stepName), - useForShipping: "1", - quoteIsVirtual: quote.isVirtual(), - billingAddressesOptionsText: function(item) { - return item.getAddressInline(); + + canUseShippingAddress: ko.computed(function(){ + return !quote.isVirtual() && quote.shippingAddress() + && quote.shippingAddress().canUseForBilling(); + }), + + saveInAddressBook: true, + + currentBillingAddress: quote.billingAddress, + + addressOptions: addressOptions, + + customerHasAddresses: addressOptions.length > 1, + + addressOptionsText: function(address) { + return address.getAddressInline(); }, - checkUseForShipping: function(useForShipping) { - var additionalData = {}; - if (useForShipping() instanceof Object) { - additionalData = useForShipping().getAdditionalData(); - useForShipping('1'); + + useShippingAddress: function () { + if (this.isAddressSameAsShipping()) { + selectBillingAddress(quote.shippingAddress()); + this.isAddressDetailsVisible(true); + } else { + this.isAddressDetailsVisible(false); } - return additionalData; + return true; }, - submitBillingAddress: function() { - var additionalData = this.checkUseForShipping(this.useForShipping); - if (this.selectedBillingAddressId()) { - selectBillingAddress( - addressList.getAddressById(this.selectedBillingAddressId()), - this.useForShipping, - additionalData - ); + + updateAddress: function () { + if (this.selectedAddress() && this.selectedAddress() != newAddressOption) { + selectBillingAddress(this.selectedAddress()); } else { - this.validate(); + this.source.set('params.invalid', false); + this.source.trigger(this.dataScopePrefix + '.data.validate'); if (!this.source.get('params.invalid')) { - var addressData = this.source.get('billingAddress'); - /** - * All the the input fields that are not a part of the address (e. g. CAPTCHA) but need to be - * submitted in the same request must have data-scope attribute set - */ - var additionalFields = $('input[data-scope="additionalAddressData"]').serializeArray(); - additionalFields.forEach(function (field) { - additionalData[field.name] = field.value; - }); - if (quote.getCheckoutMethod()() && !customer.isLoggedIn()()) { - addressData.email = this.source.get('customerDetails.email'); - } - if($(billingFormSelector).validation() && $(billingFormSelector).validation('isValid')) { - selectBillingAddress(addressData, this.useForShipping, additionalData); + var addressData = this.source.get(this.dataScopePrefix); + + if (this.isCustomerLoggedIn && !this.customerHasAddresses) { + this.saveInAddressBook = true; } + addressData.save_in_address_book = this.saveInAddressBook; + + // New address must be selected as a billing address + selectBillingAddress(createBillingAddress(addressData)); } } }, - navigateToCurrentStep: function() { - if (!navigator.isStepVisible(stepName)()) { - navigator.goToStep(stepName); - } - }, - isNewAddressSelected: function() { - if (!this.customerAddressCount) { - return true; - } - return newAddressSelected(); - }, - onAddressChange: function (value) { - value() === null ? newAddressSelected(true) : newAddressSelected(false); + + editAddress: function () { + this.isAddressDetailsVisible(false); }, - validate: function() { - var fields = $(billingFormSelector).find('input, select'); - - this.source.set('params.invalid', false); - fields.trigger('change'); - this.source.trigger('billingAddress.data.validate'); - if (!customer.isLoggedIn()()) { - this.source.trigger('customerDetails.data.validate'); + + cancelAddressEdit: function () { + if (quote.billingAddress()) { + // restore 'Same As Shipping' checkbox state + this.isAddressSameAsShipping( + !quote.isVirtual() && (quote.shippingAddress() == quote.billingAddress()) + ); + this.isAddressDetailsVisible(true); } - this.validateAdditionalAddressFields(); }, - validateAdditionalAddressFields: function() { - $(billingFormSelector).validation(); - $(billingFormSelector + ' input[data-scope="additionalAddressData"]').each(function(key, item) { - $(item).valid(); - }); - }, - isCustomerLoggedIn: customer.isLoggedIn(), - customerAddressCount: window.checkoutConfig.customerAddressCount, - hideExtraFields: function() { - if (!quote.getCheckoutMethod()() && customer.isLoggedIn()()) { - $('[name="customerDetails.email"]').hide(); - } + + onAddressChange: function (address) { + this.isAddressFormVisible(address == newAddressOption); } }); } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/cart/authentication.js b/app/code/Magento/Checkout/view/frontend/web/js/view/cart/authentication.js new file mode 100644 index 0000000000000000000000000000000000000000..0985d990a697bde35a780beb7d318895548e9103 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/cart/authentication.js @@ -0,0 +1,71 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'jquery', + 'ko', + 'Magento_Ui/js/form/form', + 'Magento_Customer/js/action/login', + 'Magento_Customer/js/customer-data', + 'Magento_Checkout/js/model/cart/authentication-popup', + 'mage/translate', + 'mage/validation' + ], + function($, ko, Component, loginAction, customerData, authenticationPopup, $t) { + 'use strict'; + return Component.extend({ + registerUrl: window.checkout.customerRegisterUrl, + forgotPasswordUrl: window.checkout.customerForgotPasswordUrl, + modalWindow: null, + isLoading: ko.observable(false), + + initialize: function() { + var self = this; + this._super(); + loginAction.registerLoginCallback(function() { + self.isLoading(false); + }); + }, + + /** Init popup login window */ + setModalElement: function (element) { + authenticationPopup.createPopUp(element); + }, + + /** Is login form enabled for current customer */ + isActive: function() { + var customer = customerData.get('customer'); + return customer() == false; + }, + + /** Show login popup window */ + showModal: function() { + if (this.modalWindow) { + $(this.modalWindow).modal('openModal'); + } else { + alert($t('Guest checkout is disabled.')); + } + }, + + /** Provide login action */ + login: function(loginForm) { + var loginData = {}, + formDataArray = $(loginForm).serializeArray(); + formDataArray.forEach(function (entry) { + loginData[entry.name] = entry.value; + }); + + if($(loginForm).validation() + && $(loginForm).validation('isValid') + ) { + this.isLoading(true); + loginAction(loginData); + } + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/columns.js b/app/code/Magento/Checkout/view/frontend/web/js/view/columns.js deleted file mode 100644 index 85a2097532024573de71c8f0295bd0f6a2e8dc45..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/columns.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'uiComponent' - ], - function (Component) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/review/iterator', - displayArea: 'columns' - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/discount.js b/app/code/Magento/Checkout/view/frontend/web/js/view/discount.js deleted file mode 100644 index f2a959dfcdb510885a209738efc74ef0b8372cf4..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/discount.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*global define*/ -define( - [ - 'uiComponent', - 'Magento_Checkout/js/model/quote', - 'Magento_Catalog/js/price-utils' - ], - function (Component, quote, priceUtils) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/review/discount', - displayArea: 'totals' - }, - colspan: 3, - style: '', - fieldName: 'Discount', - totals: quote.getTotals(), - getPureValue: function() { - var price = 0; - if (this.totals()) { - price = this.totals().discount_amount; - } - return price; - }, - getValue: function() { - var price = 0; - if (this.totals()) { - price = this.totals().discount_amount; - } - return priceUtils.formatPrice(price, quote.getPriceFormat()); - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/itemsAfter.js b/app/code/Magento/Checkout/view/frontend/web/js/view/itemsAfter.js deleted file mode 100644 index ee96966658f05bc7ffb0bbe2aabd5cecb9decdb2..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/itemsAfter.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'uiComponent' - ], - function (Component) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/review/iterator', - displayArea: 'itemsAfter' - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/itemsBefore.js b/app/code/Magento/Checkout/view/frontend/web/js/view/itemsBefore.js deleted file mode 100644 index 9d2e10ce0a87aeb5bb847e5eb83e11321d9d3c79..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/itemsBefore.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'uiComponent' - ], - function (Component) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/review/iterator', - displayArea: 'itemsBefore' - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js index 373056b389e955be7f910313faf38af2e83cddbb..51e59d8ff6bb31bfb06222c8ef965cbdf19f835d 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/minicart.js @@ -6,11 +6,13 @@ define([ 'uiComponent', 'Magento_Customer/js/customer-data', 'jquery', - 'ko' -], function (Component, customerData, $, ko) { + 'ko', + 'mage/url' +], function (Component, customerData, $, ko, url) { 'use strict'; var sidebarInitialized = false; + url.setBaseUrl(window.checkout.baseUrl); function initSidebar() { var minicart = $("[data-block='minicart']"); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js index 313ba3b923d06aa5caf03cef5330f719244471af..cde7e59dad6483cd2f2c95c55b1764403f80f035 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js @@ -6,154 +6,35 @@ /*global alert*/ define( [ - 'jquery', 'uiComponent', - '../model/quote', - '../action/select-payment-method', + 'ko', + 'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/step-navigator', 'Magento_Checkout/js/model/payment-service', - 'mage/translate', - 'mageUtils' + 'Magento_Checkout/js/model/payment/method-converter' ], - function ($, Component, quote, selectPaymentMethod, navigator, paymentService, $t, utils) { - var stepName = 'paymentMethod'; + function (Component, ko, quote, stepNavigator, paymentService, methodConverter) { + 'use strict'; + + /** Set payment methods to collection */ + paymentService.setPaymentMethods(methodConverter(window.checkoutConfig.paymentMethods)); + return Component.extend({ defaults: { template: 'Magento_Checkout/payment', activeMethod: '' }, - stepClassAttributes: function() { - return navigator.getStepClassAttributes(stepName); - }, - stepNumber: navigator.getStepNumber(stepName), - isVisible: navigator.isStepVisible(stepName), - paymentForm: '#co-payment-form', - initObservable: function () { - this._super() - .observe('activeMethod'); - return this; - }, - quoteHasShippingMethod: function() { - return quote.isVirtual() || quote.getShippingMethod(); - }, - setPaymentMethod: function() { - if (!this.activeMethod()) { - alert($t('Please choose a payment method.')); - return; - } - - if (this.isFormValid()) { - selectPaymentMethod( - this.getPaymentMethodData(), - this.getPaymentMethodInfo(), - this.getPaymentMethodCallbacks() - ); - } - }, - getPaymentMethodData: function() { - var data = { - "method": this.activeMethod(), - "po_number": null, - "cc_owner": null, - "cc_number": null, - "cc_type": null, - "cc_exp_year": null, - "cc_exp_month": null, - "additional_data": null - }; - utils.extend(data, this.getActiveMethodView().getData()); - - _.each(this.getAdditionalMethods(), function(elem) { - if (elem.isActive()) { - utils.extend(data, elem.getData()); - } - }); - - return data; - }, - getPaymentMethodInfo: function() { - var info = this.getActiveMethodView().getInfo(); - - _.each(this.getAdditionalMethods(), function(elem) { - if (elem.isActive()) { - info = _.union(info, elem.getInfo()); - } - }); - - return info; - }, - getPaymentMethodCallbacks: function() { - var callbacks = [this.getActiveMethodView().afterSave.bind(this.getActiveMethodView())]; - - _.each(this.getAdditionalMethods(), function(elem) { - if (elem.isActive()) { - callbacks = _.union(callbacks, [elem.afterSave.bind(elem)]); - } - }); + isVisible: ko.observable(quote.isVirtual()), + quoteIsVirtual: quote.isVirtual(), - return callbacks; + initialize: function () { + this._super(); + stepNavigator.registerStep('billing', 'Review & Payments', this.isVisible, 20); + return this; }, - getAvailableViews: function () { - var sortedElems = [], - self = this; - - _.each(this.getAvailableMethods(), function (originElem) { - var method = self.getMethodViewByCode(originElem.code); - if (method && method.isAvailable()) { - sortedElems.push(method); - } - }); - if (sortedElems.length == 1) { - this.activeMethod(sortedElems[0].getCode()); - } - - return sortedElems; - }, - getAvailableMethods: function() { - return paymentService.getAvailablePaymentMethods(); - }, - getAvailableCodes: function() { - return _.pluck(this.getAvailableMethods(), 'code'); - }, - getMethodViewByCode: function(code) { - return _.find(this.getRegion('paymentMethods')(), function(elem) { - return elem.getCode() == code; - }); - }, - getActiveMethodView: function() { - return this.getMethodViewByCode(this.activeMethod()); - }, - backToShippingMethod: function() { - navigator.setCurrent(stepName).goBack(); - }, - navigateToCurrentStep: function() { - if (!navigator.isStepVisible(stepName)()) { - navigator.goToStep(stepName); - } - }, - isMethodActive: function(code) { - return this.activeMethod() === code; - }, - isFormValid: function() { - $(this.paymentForm).validation(); - return $(this.paymentForm).validation('isValid'); - }, getFormKey: function() { return window.checkoutConfig.formKey; - }, - getAdditionalMethods: function() { - var methods = []; - _.each(this.getRegion('beforeMethods')(), function(elem) { - methods = _.union(methods, elem.elems()); - }); - _.each(this.getRegion('afterMethods')(), function(elem) { - methods = _.union(methods, elem.elems()); - }); - return methods; - }, - getMethodControlAdditionalClass: function() { - return this.getAvailableViews().length == 1 ? ' hidden' : ''; } }); } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/default.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/default.js new file mode 100644 index 0000000000000000000000000000000000000000..7fa9e10b69a781d1f9afc86bc79ae7cc39c388d7 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/default.js @@ -0,0 +1,110 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'ko', + 'jquery', + 'uiComponent', + 'Magento_Checkout/js/action/place-order', + 'Magento_Checkout/js/action/select-payment-method', + 'Magento_Checkout/js/model/quote', + 'Magento_Customer/js/model/customer', + 'Magento_Checkout/js/model/payment-service' + ], + function (ko, $, Component, placeOrderAction, selectPaymentMethodAction, quote, customer, paymentService) { + 'use strict'; + return Component.extend({ + redirectAfterPlaceOrder: true, + /** + * Initialize view. + * + * @returns {Component} Chainable. + */ + initialize: function () { + this._super().initChildren(); + return this; + }, + + /** + * Initialize child elements + * + * @returns {Component} Chainable. + */ + initChildren: function () { + return this; + }, + + /** + * Place order. + */ + placeOrder: function () { + var emailValidationResult = customer.isLoggedIn(), + loginFormSelector = 'form[data-role=email-with-possible-login]'; + if (!customer.isLoggedIn()) { + $(loginFormSelector).validation(); + emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid()); + } + if (emailValidationResult && this.validate()) { + placeOrderAction(this.getData(), this.redirectAfterPlaceOrder); + } + }, + + selectPaymentMethod: function() { + selectPaymentMethodAction(this.getData()); + return true; + }, + + isChecked: ko.computed(function () { + return quote.paymentMethod() ? quote.paymentMethod().method : null; + }), + + isRadioButtonVisible: ko.computed(function () { + return paymentService.getAvailablePaymentMethods().length !== 1; + }), + + /** + * Get payment method data + */ + getData: function() { + return { + "method": this.item.method, + "po_number": null, + "cc_owner": null, + "cc_number": null, + "cc_type": null, + "cc_exp_year": null, + "cc_exp_month": null, + "additional_data": null + }; + }, + + /** + * Get payment method type. + */ + getTitle: function () { + return this.item.title; + }, + + /** + * Get payment method code. + */ + getCode: function () { + return this.item.method; + }, + + validate: function () { + return true; + }, + + getBillingAddressFormName: function() { + return 'billing-address-form-' + this.item.method; + }, + + disposeSubscriptions: function () { + // dispose all active subscriptions + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/generic.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/generic.js deleted file mode 100644 index 64833500f70a1919a513cb7b6362bf5cc1655be6..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/generic.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'uiComponent' - ], - function (Component) { - return Component.extend({ - getCode: function() { - return this.index; - }, - isActive: function(parent) { - return false; - }, - getData: function() { - return {}; - }, - getInfo: function() { - return []; - }, - afterSave: function() { - return true; - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js new file mode 100644 index 0000000000000000000000000000000000000000..78faf6ba156658108f4820978fba27190f2cc9a3 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/list.js @@ -0,0 +1,119 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'underscore', + 'ko', + 'mageUtils', + 'uiComponent', + 'Magento_Checkout/js/model/payment/method-list', + 'Magento_Checkout/js/model/payment/renderer-list', + 'Magento_Ui/js/core/renderer/layout' +], function (_, ko, utils, Component, paymentMethods, rendererList, layout) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_Checkout/payment-methods/list', + visible: paymentMethods().length > 0 + }, + + /** + * Initialize view. + * + * @returns {Component} Chainable. + */ + initialize: function () { + this._super().initChildren(); + paymentMethods.subscribe( + function (changes) { + _.each(changes, function (change) { + if (change.status === 'added') { + this.createRenderer(change.value); + } else if (change.status === 'deleted') { + this.removeRenderer(change.value.method); + } + }, this); + }, this, 'arrayChange'); + + return this; + }, + + /** + * Create renders for child payment methods. + * + * @returns {Component} Chainable. + */ + initChildren: function () { + var self = this; + _.each(paymentMethods(), function (paymentMethodData) { + self.createRenderer(paymentMethodData); + }); + + return this; + }, + + /** + * Create renderer. + * + * @param {Object} paymentMethodData + */ + createRenderer: function (paymentMethodData) { + var renderer = this.getRendererByType(paymentMethodData.method), + rendererTemplate, + rendererComponent, + templateData; + + if (renderer) { + templateData = { + parentName: this.name, + name: paymentMethodData.method + }; + rendererTemplate = { + parent: '${ $.$data.parentName }', + name: '${ $.$data.name }', + displayArea: 'payment-method-items', + component: renderer.component + }; + rendererComponent = utils.template(rendererTemplate, templateData); + utils.extend(rendererComponent, { + item: paymentMethodData + }); + layout([rendererComponent]); + } + }, + + /** + * Get renderer for payment method type. + * + * @param {String} paymentMethodCode + * @returns {Object} + */ + getRendererByType: function (paymentMethodCode) { + var compatibleRenderer; + _.find(rendererList(), function (renderer) { + if (renderer.type === paymentMethodCode) { + compatibleRenderer = renderer; + } + }); + + return compatibleRenderer; + }, + + /** + * Remove view renderer. + * + * @param {String} paymentMethodCode + */ + removeRenderer: function (paymentMethodCode) { + var items = this.getRegion('payment-method-items'); + _.find(items(), function (value) { + if (value.item.method === paymentMethodCode) { + value.disposeSubscriptions(); + this.removeChild(value); + } + }, this); + } + }); +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/method-info.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/method-info.js deleted file mode 100644 index c653d3f54111d7f52b031e3376bdc8db84c4dce0..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/method-info.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'Magento_Checkout/js/view/payment/generic', - '../../model/payment-service' - ], - function (generic, paymentService) { - return generic.extend({ - defaults: { - titleTemplate: 'Magento_Checkout/payment/generic-title', - displayArea: 'paymentMethods', - isEnabled: true - }, - initObservable: function () { - this._super() - .observe('isEnabled'); - return this; - }, - getMethod: function() { - var paymentMethods = _.indexBy(paymentService.getAvailablePaymentMethods(), 'code'); - - return paymentMethods[this.getCode()]; - }, - isAvailable: function() { - return this.getMethod() != null; - }, - getTitle: function() { - return this.isAvailable() ? this.getMethod()['title'] : ''; - }, - isActive: function(parent) { - return this.isAvailable() && parent.isMethodActive(this.getCode()); - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/virtual.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment/virtual.js deleted file mode 100644 index ec20c4d42179aeee395bec21babff8eda2849516..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/payment/virtual.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true*/ -/*global define*/ -define( - [ - 'ko', - 'Magento_Checkout/js/view/payment/generic', - 'Magento_Checkout/js/model/quote' - ], - function (ko, generic, quote) { - return generic.extend({ - defaults: { - isChecked: false - }, - isAvailable: function() { - return false; - }, - isOn: function() { - return false; - }, - getBalance: function() { - return 0; - }, - initObservable: function () { - this._super() - .observe('isChecked'); - - var self = this; - this.isChecked.subscribe( - function(isChecked) { - if (isChecked) { - quote.setCollectedTotals(self.getCode(), -parseFloat(self.getBalance())); - } else { - quote.setCollectedTotals(self.getCode(), 0); - } - } - ); - this.isChecked(this.isOn()); - - return this; - }, - isActive: function() { - return this.isChecked(); - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/progress-bar.js b/app/code/Magento/Checkout/view/frontend/web/js/view/progress-bar.js new file mode 100644 index 0000000000000000000000000000000000000000..626171c589d3d3aaf6ab2a06e5b3b0884fd8322a --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/progress-bar.js @@ -0,0 +1,35 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'ko', + 'uiComponent', + 'Magento_Checkout/js/model/step-navigator' + ], + function (ko, Component, stepNavigator) { + var steps = stepNavigator.steps; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/progress-bar', + visible: true + }, + steps: steps, + + sortItems: function(itemOne, itemTwo) { + return stepNavigator.sortItems(itemOne, itemTwo); + }, + + navigateTo: function(step) { + stepNavigator.navigateTo(step); + }, + + isProcessed: function(item) { + return stepNavigator.isProcessed(item.code); + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/progress.js b/app/code/Magento/Checkout/view/frontend/web/js/view/progress.js deleted file mode 100644 index 1017f9f160eeaa55c9c306bf42b1c98fd8f6d8f5..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/progress.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - 'ko', - 'uiComponent', - 'Magento_Checkout/js/model/step-navigator', - 'Magento_Checkout/js/model/quote', - 'Magento_Checkout/js/model/shipping-service', - 'Magento_Checkout/js/model/payment-service' - ], - function (ko, Component, navigator, quote, shippingService, paymentService) { - var className = ko.observable(); - return Component.extend({ - defaults: { - template: 'Magento_Checkout/progress' - }, - getClassName: function() - { - className('opc-block-progress'); - if(quote.getBillingAddress()() && (quote.getShippingAddress()()) || quote.isVirtual()) { - className('opc-block-progress active') - } - if (quote.getPaymentMethod()()) { - className('opc-block-progress order-review-step') - } - return className() - }, - - isShowStep: function (stepName) { - switch(stepName){ - case 'shippingAddress': - if (quote.isVirtual()) { - return false - } - return navigator.findStepByName(stepName).isEnabled; - break; - case 'shippingMethod': - if (quote.isVirtual()) { - return false - } - return navigator.findStepByName(stepName).isEnabled; - break; - default: - return navigator.findStepByName(stepName).isEnabled; - } - }, - isStepComplete: function(stepName) { - switch(stepName){ - case 'billingAddress': - return quote.getFormattedBillingAddress()|| false; - break; - case 'shippingAddress': - return quote.getFormattedShippingAddress()||false; - break; - case 'shippingMethod': - return quote.getShippingMethod()||false; - break; - case 'paymentMethod': - return quote.getPaymentMethod()||false; - break; - default: - return false; - } - }, - getBillingAddress: function() { - return quote.getFormattedBillingAddress()(); - }, - getShippingAddress: function() { - return quote.getFormattedShippingAddress(); - }, - getShippingMethod: function() { - return quote.getShippingMethod() - }, - getPaymentMethod: function() { - return quote.getPaymentMethod(); - }, - getPaymentMethodTitle: function() { - var code = this.getPaymentMethod()(); - return paymentService.getTitleByCode(code) - }, - getPaymentMethodInfo: function() { - return paymentService.getSelectedPaymentInfo() - }, - goToStep: function(stepName) { - navigator.goToStep(stepName); - }, - getShippingMethodTitle: function() { - var code = this.getShippingMethod()(); - return shippingService.getTitleByCode(code) - }, - getShippingRates: function() { - var code = this.getShippingMethod()(); - return shippingService.getRateByCode(code) - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/review.js b/app/code/Magento/Checkout/view/frontend/web/js/view/review.js deleted file mode 100644 index c2c9c58333f9f990073680f12e449cb67fd96471..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/review.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true jquery:true*/ -/*global define*/ -define( - [ - 'uiComponent', - 'Magento_Checkout/js/model/quote', - 'mage/url', - 'Magento_Checkout/js/model/step-navigator', - 'Magento_Checkout/js/action/place-order', - 'underscore' - ], - function (Component, quote, url, navigator, orderAction, _) { - "use strict"; - var stepName = 'review'; - var itemsBefore = []; - var itemsAfter = []; - var beforePlaceOrder = {}; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/review' - }, - stepClassAttributes: function() { - return navigator.getStepClassAttributes(stepName); - }, - stepNumber: navigator.getStepNumber(stepName), - quoteHasPaymentMethod: quote.getPaymentMethod(), - itemsBefore: itemsBefore, - itemsAfter: itemsAfter, - beforePlaceOrder: beforePlaceOrder, - getItems: function() { - return quote.getTotals()().items; - }, - getColHeaders: function() { - return ['name', 'price', 'qty', 'subtotal']; - }, - isVisible: navigator.isStepVisible(stepName), - cartUrl: url.build('checkout/cart/'), - placeOrder: function(callback) { - var component, - isValid = false; - if (_.isEmpty(this.beforePlaceOrder)) { - orderAction(null, callback); - } else { - for (component in this.beforePlaceOrder) { - if (this.beforePlaceOrder.hasOwnProperty(component) && !this.beforePlaceOrder[component].validate()) { - isValid = true; - } - } - if (isValid) { - orderAction(this.beforePlaceOrder[component].getSubmitParams(), callback); - } - } - }, - // get recalculated totals when all data set - getTotals: quote.getTotals() - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/review/actions.js b/app/code/Magento/Checkout/view/frontend/web/js/view/review/actions.js index e160151929985e6a859950e7c33141c7bead36a1..595871bc061e3c513341892fa5f83300e5a8836f 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/review/actions.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/review/actions.js @@ -17,7 +17,7 @@ define( displayArea: 'actions' }, getActiveView: function() { - var view = this.getViewByCode(quote.getPaymentMethod()()); + var view = this.getViewByCode(quote.paymentMethod()); return view ? view : this.getDefaultView(); }, getViewByCode: function(code) { diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/column.js b/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/column.js deleted file mode 100644 index 3c80b6595f9ef83703676ed7f2c5954da1fd4ac8..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/column.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'uiComponent', - '../../../model/quote', - 'Magento_Catalog/js/price-utils' - ], - function (Component, quote, priceUtils) { - "use strict"; - var ownClass = ''; - var columnTitle = ''; - return Component.extend({ - defaults: { - headerClass: null, - ownClass: ownClass, - columnTitle: columnTitle, - template: 'Magento_Checkout/review/item/column' - }, - getClass: function() { - return 'col ' + this.ownClass; - }, - getHeaderClass: function() { - if (this.headerClass) { - return this.headerClass; - } - return 'col ' + this.ownClass; - }, - getColName: function() { - return this.columnTitle; - }, - getValue: function(quoteItem) { - return quoteItem.name; - }, - getFormattedPrice: function (price) { - return priceUtils.formatPrice(price, quote.getPriceFormat()); - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/price.js b/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/price.js deleted file mode 100644 index 0066f8cce1c0c39607ece39310b05a4226aba5a0..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/price.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - '../column' - ], - function (column) { - "use strict"; - return column.extend({ - defaults: { - ownClass: 'price', - columnTitle: 'Price', - template: 'Magento_Checkout/review/item/columns/price' - }, - getValue: function(quoteItem) { - return this.getFormattedPrice(quoteItem.price); - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/qty.js b/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/qty.js deleted file mode 100644 index c3352464d34e2e54cad7c2ed67b2bf314801915e..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/qty.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - '../column' - ], - function (column) { - "use strict"; - return column.extend({ - defaults: { - ownClass: 'qty', - columnTitle: 'Qty', - template: 'Magento_Checkout/review/item/columns/qty' - }, - getValue: function(quoteItem) { - return quoteItem.qty; - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address.js deleted file mode 100644 index aaa5529851d792e13ed91dcb28c29f66773efd24..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*global define*/ -define( - [ - "jquery", - 'Magento_Ui/js/form/form', - 'ko', - 'Magento_Checkout/js/action/select-shipping-address', - 'Magento_Customer/js/model/customer', - '../model/quote', - 'Magento_Checkout/js/model/step-navigator', - '../model/addresslist', - 'underscore' - ], - function($, Component, ko, selectShippingAddress, customer, quote, navigator, addressList, _) { - 'use strict'; - var stepName = 'shippingAddress'; - var newAddressSelected = ko.observable(false); - return Component.extend({ - defaults: { - template: 'Magento_Checkout/shipping-address', - visible: true, - formVisible: customer.getShippingAddressList().length === 0 - }, - stepClassAttributes: function() { - return navigator.getStepClassAttributes(stepName); - }, - stepNumber: navigator.getStepNumber(stepName), - addresses: function() { - var newAddress = { - getAddressInline: function() { - return $.mage.__('New address'); - }, - customerAddressId: null - }, - addresses = addressList.getAddresses(); - addresses.push(newAddress); - return addresses; - }, - selectedAddressId: ko.observable( - addressList.getAddresses().length ? addressList.getAddresses()[0].customerAddressId : null - ), - sameAsBilling: ko.observable(null), - quoteHasBillingAddress: quote.getBillingAddress(), - isVisible: navigator.isStepVisible(stepName), - initObservable: function () { - this._super() - .observe('visible'); - return this; - }, - isActive: function() { - if (quote.isVirtual()) { - navigator.setStepEnabled(stepName, false); - } - return !quote.isVirtual(); - }, - selectShippingAddress: function() { - var additionalFields, - addressData, - additionalData = {}, - billingAddress = quote.getBillingAddress()(); - - if (!billingAddress.customerAddressId || !this.visible()) { - /** - * All the the input fields that are not a part of the address but need to be submitted - * in the same request must have data-scope attribute set - */ - additionalFields = $('input[data-scope="additionalAddressData"]').serializeArray(); - additionalFields.forEach(function (field) { - additionalData[field.name] = field.value; - }); - } - - if (!newAddressSelected()) { - selectShippingAddress( - addressList.getAddressById(this.selectedAddressId()), - this.sameAsBilling(), - additionalData - ); - } else { - if (this.visible()) { - this.validate(); - } - - if (!this.source.get('params.invalid')) { - addressData = this.source.get('shippingAddress'); - selectShippingAddress(addressData, this.sameAsBilling(), additionalData); - } - } - }, - sameAsBillingClick: function() { - var billingAddress, - shippingAddress, - property; - - addressList.isBillingSameAsShipping = !addressList.isBillingSameAsShipping; - - if (this.sameAsBilling()) { - billingAddress = quote.getBillingAddress()(); - - if (billingAddress.customerAddressId) { - this.selectedAddressId(billingAddress.customerAddressId); - newAddressSelected(false); - - } else { - // copy billing address data to shipping address form if customer uses new address for billing - shippingAddress = this.source.get('shippingAddress'); - - for (property in billingAddress) { - if (billingAddress.hasOwnProperty(property) && shippingAddress.hasOwnProperty(property)) { - if (typeof billingAddress[property] === 'string') { - this.source.set('shippingAddress.' + property, billingAddress[property]); - } else { - this.source.set('shippingAddress.' + property, _.clone(billingAddress[property])); - } - } - } - - this.selectedAddressId(null); - newAddressSelected(true); - } - } - return true; - }, - onAddressChange: function() { - var billingAddress = quote.getBillingAddress(); - - if (this.selectedAddressId() !== billingAddress().customerAddressId) { - this.sameAsBilling(false); - } - - if (this.selectedAddressId() === null) { - newAddressSelected(true); - } else { - newAddressSelected(false); - } - }, - // Checkout step navigation - backToBilling: function() { - navigator.setCurrent(stepName).goBack(); - }, - navigateToCurrentStep: function() { - if (!navigator.isStepVisible(stepName)()) { - navigator.goToStep(stepName); - } - }, - isNewAddressSelected: function() { - if (!this.customerAddressCount) { - newAddressSelected(true); - return true; - } - return newAddressSelected(); - }, - validate: function() { - this.source.set('params.invalid', false); - this.source.trigger('shippingAddress.data.validate'); - }, - isCustomerLoggedIn: customer.isLoggedIn(), - customerAddressCount: window.checkoutConfig.customerAddressCount - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/address-renderer/default.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/address-renderer/default.js new file mode 100644 index 0000000000000000000000000000000000000000..16ed0dbabc78b5ca4141a2c946b6dec97ed34c69 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/address-renderer/default.js @@ -0,0 +1,53 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define([ + 'jquery', + 'ko', + 'uiComponent', + 'Magento_Checkout/js/action/select-shipping-address', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/shipping-address/form-popup-state' +], function($, ko, Component, selectShippingAddressAction, quote, formPopUpState) { + 'use strict'; + var countryData = window.checkoutConfig.countryData; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/shipping-address/address-renderer/default' + }, + + initProperties: function () { + this._super(); + this.isSelected = ko.computed(function() { + var isSelected = false; + var shippingAddress = quote.shippingAddress(); + if (shippingAddress) { + isSelected = shippingAddress.getKey() == this.address().getKey(); + } + return isSelected; + }, this); + + return this; + }, + + getCountryName: function(countryId) { + return (countryData[countryId] != undefined) ? countryData[countryId].name : ""; + }, + + /** Set selected customer shipping address */ + selectAddress: function() { + selectShippingAddressAction(this.address()); + }, + + editAddress: function() { + formPopUpState.isVisible(true); + this.showPopup(); + + }, + showPopup: function() { + $('[data-open-modal="opc-new-shipping-address"]').trigger('click'); + } + }); +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/list.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/list.js new file mode 100644 index 0000000000000000000000000000000000000000..352d8e628e37f4a598115181c8a3c576e56b8ed2 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-address/list.js @@ -0,0 +1,84 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define([ + 'underscore', + 'ko', + 'mageUtils', + 'uiComponent', + 'Magento_Ui/js/core/renderer/layout', + 'Magento_Customer/js/model/address-list' +], function (_, ko, utils, Component, layout, addressList) { + 'use strict'; + var defaultRendererTemplate = { + parent: '${ $.$data.parentName }', + name: '${ $.$data.name }', + component: 'Magento_Checkout/js/view/shipping-address/address-renderer/default' + }; + + return Component.extend({ + defaults: { + template: 'Magento_Checkout/shipping-address/list', + visible: addressList().length > 0, + rendererTemplates: [] + }, + + initialize: function () { + this._super() + .initChildren(); + + addressList.subscribe( + function(changes) { + var self = this; + changes.forEach(function(change) { + if (change.status === 'added') { + self.createRendererComponent(change.value, change.index); + } + }); + }, + this, + 'arrayChange' + ); + return this; + }, + + initProperties: function () { + this._super(); + // the list of child components that are responsible for address rendering + this.rendererComponents = []; + return this; + }, + + initChildren: function () { + _.each(addressList(), this.createRendererComponent, this); + return this; + }, + + /** + * Create new component that will render given address in the address list + * + * @param address + * @param index + */ + createRendererComponent: function (address, index) { + if (index in this.rendererComponents) { + this.rendererComponents[index].address(address); + } else { + // rendererTemplates are provided via layout + var rendererTemplate = (address.getType() != undefined && this.rendererTemplates[address.getType()] != undefined) + ? utils.extend({}, defaultRendererTemplate, this.rendererTemplates[address.getType()]) + : defaultRendererTemplate; + var templateData = { + parentName: this.name, + name: index + }; + var rendererComponent = utils.template(rendererTemplate, templateData); + utils.extend(rendererComponent, {address: ko.observable(address)}); + layout([rendererComponent]); + this.rendererComponents[index] = rendererComponent; + } + } + }); +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information.js new file mode 100644 index 0000000000000000000000000000000000000000..d33dd69762f9ca3fab4c12c0ea05108d91e61764 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information.js @@ -0,0 +1,37 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'jquery', + 'uiComponent', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/shipping-service', + 'Magento_Checkout/js/model/step-navigator' + ], + function($, Component, quote, shippingService, stepNavigator) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/shipping-information' + }, + + isVisible: function() { + return !quote.isVirtual() && stepNavigator.isProcessed('shipping'); + }, + + getShippingMethodTitle: function() { + return shippingService.getTitleByCode(quote.shippingMethod()) + }, + + back: function() { + // Temp solution for closing summary sliding panel on mobile MAGETWO-3864 + $('#opc-sidebar').modal('toggleModal'); + stepNavigator.back(); + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/address-renderer/default.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/address-renderer/default.js new file mode 100644 index 0000000000000000000000000000000000000000..9df85f97d84c402e33a2dad71ad1e48bf5b643eb --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/address-renderer/default.js @@ -0,0 +1,20 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define([ + 'uiComponent' +], function(Component) { + 'use strict'; + var countryData = window.checkoutConfig.countryData; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/shipping-information/address-renderer/default' + }, + + getCountryName: function(countryId) { + return (countryData[countryId] != undefined) ? countryData[countryId].name : ""; + } + }); +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/list.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/list.js new file mode 100644 index 0000000000000000000000000000000000000000..36342149c66e6fcc140e5c1d6ab9316c45e26958 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-information/list.js @@ -0,0 +1,84 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define([ + 'jquery', + 'ko', + 'mageUtils', + 'uiComponent', + 'Magento_Ui/js/core/renderer/layout', + 'Magento_Checkout/js/model/quote' +], function ($, ko, utils, Component, layout, quote) { + 'use strict'; + var defaultRendererTemplate = { + parent: '${ $.$data.parentName }', + name: '${ $.$data.name }', + component: 'Magento_Checkout/js/view/shipping-information/address-renderer/default' + }; + + return Component.extend({ + defaults: { + template: 'Magento_Checkout/shipping-information/list', + rendererTemplates: {} + }, + + initialize: function () { + this._super() + .initChildren(); + + var self = this; + quote.shippingAddress.subscribe(function(address) { + self.createRendererComponent(address); + }); + return this; + }, + + initProperties: function () { + this._super(); + // the list of child components that are responsible for address rendering + this.rendererComponents = {}; + return this; + }, + + initChildren: function () { + return this; + }, + + /** + * Create new component that will render given address in the address list + * + * @param address + */ + createRendererComponent: function (address) { + + $.each(this.rendererComponents, function(index, component) { + component.visible(false); + }); + + if (this.rendererComponents[address.getType()]) { + this.rendererComponents[address.getType()].address(address); + this.rendererComponents[address.getType()].visible(true); + } else { + // rendererTemplates are provided via layout + var rendererTemplate = + (address.getType() != undefined && this.rendererTemplates[address.getType()] != undefined) + ? utils.extend({}, defaultRendererTemplate, this.rendererTemplates[address.getType()]) + : defaultRendererTemplate; + var templateData = { + parentName: this.name, + name: address.getType() + }; + + var rendererComponent = utils.template(rendererTemplate, templateData); + utils.extend( + rendererComponent, + {address: ko.observable(address), visible: ko.observable(true)} + ); + layout([rendererComponent]); + this.rendererComponents[address.getType()] = rendererComponent; + } + } + }); +}); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-method.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-method.js deleted file mode 100644 index 29f4ebbca2a04b3d8d9eba738a9c734b3abd112b..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping-method.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - 'jquery', - 'underscore', - 'uiComponent', - '../model/quote', - '../model/shipping-service', - '../action/select-shipping-method', - 'Magento_Catalog/js/price-utils', - 'Magento_Checkout/js/model/step-navigator' - ], - function ($, _, Component, quote, shippingService, selectShippingMethod, priceUtils, navigator) { - var stepName = 'shippingMethod'; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/shipping-method' - }, - stepClassAttributes: function() { - return navigator.getStepClassAttributes(stepName); - }, - stepNumber: navigator.getStepNumber(stepName), - rates: shippingService.getSippingRates(), - // Checkout step navigation - isVisible: navigator.isStepVisible(stepName), - quoteHasShippingAddress: function() { - return quote.isVirtual() || quote.getShippingAddress(); - }, - - selectedMethod: quote.getSelectedShippingMethod(), - verifySelectedMethodCode: function (data) { - if (this.selectedMethod() == data) { - return data; - } - return false; - }, - - setShippingMethod: function (form) { - var item, - customOptions = {}; - for (item in this.elems()) { - if ('submit' in this.elems()[item]) { - customOptions = _.extend(customOptions, this.elems()[item].submit()); - } - } - form = $(form); - var code = form.find("input[name='shipping_method']:checked").val(); - selectShippingMethod(code, customOptions, this.getAfterSelectCallbacks()); - }, - getAfterSelectCallbacks: function() { - var callbacks = []; - _.each(this.getAdditionalMethods(), function(view) { - if (typeof view.afterSelect === 'function') { - callbacks.push(view.afterSelect); - } - }); - return callbacks; - }, - getAdditionalMethods: function() { - var methods = []; - _.each(this.getRegion('afterSelect')(), function(elem) { - methods = _.union(methods, elem.elems()); - }); - return methods; - }, - isActive: function() { - if (quote.isVirtual()) { - navigator.setStepEnabled(stepName, false); - } - return !quote.isVirtual(); - }, - backToShippingAddress: function () { - navigator.setCurrent(stepName).goBack(); - }, - navigateToCurrentStep: function() { - if (!navigator.isStepVisible(stepName)()) { - navigator.goToStep(stepName); - } - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js new file mode 100644 index 0000000000000000000000000000000000000000..7a0b60c760956737ff6d178faaa8528a8754d470 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js @@ -0,0 +1,241 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'Magento_Ui/js/form/form', + 'ko', + 'Magento_Customer/js/model/customer', + 'Magento_Customer/js/model/address-list', + 'Magento_Checkout/js/model/address-converter', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/action/create-shipping-address', + 'Magento_Checkout/js/action/select-shipping-address', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-address/form-popup-state', + 'Magento_Checkout/js/model/shipping-service', + 'Magento_Checkout/js/action/select-shipping-method', + 'Magento_Checkout/js/model/shipping-rate-registry', + 'Magento_Checkout/js/action/set-shipping-information', + 'Magento_Checkout/js/model/new-customer-address', + 'Magento_Checkout/js/model/step-navigator', + 'Magento_Ui/js/modal/modal', + 'mage/translate' + ], + function( + $, + Component, + ko, + customer, + addressList, + addressConverter, + quote, + createShippingAddress, + selectShippingAddress, + shippingRatesValidator, + formPopUpState, + shippingService, + selectShippingMethodAction, + rateRegistry, + setShippingInformationAction, + newAddress, + stepNavigator, + modal, + $t + ) { + 'use strict'; + var rates = window.checkoutConfig.shippingRates.data, + rateKey = window.checkoutConfig.shippingRates.key; + var popUp = null; + if (addressList().length == 0) { + var address = new newAddress({}); + rateRegistry.set(address.getCacheKey(), rates); + shippingService.setShippingRates(rates); + selectShippingAddress(address); + } + + if (rateKey) { + rateRegistry.set(rateKey, rates); + } + + selectShippingMethodAction(window.checkoutConfig.selectedShippingMethod); + shippingService.setShippingRates(rates); + + return Component.extend({ + defaults: { + template: 'Magento_Checkout/shipping' + }, + visible: ko.observable(!quote.isVirtual()), + isCustomerLoggedIn: customer.isLoggedIn, + isFormPopUpVisible: formPopUpState.isVisible, + isFormInline: addressList().length == 0, + isNewAddressAdded: ko.observable(false), + saveInAddressBook: true, + quoteIsVirtual: quote.isVirtual(), + + initialize: function () { + var self = this; + this._super(); + var shippingAddress = quote.shippingAddress(); + if (!shippingAddress) { + var isShippingAddressInitialized = addressList.some(function (address) { + if (address.isDefaultShipping()) { + selectShippingAddress(address); + return true; + } + return false; + }); + if (!isShippingAddressInitialized && addressList().length == 1) { + selectShippingAddress(addressList()[0]); + } + } + if (rates.length == 1) { + selectShippingMethodAction(rates[0]) + } + + if (!quote.isVirtual()) { + stepNavigator.registerStep('shipping', 'Shipping', this.visible, 10); + } + + this.isFormPopUpVisible.subscribe(function(value) { + if (value) { + self.getPopUp().openModal(); + } + }); + + return this; + }, + + initElement: function(element) { + if (element.index === 'shipping-address-fieldset') { + shippingRatesValidator.bindChangeHandlers(element.elems()); + } + }, + + getPopUp: function() { + var self = this; + if (!popUp) { + var buttons = this.popUpForm.options.buttons; + this.popUpForm.options.buttons = [ + { + text: buttons.save.text ? buttons.save.text : $t('Save Address'), + class: buttons.save.class ? buttons.save.class : 'action primary action-save-address', + click: self.saveNewAddress.bind(self) + }, + { + text: buttons.cancel.text ? buttons.cancel.text: $t('Cancel'), + class: buttons.cancel.class ? buttons.cancel.class : 'action secondary action-hide-popup', + click: function() { + this.closeModal(); + } + } + ]; + this.popUpForm.options.closed = function() { + self.isFormPopUpVisible(false); + }; + popUp = modal(this.popUpForm.options, $(this.popUpForm.element)); + } + return popUp; + }, + + /** Show address form popup */ + showFormPopUp: function() { + this.isFormPopUpVisible(true); + }, + + + /** Save new shipping address */ + saveNewAddress: function() { + this.source.set('params.invalid', false); + this.source.trigger('shippingAddress.data.validate'); + + if (!this.source.get('params.invalid')) { + var addressData = this.source.get('shippingAddress'); + addressData.save_in_address_book = this.saveInAddressBook; + + // New address must be selected as a shipping address + selectShippingAddress(createShippingAddress(addressData)); + this.getPopUp().closeModal(); + this.isNewAddressAdded(true); + } + }, + + /** Shipping Method View **/ + rates: shippingService.getSippingRates(), + isLoading: shippingService.isLoading, + isSelected: ko.computed(function () { + return quote.shippingMethod() + ? quote.shippingMethod().carrier_code + '_' + quote.shippingMethod().method_code + : null; + } + ), + + selectShippingMethod: function(shippingMethod) { + selectShippingMethodAction(shippingMethod); + return true; + }, + + setShippingInformation: function () { + if (this.validateShippingInformation()) { + setShippingInformationAction().done( + function() { + stepNavigator.next(); + } + ); + } + }, + + validateShippingInformation: function() { + var shippingAddress, + addressData, + loginFormSelector = 'form[data-role=email-with-possible-login]', + emailValidationResult = customer.isLoggedIn(); + + if (!quote.shippingMethod()) { + alert($t('Please specify a shipping method')); + return false; + } + + if (!customer.isLoggedIn()) { + $(loginFormSelector).validation(); + emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid()); + } + + if (this.isFormInline) { + this.source.set('params.invalid', false); + this.source.trigger('shippingAddress.data.validate'); + if (this.source.get('params.invalid') + || !quote.shippingMethod().method_code + || !quote.shippingMethod().carrier_code + || !emailValidationResult + ) { + return false; + } + shippingAddress = quote.shippingAddress(); + addressData = addressConverter.formAddressDataToQuoteAddress( + this.source.get('shippingAddress') + ); + + //Copy form data to quote shipping address object + for (var field in addressData) { + if (addressData.hasOwnProperty(field) + && shippingAddress.hasOwnProperty(field) + && typeof addressData[field] != 'function' + ) { + shippingAddress[field] = addressData[field]; + } + } + + if (customer.isLoggedIn()) { + shippingAddress.save_in_address_book = true; + } + selectShippingAddress(shippingAddress); + } + return true; + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/subtotal.js b/app/code/Magento/Checkout/view/frontend/web/js/view/subtotal.js deleted file mode 100644 index 227129562f0e58471263236a60dff85ce8a26b0b..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/subtotal.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*global define*/ -define( - ['uiComponent'], - function (Component) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/review/iterator', - displayArea: 'totals' - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/onepage.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary.js similarity index 53% rename from app/code/Magento/Checkout/view/frontend/web/js/view/onepage.js rename to app/code/Magento/Checkout/view/frontend/web/js/view/summary.js index 1d8f713edc4c829a97086f3df4b7b69a150ec92a..7a97079de6bcdf291c0bddacdf8b9e77efed2ac6 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/onepage.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary.js @@ -2,17 +2,16 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*browser:true jquery:true*/ /*global define*/ define( [ - 'uiComponent' + 'uiComponent', + 'Magento_Checkout/js/model/totals' ], - function (Component) { + function(Component, totals) { + 'use strict'; return Component.extend({ - defaults: { - template: 'Magento_Checkout/onepage' - } + isLoading: totals.isLoading }); } ); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/abstract-total.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/abstract-total.js new file mode 100644 index 0000000000000000000000000000000000000000..35a4b0071d724572aefb3cc1faaeee68123f3606 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/abstract-total.js @@ -0,0 +1,31 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/quote', + 'Magento_Catalog/js/price-utils', + 'Magento_Checkout/js/model/totals', + 'Magento_Checkout/js/model/step-navigator' + ], + function (Component, quote, priceUtils, totals, stepNavigator) { + "use strict"; + return Component.extend({ + getFormattedPrice: function (price) { + return priceUtils.formatPrice(price, quote.getPriceFormat()); + }, + getTotals: function() { + return totals.totals(); + }, + isFullMode: function() { + if (!this.getTotals()) { + return false; + } + return stepNavigator.isProcessed('shipping'); + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/cart-items.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/cart-items.js new file mode 100644 index 0000000000000000000000000000000000000000..0a41d2b46f2bfe4ec67d75d470b261e7fe7f3626 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/cart-items.js @@ -0,0 +1,31 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'ko', + 'Magento_Checkout/js/model/totals', + 'uiComponent', + 'Magento_Checkout/js/model/step-navigator', + 'Magento_Checkout/js/model/quote' + ], + function (ko, totals, Component, stepNavigator, quote) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/summary/cart-items' + }, + totals: totals.totals(), + getItems: totals.getItems(), + getItemsQty: function() { + return parseInt(this.totals.items_qty) || 0; + }, + isItemsBlockExpanded: function () { + return quote.isVirtual() || stepNavigator.isProcessed('shipping'); + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/grand-total.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/grand-total.js new file mode 100644 index 0000000000000000000000000000000000000000..0f341a847edc1f10af2ed256c115573212899d75 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/grand-total.js @@ -0,0 +1,32 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote' + ], + function (Component, quote) { + "use strict"; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/summary/grand-total' + }, + isDisplayed: function() { + return this.isFullMode(); + }, + getPureValue: function() { + var totals = quote.getTotals()(); + if (totals) { + return totals.grand_total; + } + return quote.grand_total; + }, + getValue: function() { + return this.getFormattedPrice(this.getPureValue()); + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/name.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details.js similarity index 59% rename from app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/name.js rename to app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details.js index 7e04d856621c69cb54018ea1aa937ddfad943163..1c965b0d5701be6269b412b9e825d1499531acca 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/name.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details.js @@ -6,15 +6,15 @@ /*global alert*/ define( [ - '../column' + 'uiComponent', + '../../../model/quote', + 'Magento_Catalog/js/price-utils' ], - function (column) { + function (Component, quote, priceUtils) { "use strict"; - return column.extend({ + return Component.extend({ defaults: { - ownClass: 'name', - columnTitle: 'Product Name', - template: 'Magento_Checkout/review/item/columns/name' + template: 'Magento_Checkout/summary/item/details' }, getValue: function(quoteItem) { return quoteItem.name; diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/subtotal.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/subtotal.js similarity index 61% rename from app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/subtotal.js rename to app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/subtotal.js index f08fb4830a0db1ab8aa6e6e474fc0d83d90e03df..30d43f7369298743b79f1fb9d9d76e0de6c93044 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/review/item/columns/subtotal.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/subtotal.js @@ -6,15 +6,14 @@ /*global alert*/ define( [ - '../column' + 'Magento_Checkout/js/view/summary/abstract-total' ], - function (column) { + function (viewModel) { "use strict"; - return column.extend({ + return viewModel.extend({ defaults: { - ownClass: 'subtotal', - columnTitle: 'Subtotal', - template: 'Magento_Checkout/review/item/columns/price' + displayArea: 'after_details', + template: 'Magento_Checkout/summary/item/details/subtotal' }, getValue: function(quoteItem) { return this.getFormattedPrice(quoteItem.row_total); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/thumbnail.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/thumbnail.js new file mode 100644 index 0000000000000000000000000000000000000000..2efdc4f91f4b071b79cd916c5cc2e090981e5a29 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/item/details/thumbnail.js @@ -0,0 +1,52 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'uiComponent' + ], + function (Component) { + "use strict"; + var imageData = window.checkoutConfig.imageData; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/summary/item/details/thumbnail' + }, + displayArea: 'before_details', + imageData: imageData, + getImageItem: function(item) { + if (this.imageData[item.item_id]) { + return this.imageData[item.item_id]; + } + return []; + }, + getSrc: function(item) { + if (this.imageData[item.item_id]) { + return this.imageData[item.item_id]['src']; + } + return null; + }, + getWidth: function(item) { + if (this.imageData[item.item_id]) { + return this.imageData[item.item_id]['width']; + } + return null; + }, + getHeight: function(item) { + if (this.imageData[item.item_id]) { + return this.imageData[item.item_id]['height']; + } + return null; + }, + getAlt: function(item) { + if (this.imageData[item.item_id]) { + return this.imageData[item.item_id]['alt']; + } + return null; + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js new file mode 100644 index 0000000000000000000000000000000000000000..fdce6d6d37db2bb914517a0dfae21b31e63cdf0f --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/shipping.js @@ -0,0 +1,39 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'jquery', + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/shipping-service' + ], + function ($, Component, quote, shippingService) { + return Component.extend({ + defaults: { + template: 'Magento_Checkout/summary/shipping' + }, + quoteIsVirtual: quote.isVirtual(), + totals: quote.getTotals(), + getShippingMethodTitle: function() { + if (!this.isCalculated()) { + return ''; + } + return shippingService.getTitleByCode(quote.shippingMethod()) + }, + isCalculated: function() { + return this.totals() && this.isFullMode() && null != quote.shippingMethod(); + }, + getValue: function() { + if (!this.isCalculated()) { + return this.notCalculatedMessage; + } + var price = this.totals().shipping_amount; + return this.getFormattedPrice(price); + } + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/summary/subtotal.js b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/subtotal.js new file mode 100644 index 0000000000000000000000000000000000000000..b5929a2b60562611adeac62ade8f95608d31ff32 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/summary/subtotal.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote' + ], + function (Component, quote) { + "use strict"; + return Component.extend({ + defaults: { + template: 'Magento_Checkout/summary/subtotal' + }, + getPureValue: function() { + var totals = quote.getTotals()(); + if (totals) { + return totals.subtotal; + } + return quote.subtotal; + }, + getValue: function () { + return this.getFormattedPrice(this.getPureValue()); + } + + }); + } +); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/totals.js b/app/code/Magento/Checkout/view/frontend/web/js/view/totals.js deleted file mode 100644 index caca53e801396ac04e93ebbba53ebe2d4815bbfb..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/totals.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'uiComponent' - ], - function (Component) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_Checkout/review/totals', - displayArea: 'totals' - } - }); - } -); diff --git a/app/code/Magento/Checkout/view/frontend/web/template/authentication.html b/app/code/Magento/Checkout/view/frontend/web/template/authentication.html index 263249c03824174fbc03630df6581d5e256b0909..f6a1e6e73a2bfcdb356a85b00747775a7d094ed4 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/authentication.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/authentication.html @@ -4,92 +4,81 @@ * See COPYING.txt for license details. */ --> -<li id="opc-billing" - data-bind="visible: isActive(), attr: {'class': stepClassAttributes() }" - role="presentation" - data-collapsible="true"> - <div class="step-title" - data-role="title" - data-bind="click: navigateToCurrentStep" - aria-controls="checkout-step-login" - role="tab"> - <span class="number" data-bind="text: stepNumber()"></span> - <h2 data-bind="text: $t('Checkout Method')"></h2> - </div> - <div id="checkout-step-authentication" class="step-content" data-role="content" data-bind="fadeVisible: isVisible()" > +<div class="authentication-wrapper" data-block="authentication" data-bind="visible: isActive()"> + <button + type="button" + class="action action-auth-toggle" + data-trigger="authentication"> + <span data-bind="text: $t('Sign In')"></span> + </button> + <div class="block-authentication" + style="display: none" + data-bind="mageInit: { + 'Magento_Ui/js/modal/modal':{ + 'type': 'custom', + 'modalClass': 'authentication-dropdown', + 'trigger': '[data-trigger=authentication]', + 'wrapperClass': 'authentication-wrapper', + 'parentModalClass': '_has-modal-custom _has-auth-shown', + 'responsive': true, + 'responsiveClass': 'custom-slide', + 'overlayClass': 'dropdown-overlay modal-custom-overlay', + 'buttons': [] + }}"> <!-- ko foreach: getRegion('before') --> <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> - <div class="login-wrapper"> - <!-- ko if: (isGuestCheckoutAllowed) --> - <div class="block block-guest"> - <div class="block-title"> - <strong id="block-guest-heading" role="heading" aria-level="2"> - <!--ko text: $t('Check Out as a Guest')--><!--/ko--> - </strong> - </div> - <div class="block-content" aria-labelledby="block-guest-heading"> + <div class="block block-customer-login" + data-bind="attr: {'data-label': $t('or')}"> + <div class="block-title"> + <strong id="block-customer-login-heading" + role="heading" + aria-level="2" + data-bind="text: $t('Sign In')"></strong> + </div> + <div class="block-content" aria-labelledby="block-customer-login-heading"> + <form data-role="login" + data-bind="submit:login" + method="post"> + <div class="fieldset" + data-bind="attr: {'data-hasrequired': $t('* Required Fields')}"> + <div class="field field-email required"> + <label class="label" for="login-email"><span data-bind="text: $t('Email Address')"></span></label> + <div class="control"> + <input type="email" + class="input-text" + id="login-email" + name="username" + data-validate="{required:true, 'validate-email':true}" /> + </div> + </div> + <div class="field field-password required"> + <label for="login-password" class="label"><span data-bind="text: $t('Password')"></span></label> + <div class="control"> + <input type="password" + class="input-text" + id="login-password" + name="password" + data-validate="{required:true, 'validate-password':true}"/> + </div> + </div> + <!-- ko foreach: getRegion('additional-login-form-fields') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </div> <div class="actions-toolbar"> + <input name="context" type="hidden" value="checkout" /> <div class="primary"> - <!-- ko if: (isGuestCheckoutAllowed)--> - <button data-bind="visible: isGuestCheckoutAllowed, click: setCheckoutMethod" data-role="opc-continue" id="onepage-guest-register-button" type="button" class="action continue primary" data-checkout='{"isGuestCheckoutAllowed":true}'><span data-bind="text: $t('Continue')"></span></button> - <!-- /ko --> - <!-- ko ifnot: isGuestCheckoutAllowed --> - <!-- ko if: isCustomerLoginRequired --> - <input type="checkbox" name="checkout_method" data-role="checkout-method-register" id="login:register" value="register" checked="checked" style="display: none"/> - <button data-bind="click: setCheckoutMethod" data-role="opc-continue" id="onepage-guest-register-button" type="button" class="action register primary" data-checkout='{"isGuestCheckoutAllowed":false, "registrationUrl":"registerUrl"}'><span data-bind="text: $t('Create an Account')"></span></button> - <!-- /ko --> - <!-- ko ifnot: isCustomerLoginRequired --> - <input type="checkbox" name="checkout_method" data-role="checkout-method-register" id="login:register" value="register" checked="checked" style="display: none"/> - <button data-bind="click: setCheckoutMethod" data-role="opc-continue" id="onepage-guest-register-button" type="button" class="action register primary" data-checkout='{"isGuestCheckoutAllowed":true}'><span data-bind="text: $t('Create an Account')"></span></button> - <!-- /ko --> - <!-- /ko --> + <button type="submit" class="action action-login secondary"><span data-bind="text: $t('Sign In')"></span></button> + </div> + <div class="secondary"> + <a class="action action-remind" data-bind="attr: { href: forgotPasswordUrl }"> + <span data-bind="text: $t('Forgot Password')"></span> + </a> </div> </div> - </div> - </div> - <!-- /ko --> - <div class="block block-customer-login"> - <div class="block-title"> - <strong id="block-customer-login-heading" role="heading" aria-level="2" data-bind="text: $t('Login')"></strong> - </div> - <div class="block-content" aria-labelledby="block-customer-login-heading"> - <form class="form login" data-role="login" - data-bind="submit:login" - method="post" - data-mage-init='{"validation":{}}'> - <fieldset class="fieldset login" data-bind="attr: {'data-hasrequired': $t('* Required Fields')}"> - <div class="field note" data-bind="text: $t('Already registered? Please sign in below:')"></div> - <div class="field email required"> - <label class="label" for="login-email"><span data-bind="text: $t('Email')"></span></label> - <div class="control"> - <input type="email" class="input-text" id="login-email" name="username" data-validate="{required:true, 'validate-email':true}" data-bind="value: username" /> - </div> - </div> - <div class="field password required"> - <label for="login-password" class="label"><span data-bind="text: $t('Password')"></span></label> - <div class="control"> - <input type="password" class="input-text" id="login-password" name="password" data-bind="value:password" data-validate="{required:true, 'validate-password':true}"/> - </div> - </div> - <!-- ko foreach: getRegion('additional-login-form-fields') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - <div class="actions-toolbar"> - <input name="context" type="hidden" value="checkout" /> - <div class="primary"> - <button type="submit" class="action login primary" data-action="checkout-method-login"><span data-bind="text: $t('Login')"></span></button> - </div> - <div class="secondary"> - <a class="action remind" data-bind="attr: { href: forgotPasswordUrl }"> - <span data-bind="text: $t('Forgot Your Password?')"></span> - </a> - </div> - </div> - </fieldset> - </form> - </div> + </form> </div> </div> </div> -</li> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address.html index baed4c7b53edbfb4715f8ddc7b3d9d8fe817074c..895f94e4cbd9404a667524f3e5cf29ba142371cd 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address.html @@ -4,54 +4,23 @@ * See COPYING.txt for license details. */ --> -<li id="opc-billing" data-bind="attr: {'class': stepClassAttributes() }" role="presentation"> - <div class="step-title" data-role="title" data-bind="click: navigateToCurrentStep"> - <span class="number" data-bind="text: stepNumber()"></span> - <h2 data-bind="text: $t('Billing Information')"></h2> - </div> - <div id="checkout-step-billing" class="step-content" data-role="content" data-bind="fadeVisible: isVisible()"> - <form class="form billing" id="co-billing-form" data-hasrequired="* Required Fields"> - <!-- ko if: (customerAddressCount)--> - <div class="field addresses"> - <label class="label" for="billing:address-select"><span data-bind="text: $t('Select a billing address from your address book or enter a new address.')"></span></label> - <div class="control"> - <select name="billing_address_id" id="billing:address-select" data-bind=" - options: billingAddresses(), - optionsText: billingAddressesOptionsText, - optionsValue: 'customerAddressId', - value: selectedBillingAddressId, - event: {change: onAddressChange(selectedBillingAddressId)}; - "></select> - </div> - </div> - <!--/ko--> - <fieldset id="billing-new-address-form" class="fieldset address" - data-bind="fadeVisible: isNewAddressSelected(), event {change: hideExtraFields()}"> - - <!-- ko foreach: getRegion('additional-fieldsets') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!--/ko--> - </fieldset> - <!-- ko if: quoteIsVirtual == 0 --> - <div class="field choice"> - <input type="radio" name="billing[use_for_shipping]" id="billing:use_for_shipping_yes" value="1" checked="checked" class="radio" data-bind="checked: useForShipping" /> - <label class="label" for="billing:use_for_shipping_yes"><span><!-- ko text: $t('Ship to this address')--><!-- /ko --> </span></label> - </div> - <div class="field choice"> - <input type="radio" name="billing[use_for_shipping]" id="billing:use_for_shipping_no" value="0" class="radio" data-bind="checked: useForShipping" /> - <label class="label" for="billing:use_for_shipping_no"><span><!-- ko text: $t('Ship to different address')--><!-- /ko --></span></label> - </div> - <!-- ko foreach: getRegion('additional-field-choice') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - <!-- /ko --> +<div class="billing-address-same-as-shipping-block field choice" data-bind="visible: canUseShippingAddress()"> + <input type="checkbox" name="billing-address-same-as-shipping" data-bind="checked: isAddressSameAsShipping, click: useShippingAddress, attr: {id: 'billing-address-same-as-shipping-' + $parent.getCode()}"/> + <label data-bind="text: $t('My billing and shipping address are the same'), attr: {for: 'billing-address-same-as-shipping-' + $parent.getCode()}"></label> +</div> - <input type="hidden" name="billing[use_for_shipping]" value="1" /> - <div class="actions" id="billing-buttons-container"> - <div class="primary"> - <button data-role="opc-continue" type="button" class="action continue primary" data-bind="click: submitBillingAddress"><span><!-- ko text: $t('Continue')--><!-- /ko --></span></button> - </div> - </div> - </form> +<!-- ko template: 'Magento_Checkout/billing-address/details' --><!-- /ko --> +<fieldset class="fieldset" data-bind="visible: !isAddressDetailsVisible()"> + <!-- ko template: 'Magento_Checkout/billing-address/list' --><!-- /ko --> + <!-- ko template: 'Magento_Checkout/billing-address/form' --><!-- /ko --> + <div class="actions-toolbar"> + <div class="primary"> + <button class="action action-update" type="button" data-bind="click: updateAddress"> + <span data-bind="text: $t('Update')"></span> + </button> + <button class="action action-cancel" type="button" data-bind="click: cancelAddressEdit"> + <span data-bind="text: $t('Cancel')"></span> + </button> + </div> </div> -</li> +</fieldset> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html new file mode 100644 index 0000000000000000000000000000000000000000..3d7d38a0f4aa80de63c750c37b0c489572300055 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html @@ -0,0 +1,18 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="billing-address-details" data-bind="if: isAddressDetailsVisible() && currentBillingAddress()"> + <!-- ko text: currentBillingAddress().firstname --><!-- /ko --> <!-- ko text: currentBillingAddress().lastname --><!-- /ko --><br/> + <!-- ko text: currentBillingAddress().street --><!-- /ko --><br/> + <!-- ko text: currentBillingAddress().city --><!-- /ko -->, <!-- ko text: currentBillingAddress().region --><!-- /ko --> <!-- ko text: currentBillingAddress().postcode --><!-- /ko --><br/> + + <!-- ko text: currentBillingAddress().telephone --><!-- /ko --><br/> + <button type="button" + class="action action-edit-address" + data-bind="visible: !isAddressSameAsShipping(), click: editAddress"> + <span data-bind="text: $t('Edit')"></span> + </button> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html new file mode 100644 index 0000000000000000000000000000000000000000..4174aa194d635afdd5220f2076a8ac71e985a0a7 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/form.html @@ -0,0 +1,26 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="billing-address-form" data-bind="fadeVisible: isAddressFormVisible"> + <!-- ko foreach: getRegion('before-fields') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + <form data-hasrequired="* Required Fields"> + <fieldset id="billing-new-address-form" class="fieldset address"> + <!-- ko foreach: getRegion('additional-fieldsets') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + <!-- ko if: (isCustomerLoggedIn && customerHasAddresses) --> + <div class="choice field"> + <input type="checkbox" class="checkbox" id="billing-save-in-address-book" data-bind="checked: saveInAddressBook" /> + <label class="label" for="billing-save-in-address-book"> + <span data-bind="text: $t('Save in address book')"></span> + </label> + </div> + <!-- /ko --> + </fieldset> + </form> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/list.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/list.html new file mode 100644 index 0000000000000000000000000000000000000000..f826ede448372134c8e7084dadbc973443492ed0 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/list.html @@ -0,0 +1,17 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="field field-select-billing"> + <label class="label"><span data-bind="text: $t('My billing and shipping address are the same')"></span></label> + <div class="control" data-bind="if: (addressOptions.length > 1)"> + <select class="select" name="billing_address_id" data-bind=" + options: addressOptions, + optionsText: addressOptionsText, + value: selectedAddress, + event: {change: onAddressChange(selectedAddress())}; + "></select> + </div> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/cart/authentication.html b/app/code/Magento/Checkout/view/frontend/web/template/cart/authentication.html new file mode 100644 index 0000000000000000000000000000000000000000..a2d2941754ff84e19bd81ff0acecce2056ee83d5 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/cart/authentication.html @@ -0,0 +1,89 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<div class="block-authentication" + data-bind="afterRender: setModalElement, blockLoader: isLoading" + style="display: none"> + <div class="block block-new-customer" + data-label="or"> + <div class="block-title"> + <strong id="block-new-customer-heading" role="heading" aria-level="2" data-bind="text: $t('Checkout out as a new customer')"></strong> + </div> + <div class="block-content" aria-labelledby="block-new-customer-heading"> + <p data-bind="text: $t('Creating an account has many benefits:')"></p> + <ul> + <li data-bind="text: $t('See order and shipping status')"></li> + <li data-bind="text: $t('Track order history')"></li> + <li data-bind="text: $t('Check out faster')"></li> + </ul> + <div class="actions-toolbar"> + <div class="primary"> + <a class="action action-register primary" data-bind="attr: {href: registerUrl}"> + <span data-bind="text: $t('Create Account')"></span> + </a> + </div> + </div> + </div> + </div> + <div class="block block-customer-login" + data-label="or"> + <div class="block-title"> + <strong id="block-customer-login-heading" role="heading" aria-level="2" data-bind="text:$t('Checkout out using your account')"></strong> + </div> + <!-- ko foreach: getRegion('messages') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + <!-- ko foreach: getRegion('before') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + <div class="block-content" aria-labelledby="block-customer-login-heading"> + <form class="form form-login" + method="post" + data-bind="submit:login" + id="login-form"> + <div class="fieldset login" data-hasrequired="* Required Fields"> + <div class="field email required"> + <label class="label" for="email"><span data-bind="text: $t('Email Address')"></span></label> + <div class="control"> + <input name="username" + id="email" + type="email" + class="input-text" + data-validate="{required:true, 'validate-email':true}"> + </div> + </div> + <div class="field password required"> + <label for="pass" class="label"><span data-bind="text: $t('Password')"></span></label> + <div class="control"> + <input name="password" + type="password" + class="input-text" + id="pass" + data-validate="{required:true, 'validate-password':true}"> + </div> + </div> + <!-- ko foreach: getRegion('additional-login-form-fields') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </div> + <div class="actions-toolbar"> + <input name="context" type="hidden" value="checkout" /> + <div class="primary"> + <button type="submit" class="action action-login secondary" name="send" id="send2"> + <span data-bind="text: $t('Sign In')"></span> + </button> + </div> + <div class="secondary"> + <a class="action" data-bind="attr: {href: forgotPasswordUrl}"> + <span data-bind="text: $t('Forgot Your Password?')"></span> + </a> + </div> + </div> + </div> + </form> + </div> + </div> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/minicart/content.html b/app/code/Magento/Checkout/view/frontend/web/template/minicart/content.html index 82475d90a25234b62a37c5e8c73fd01e5d0d61b8..a2fe08baaa52a4265d71b256b2d675514a380047 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/minicart/content.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/minicart/content.html @@ -98,3 +98,6 @@ <!-- /ko --> </div> </div> +<!-- ko foreach: getRegion('sign-in-popup') --> +<!-- ko template: getTemplate() --><!-- /ko --> +<!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html b/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html index 7a5432c380b5579dff032a888203426d61ae03ea..ee9b97ccd8ab3441c0f7942baf948799ea2aba9c 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html @@ -33,9 +33,9 @@ <!-- ko if: options.length --> <div class="product options" data-mage-init='{"collapsible":{"openedState": "active", "saveState": false}}'> - <span data-role="title" class="more toggle"><!-- ko text: $t('See Details') --><!-- /ko --></span> + <span data-role="title" class="toggle"><!-- ko text: $t('See Details') --><!-- /ko --></span> - <div data-role="content" class="product options details content"> + <div data-role="content" class="content"> <strong class="subtitle"><!-- ko text: $t('Options Details') --><!-- /ko --></strong> <dl class="product options list"> <!-- ko foreach: { data: options, as: 'option' } --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/onepage.html b/app/code/Magento/Checkout/view/frontend/web/template/onepage.html index b05de111621164ef6ff48603fa307eb087c49812..51b80426e5dd4a8fc930916241602f4d28da9681 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/onepage.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/onepage.html @@ -4,19 +4,70 @@ * See COPYING.txt for license details. */ --> +<!-- ko foreach: getRegion('authentication') --> +<!-- ko template: getTemplate() --><!-- /ko --> +<!--/ko--> -<!-- ko foreach: getRegion('errors') --> +<!-- ko foreach: getRegion('progressBar') --> <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> + +<!-- Temp MAGETWO-36025 markup --> +<div class="opc-estimated-wrapper"> +<!-- Markup for MAGETWO-38644 --> + <div class="estimated-block"> + <span class="estimated-label" data-bind="text: $t('Estimated Total')"></span> + <span class="estimated-price">$100.00</span> + </div> + <div class="minicart-wrapper"> + <button type="button" class="action showcart" data-toggle="opc-summary"> + <span class="counter qty"> + <span class="counter-number">6</span> + </span> + </button> + </div> + <!-- Temp MAGETWO-36025 markup + <button + type="button" + class="action showcart" + data-toggle="opc-summary"> + <span data-bind="text: $t('View order summary')"></span> + </button>--> +</div> +<!-- /Temp MAGETWO-36025 markup --> + +<!-- ko foreach: getRegion('messages') --> + <!-- ko template: getTemplate() --><!-- /ko --> +<!--/ko--> <div class="opc-wrapper"> <ol class="opc" id="checkoutSteps"> <!-- ko foreach: getRegion('steps') --> - <!-- ko template: getTemplate() --><!-- /ko --> + <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> </ol> </div> -<div id="checkout-progress-wrapper" class="opc-block-progress-wrapper"> - <!-- ko foreach: getRegion('progress') --> - <!-- ko template: getTemplate() --><!-- /ko --> + +<div id="opc-sidebar" + data-bind="mageInit: { + 'Magento_Ui/js/modal/modal':{ + 'type': 'custom', + 'modalClass': 'opc-sidebar opc-summary-wrapper', + 'trigger': '[data-toggle=opc-summary]', + 'wrapperClass': 'checkout-container', + 'parentModalClass': '_has-modal-custom', + 'responsive': true, + 'responsiveClass': 'custom-slide', + 'overlayClass': 'modal-custom-overlay', + 'buttons': [] + }}"> + + <!-- ko foreach: getRegion('summary') --> + <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> + + <div class="opc-block-shipping-information"> + <!-- ko foreach: getRegion('shipping-information') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> </div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/payment-methods/list.html b/app/code/Magento/Checkout/view/frontend/web/template/payment-methods/list.html new file mode 100644 index 0000000000000000000000000000000000000000..386f34af57ecc0486acaca9b73b2f62cf4fe4f5e --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/payment-methods/list.html @@ -0,0 +1,12 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<div class="items payment-methods"> + <!-- ko foreach: { data: getRegion('payment-method-items'), as: 'element'} --> + <!-- ko template: element.getTemplate() --><!-- /ko --> + <!-- /ko --> +</div> +<!-- ko ifnot: getRegion('payment-method-items')().length > 0 --><div class="no-payments-block"><!-- ko text: $t('No Payment Methods')--><!-- /ko --></div><!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/payment.html b/app/code/Magento/Checkout/view/frontend/web/template/payment.html index af29231586341e0e2f2cb46ab944a52f6823b77b..d289eacc124401c39893b337149972af7245254e 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/payment.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/payment.html @@ -4,59 +4,33 @@ * See COPYING.txt for license details. */ --> -<li id="opc-payment" data-bind=", attr: {'class': stepClassAttributes() }" role="presentation"> - <div class="step-title" data-role="title" data-bind="click: navigateToCurrentStep"> - <span class="number" data-bind="text: stepNumber()"></span> - <h2 data-bind="text: $t('Payment Information')"></h2> - </div> +<li id="opc-payment" role="presentation" class="checkout-payment-method" data-bind="fadeVisible: isVisible"> + <div class="step-title" data-bind="text: $t(title)" data-role="title"></div> <div id="checkout-step-payment" class="step-content" data-role="content" role="tabpanel" - aria-hidden="false" - data-bind="fadeVisible: isVisible() && quoteHasShippingMethod()"> - <form id="co-payment-form" class="form payments" novalidate="novalidate" data-bind="submit: setPaymentMethod"> + aria-hidden="false"> + <!-- ko if: (quoteIsVirtual) --> + <!-- ko foreach: getRegion('customer-email') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + <!--/ko--> + <form id="co-payment-form" class="form payments" novalidate="novalidate"> <input data-bind='attr: {value: getFormKey()}' type="hidden" name="form_key"/> <fieldset class="fieldset"> - <legend class="legend payments-title"> - <span><!-- ko text: $t('Payment Information')--><!-- /ko --></span>` - </legend> - <br> <!-- ko foreach: getRegion('beforeMethods') --> <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> <div id="checkout-payment-method-load" class="opc-payment"> - <dl class="items methods-payment"> - <!-- ko foreach: getAvailableViews() --> - <dt data-bind='attr: {class: "item-title " + getCode()}'> - <input data-bind='attr: {id: "p_method_" + getCode(), value: getCode(), title: getTitle(), class: "radio" + $parent.getMethodControlAdditionalClass()}, checked: $parent.activeMethod, enable: isEnabled' type="radio" name="payment[method]"/> - <label data-bind='attr: {for: "p_method_" + getCode()}'><!-- ko template: titleTemplate --><!--/ko--></label> - </dt> - <!-- ko if: $data.formTemplate --> - <dd data-bind='attr: {class: "item-content " + getCode()}, visible: $parent.isMethodActive(getCode()), enable: isEnabled'><!-- ko template: formTemplate --><!--/ko--></dd> - <!-- /ko --> - <!-- /ko --> - <!-- ko ifnot: getAvailableViews().length > 0 --> - <dt class="item-title"><!-- ko text: $t('No Payment Methods')--><!-- /ko --></dt> - <!-- /ko --> - </dl> + <!-- ko foreach: getRegion('payment-methods-list') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> </div> <!-- ko foreach: getRegion('afterMethods') --> <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> </fieldset> - <div class="actions-toolbar" id="payment-buttons-container"> - <div class="primary"> - <button data-role="opc-continue" - type="submit" - class="button action continue primary"> - <span><!-- ko text: $t('Continue')--><!-- /ko --></span> - </button> - </div> - <div class="secondary"> - <a class="action back" href="#" data-bind="click: backToShippingMethod"><span>Back</span></a> - </div> - </div> </form> </div> </li> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/progress-bar.html b/app/code/Magento/Checkout/view/frontend/web/template/progress-bar.html new file mode 100644 index 0000000000000000000000000000000000000000..6c13c80261d707b2e8b8930ff8e5642035231b11 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/progress-bar.html @@ -0,0 +1,13 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<ul class="opc-progress-bar"> + <!-- ko foreach: { data: steps().sort(sortItems), as: 'item' } --> + <li class="opc-progress-bar-item" data-bind="css: item.isVisible() ? '_active' : ($parent.isProcessed(item) ? '_complete' : '')"> + <span data-bind="text: $t(item.title), click: $parent.navigateTo"></span> + </li> + <!-- /ko --> +</ul> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/progress.html b/app/code/Magento/Checkout/view/frontend/web/template/progress.html deleted file mode 100644 index 2831a845897496816dd57d0fefadecd98b44390d..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/progress.html +++ /dev/null @@ -1,146 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> - <div data-bind = "attr: {'class': getClassName()}"> - <div class="title"> - <strong data-bind="text: $t('Your Checkout Progress')"></strong> - </div> - <div class="content"> - <dl class="items"> - <!-- ko if: isShowStep('billingAddress') --> - <!-- ko if: isStepComplete('billingAddress') --> - <dt class="item-title complete"> - <span id="billing-address-label" data-bind="text: $t('Billing Address')"></span> - <a href="#billing" - data-goto-section="billing" - class="action billing" - aria-describedby="billing-address-label" data-bind="text: $t('Change'), click: goToStep('billingAddress')"> - </a> - </dt> - <dd class="item-content complete"> - <address data-bind="html:getBillingAddress()"></address> - </dd> - <!--/ko--> - <!-- ko ifnot: isStepComplete('billingAddress') --> - <dt class="item-title" data-bind="text: $t('Billing Address')"></dt> - <!--/ko--> - <!--/ko--> - - <!-- ko if: isShowStep('shippingAddress') --> - <!-- ko if: isStepComplete('shippingAddress') --> - <dt class="item-title complete"> - <span id="shipping-address-label" data-bind="text: $t('Shipping Address')"></span> - <a href="#payment" - data-goto-section="shipping" - class="action shipping address" - aria-describedby="shipping-address-label" data-bind="text:$t('Change'), click: goToStep('shippingAddress')"> - </a> - </dt> - <dd class="item-content complete"> - <address data-bind="html:getShippingAddress()"></address> - </dd> - <!--/ko--> - <!-- ko ifnot: isStepComplete('shippingAddress') --> - <dt class="item-title"> - <span data-bind="text:$t('Shipping Address')"></span> - </dt> - <!--/ko--> - <!--/ko--> - - <!-- ko if: isShowStep('shippingMethod') --> - <!-- ko if: isStepComplete('shippingMethod') --> - <dt class="item-title complete"> - <span id="shipping-method-label" data-bind="text:$t('Shipping Method')"></span> - <a href="#shipping_method" - data-goto-section="shipping_method" - class="action shipping method" - aria-describedby="shipping-method-label" data-bind="text:$t('Change'), click: goToStep('shippingMethod')"> - </a> - </dt> - <dd class="item-content complete"> - <!--<?php if ($block->getShippingMethod()): ?>--> - - <!-- ko text: getShippingMethodTitle() --><!--/ko--> - - <!--shipping method price rendering--> - - <!-- ko foreach: {data: getShippingRates(), as: 'item'} --> - <!-- ko foreach: $parent.getRegion('shipping') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!--/ko--> - <!--/ko--> - - <!-- ko ifnot : (getShippingRates().length > 0) --> - <!-- ko text: $t('Please choose a shipping method.') --><!--/ko--> - <!--/ko--> - </dd> - <!--/ko--> - <!-- ko ifnot: isStepComplete('shippingMethod') --> - <dt class="item-title"> - <span data-bind="text:$t('Shipping Method')"></span> - </dt> - <!--/ko--> - <!--/ko--> - - <!-- ko if: isShowStep('paymentMethod') --> - <!-- ko if: isStepComplete('paymentMethod') --> - <dt class="item-title complete"> - <span id="payment-method-label" data-bind="text:$t('Payment Method')"></span> - <a href="#payment" - data-goto-section="payment" - class="action payment method" - aria-describedby="payment-method-label" data-bind="text:$t('Change'), click: goToStep('paymentMethod')"> - </a> - </dt> - <dd class="item-content complete"> - <dl class="payment-method"> - <dt class="title"><!-- ko text: getPaymentMethodTitle() --><!--/ko--></dt> - <dd class="content"> - <!-- ko if: getPaymentMethodInfo().length > 0 --> - <table class="data table"> - <tbody data-bind="foreach: {data: getPaymentMethodInfo(), as: 'item'}"> - <!-- ko if: item.name && (item.value || item.html) --> - <tr> - <th scope="row" data-bind="html: $t(item.name)"></th> - <!-- ko if: item.value --> - <td data-bind="text: $t(item.value)"></td> - <!--/ko--> - <!-- ko if: !item.value && item.html --> - <td data-bind="html: $t(item.html)"></td> - <!--/ko--> - </tr> - <!--/ko--> - <!-- ko if: item.name && !item.value && !item.html --> - <tr> - <th colspan="2" scope="row"><!-- ko text: $t(item.name) --><!--/ko--></th> - </tr> - <!--/ko--> - <!-- ko if: !item.name && (item.value || item.html) --> - <tr> - <!-- ko if: item.value --> - <td colspan="2" data-bind="text: $t(item.value)"></td> - <!--/ko--> - <!-- ko if: !item.value && item.html --> - <td colspan="2" data-bind="html: $t(item.html)"></td> - <!--/ko--> - </tr> - <!--/ko--> - </tbody> - </table> - <!--/ko--> - </dd> - </dl> - </dd> - <!--/ko--> - <!-- ko ifnot: isStepComplete('paymentMethod') --> - <dt class="item-title"> - <span data-bind="text:$t('Payment Method')"></span> - </dt> - <!--/ko--> - <!--/ko--> - </dl> - </div> -</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review.html b/app/code/Magento/Checkout/view/frontend/web/template/review.html deleted file mode 100644 index 2258e50fd37a2a127040dbc0f3595e80c280012b..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/review.html +++ /dev/null @@ -1,63 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<li id="opc-review" data-bind="attr: {'class': stepClassAttributes() }" role="presentation"> - <div class="step-title" data-role="title"> - <span class="number" data-bind="text: stepNumber()"></span> - <h2 data-bind="text: $t('Order Review')"></h2> - </div> - <div id="checkout-step-review" - class="step-content" - data-role="content" - role="tabpanel" - aria-hidden="false" - data-bind="fadeVisible: isVisible() && quoteHasPaymentMethod()"> - <div class="order-review" id="checkout-review-load"> - <!-- ko foreach: getRegion('itemsBefore') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - <div id="checkout-review-table-wrapper" class="order-review-wrapper table-wrapper"> - <table class="data table table-order-review items" id="checkout-review-table"> - <caption class="table-caption" data-bind="text: $t('Order Review')"></caption> - <thead> - <tr> - <!-- ko foreach: getRegion('columns') --> - <!-- ko foreach: elems() --> - <th class="col" scope="col" data-bind=" text: $t(getColName()) , attr: { class: getHeaderClass() }" ></th> - <!-- /ko --> - <!-- /ko --> - </tr> - </thead> - <tbody> - <!-- ko foreach: {data: getItems(), as: 'item'} --> - <tr> - <!-- ko foreach: $parent.getRegion('columns') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - </tr> - <!-- /ko --> - </tbody> - <tfoot> - <!-- ko foreach: getRegion('totals') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - </tfoot> - </table> - </div> - <!-- ko foreach: getRegion('itemsAfter') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - <div id="checkout-review-submit" data-mage-init='{"paymentAuthentication":{}}' class="checkout-submit-order"> - <!-- ko foreach: getRegion('beforePlaceOrder') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - <!-- ko foreach: getRegion('actions') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - </div> - </div> - </div> -</li> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review/discount.html b/app/code/Magento/Checkout/view/frontend/web/template/review/discount.html deleted file mode 100644 index 3123b421025ed575861d20ea2b6ebc5902df48dd..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/review/discount.html +++ /dev/null @@ -1,13 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko if: getPureValue() != 0 --> -<tr class="totals"> - <th data-bind="text: $t(fieldName) , attr: {'style':style, 'colspan': colspan}" class="mark" scope="row"> - </th> - <td data-bind="text: getValue(), attr: {'style': style, 'data-th': $t(name) }" class="amount"></td> -</tr> -<!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review/item/column.html b/app/code/Magento/Checkout/view/frontend/web/template/review/item/column.html deleted file mode 100644 index c32d4991c36b0bcacca083ee241d5ca5149f1fa9..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/review/item/column.html +++ /dev/null @@ -1,9 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<td data-bind="attr: { 'data-th': getColName(), class: getClass() }"> - <span data-bind="text: getValue($parents[1])"></span> -</td> \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/name.html b/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/name.html deleted file mode 100644 index 54f6daf92fd94f087ab5c8aba02fe9b7d9585391..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/name.html +++ /dev/null @@ -1,25 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<td class="col item" data-th="Product Name"><strong class="product name product-item-name" data-bind="text: $t(item.name)"></strong> - <!-- ko foreach: elems() --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - - <!-- ko if: (JSON.parse(item.options).length > 0)--> - <dl class="item-options"> - <!--ko foreach: JSON.parse(item.options)--> - <dt data-bind="text: $t(label)"></dt> - <!-- ko if: ($data.full_view)--> - <dd data-bind="html: full_view"></dd> - <!-- /ko --> - <!-- ko ifnot: ($data.full_view)--> - <dd data-bind="html: value"></dd> - <!-- /ko --> - <!-- /ko --> - </dl> - <!-- /ko --> -</td> \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/price.html b/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/price.html deleted file mode 100644 index 25e9e79a35d89d2487140d9b3b5db518927be2e5..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/price.html +++ /dev/null @@ -1,11 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<td data-bind="attr: { 'data-th': getColName(), class: getClass() }"> - <span class="cart-price"> - <span class="price" data-bind="text: getValue($parents[1])"></span> - </span> -</td> \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/qty.html b/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/qty.html deleted file mode 100644 index cc5e4d63f7890acb036bb3adb5a681e689df3743..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/review/item/columns/qty.html +++ /dev/null @@ -1,7 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<td class="col qty" data-th="Qty"><span class="qty" data-bind="text: item.qty"></span></td> \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review/iterator.html b/app/code/Magento/Checkout/view/frontend/web/template/review/iterator.html deleted file mode 100644 index 3e2032f2c631a6bebe2e29d02589aa44cae5c0dc..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/review/iterator.html +++ /dev/null @@ -1,10 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<!-- ko foreach: elems() --> - <!-- ko template: getTemplate() --><!-- /ko --> -<!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address.html deleted file mode 100644 index acd04e1fca45cfca1ead82a33c4d7c34de5637f0..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address.html +++ /dev/null @@ -1,62 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<li id="opc-shipping" data-bind="fadeVisible: isActive(), attr: {'class': stepClassAttributes() }"> - <div class="step-title" data-role="title" data-bind="click: navigateToCurrentStep"> - <span class="number" data-bind="text: stepNumber()"></span> - <h2 data-bind="text: $t('Shipping Information')"></h2> - </div> - <div id="checkout-step-shipping" - class="step-content" - data-role="content" - data-bind="fadeVisible: isVisible() && quoteHasBillingAddress()"> - <form class="form shipping address" id="co-shipping-form" data-hasrequired="* Required Fields"> - <!-- ko foreach: getRegion('before-fields') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!--/ko--> - <!-- ko if: (customerAddressCount)--> - <div class="field addresses" data-bind="visible: visible"> - <label class="label" for="shipping:address-select"><span data-bind="text: $t('Select a shipping address from your address book or enter a new address.')"></span></label> - <div class="control"> - <select name="shipping_address_id" id="shipping:address-select" data-bind=" - options: addresses(), - optionsText: function(item) { return item.getAddressInline(); }, - optionsValue: 'customerAddressId', - value: selectedAddressId, - event: {change: onAddressChange} - "> - </select> - </div> - </div> - <!-- /ko --> - <fieldset id="shipping-new-address-form" class="fieldset address" - data-bind="fadeVisible: isNewAddressSelected(), visible: formVisible"> - <!-- ko foreach: getRegion('additional-fieldsets') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!--/ko--> - </fieldset> - - <div class="choice field" data-bind="visible: visible"> - <input type="checkbox" - name="shipping[same_as_billing]" - id="shipping:same_as_billing" - value="1" - checked="checked" - class="checkbox" - data-bind="checked: sameAsBilling, click: sameAsBillingClick"/> - <label class="label" for="shipping:same_as_billing"> - <span data-bind="text: $t('Use Billing Address')"></span> - </label> - </div> - <div class="actions-toolbar" id="shipping-buttons-container"> - <div class="primary"> - <button data-role="opc-continue" type="button" class="action continue primary" data-bind="click: selectShippingAddress"><span data-bind="text: $t('Continue')"></span></button> - </div> - <div class="secondary"><a href="#" class="action back" data-bind="click: backToBilling"><span data-bind="text: $t('Back')"></span></a></div> - </div> - </form> - </div> -</li> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html new file mode 100644 index 0000000000000000000000000000000000000000..af87b5805b51e16afb0fec1d006c170325f1675c --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html @@ -0,0 +1,21 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="shipping-address-item" data-bind="css: isSelected() ? 'selected-item' : 'not-selected-item'"> + <!-- ko text: address().firstname --><!-- /ko --> <!-- ko text: address().lastname --><!-- /ko --><br/> + <!-- ko text: address().street --><!-- /ko --><br/> + <!-- ko text: address().city --><!-- /ko -->, <!-- ko text: address().region --><!-- /ko --> <!-- ko text: address().postcode --><!-- /ko --><br/> + <!-- ko text: getCountryName(address().countryId) --><!-- /ko --><br/> + <!-- ko text: address().telephone --><!-- /ko --><br/> + <button type="button" + class="action edit-address-link" + data-bind="click: editAddress, visible: address().isEditable()"> + <span data-bind="text: $t('Edit')"></span> + </button> + <button type="button" data-bind="click: selectAddress" class="action action-select-shipping-item"> + <span data-bind="text: $t('Ship Here')"></span> + </button> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/form.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/form.html new file mode 100644 index 0000000000000000000000000000000000000000..e450ee3fd9c3d04ae0c99208a64b244f3811c055 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/form.html @@ -0,0 +1,24 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<form class="form form-shipping-address" id="co-shipping-form" data-bind="attr: {'data-hasrequired': $t('* Required Fields')}"> + <!-- ko foreach: getRegion('before-fields') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + <fieldset id="shipping-new-address-form" class="fieldset address"> + <!-- ko foreach: getRegion('additional-fieldsets') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + <!-- ko if: (isCustomerLoggedIn) --> + <div class="field choice" data-bind="visible: !isFormInline"> + <input type="checkbox" class="checkbox" id="shipping-save-in-address-book" data-bind="checked: saveInAddressBook" /> + <label class="label" for="shipping-save-in-address-book"> + <span data-bind="text: $t('Save in address book')"></span> + </label> + </div> + <!-- /ko --> + </fieldset> +</form> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/list.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/list.html new file mode 100644 index 0000000000000000000000000000000000000000..84b0b3679c69f0b1d3efbf0cdf633bd0ca0519e0 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/list.html @@ -0,0 +1,18 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<!-- ko if: (visible)--> +<div class="field addresses"> + <div class="control"> + <div class="shipping-address-items"> + <!-- ko foreach: { data: elems, as: 'element' } --> + <!-- ko template: element.getTemplate() --><!-- /ko --> + <!-- /ko --> + </div> + </div> +</div> +<!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information.html new file mode 100644 index 0000000000000000000000000000000000000000..6d262c39d9f0cd0bf99259e870819e6ddc63dafe --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information.html @@ -0,0 +1,35 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<!-- ko if: (isVisible()) --> +<div class="shipping-information"> + <div class="ship-to"> + <div class="shipping-information-title"> + <span data-bind="text: $t('Ship To')"></span> + <button class="action action-edit" data-bind="click: back"> + <span data-bind="text: $t('edit')"></span> + </button> + </div> + <div class="shipping-information-content"> + <!-- ko foreach: getRegion('ship-to') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + </div> + <div class="ship-via"> + <div class="shipping-information-title"> + <span data-bind="text: $t('Ship Via')"></span> + <button class="action action-edit" data-bind="click: back"> + <span data-bind="text: $t('edit')"></span> + </button> + </div> + <div class="shipping-information-content"> + <span class="value" data-bind="text: $t(getShippingMethodTitle())"></span> + </div> + </div> +</div> +<!--/ko--> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html new file mode 100644 index 0000000000000000000000000000000000000000..32d832ca3092a32e8b8687325903880ce9274ee6 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html @@ -0,0 +1,13 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: (visible()) --> + <!-- ko text: address().firstname --><!-- /ko --> <!-- ko text: address().lastname --><!-- /ko --><br/> + <!-- ko text: address().street --><!-- /ko --><br/> + <!-- ko text: address().city --><!-- /ko -->, <!-- ko text: address().region --><!-- /ko --> <!-- ko text: address().postcode --><!-- /ko --><br/> + <!-- ko text: getCountryName(address().countryId) --><!-- /ko --><br/> + <!-- ko text: address().telephone --><!-- /ko --><br/> +<!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/review/totals.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/list.html similarity index 53% rename from app/code/Magento/Checkout/view/frontend/web/template/review/totals.html rename to app/code/Magento/Checkout/view/frontend/web/template/shipping-information/list.html index 3e2032f2c631a6bebe2e29d02589aa44cae5c0dc..c7a1eb499da7079fc81eaf82513fa59a3c3346de 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/review/totals.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/list.html @@ -5,6 +5,6 @@ */ --> -<!-- ko foreach: elems() --> - <!-- ko template: getTemplate() --><!-- /ko --> +<!-- ko foreach: { data: elems, as: 'element' } --> +<!-- ko template: element.getTemplate() --><!-- /ko --> <!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-method.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-method.html deleted file mode 100644 index 523c1eb3b34f4c2c47d692b4401f945bbe422471..0000000000000000000000000000000000000000 --- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-method.html +++ /dev/null @@ -1,94 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<li id="opc-shipping_method" data-bind="fadeVisible: isActive(), attr: {'class': stepClassAttributes() }" role="presentation"> - <div class="step-title" data-role="title" data-bind="click: navigateToCurrentStep"> - <span class="number" data-bind="text: stepNumber()"></span> - <h2 data-bind="text: $t('Shipping Method')"></h2> - </div> - <div id="checkout-step-shipping_method" - class="step-content" - data-role="content" - role="tabpanel" - aria-hidden="false" - data-bind="fadeVisible: isVisible() && quoteHasShippingAddress()"> - <!-- ko if: rates().length == 0 --> - <!-- ko text: $t('Sorry, no quotes are available for this order right now.')--><!-- /ko --> - <!-- /ko --> - <!-- ko if: rates().length --> - <form class="form methods-shipping" id="co-shipping-method-form" data-bind="submit: setShippingMethod" novalidate="novalidate"> - <div id="checkout-shipping-method-load"> - <dl class="items methods-shipping"> - <!--ko foreach: { data: rates(), as: 'method'}--> - <dt data-bind="text: $t(method.carrier_title), attr: {'class': 'item-title ' + method.carrier_code}"></dt> - <dd data-bind="attr: {'class': 'item-content ' + method.carrier_code}"> - <fieldset class="fieldset"> - <legend class="legend"><span data-bind="text: $t(method.carrier_title)"></span></legend> - <br> - <!--ko foreach: { data: items, as: 'item'}--> - <div class="field choice"> - <!-- ko if: item.error_message --> - <div class="message error"> - <div data-bind="text: $t(item.error_message)"></div> - </div> - <span class="no-display"> - <input name="shipping_method" type="radio" data-bind="attr: {'value' : item.method_code, 'id': 's_method_' + item.method_code}"/> - </span> - <!-- /ko --> - <!-- ko ifnot: item.error_message --> - <!-- ko if: $parent.items.length && $parents[1].rates().length == 1 --> - <span class="no-display"> - <input data-bind="attr: {'value' : item.carrier_code + '_' + item.method_code, 'id': 's_method_' + item.method_code}" - name="shipping_method" class="radio" type="radio" checked="checked"/> - </span> - <!-- /ko --> - <!--ko ifnot: ($parent.items.length && $parents[1].rates().length == 1)--> - <div class="control"> - <input name="shipping_method" type="radio" - data-bind="checked:$parents[1].verifySelectedMethodCode(item.carrier_code + '_' + item.method_code), attr: {'value': item.carrier_code + '_' + item.method_code, 'id': 's_method_' + item.carrier_code + '_' + item.method_code}" - class="radio"/> - </div> - <!--/ko--> - <label class="label" data-bind="attr: {'for': 's_method_' + item.carrier_code + '_' + item.method_code}"> - <span> - <!-- ko text: $t(item.method_title) --><!-- /ko --> - <!-- ko foreach: $parents[1].getRegion('price') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - </span> - </label> - <!-- /ko --> - </div> - <!-- /ko --> - </fieldset> - </dd> - - <!-- /ko --> - </dl> - - </div> - - <div id="onepage-checkout-shipping-method-additional-load"> - <!-- ko foreach: getRegion('shippingAdditional') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - </div> - <div class="actions-toolbar" id="shipping-method-buttons-container"> - <div class="primary"> - <button data-role="opc-continue" type="submit" class="button action continue primary"> - <span><!-- ko text: $t('Continue')--><!-- /ko --></span> - </button> - </div> - <div class="secondary"> - <a class="action back" href="#" data-bind="click: backToShippingAddress"> - <span><!-- ko text: $t('Back')--><!-- /ko --></span> - </a> - </div> - </div> - </form> - <!-- /ko --> - </div> -</li> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping.html new file mode 100644 index 0000000000000000000000000000000000000000..a62f3634547c53e3aa887261e137761c78394705 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping.html @@ -0,0 +1,141 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<li id="opc-shipping" data-bind="fadeVisible: visible()"> + <div class="step-title" data-bind="text: $t('Shipping Address')" data-role="title"></div> + <div id="checkout-step-shipping" + class="step-content" + data-role="content"> + + <!-- ko if: (!quoteIsVirtual) --> + <!-- ko foreach: getRegion('customer-email') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + <!--/ko--> + + <!-- ko foreach: getRegion('address-list') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + + <!-- ko foreach: getRegion('address-list-additional-addresses') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + + <!-- Address form pop up --> + <!-- ko if: (!isFormInline) --> + <button type="button" + data-bind="click: showFormPopUp, visible: !isNewAddressAdded()" + class="action action-show-popup"> + <span data-bind="text: $t('New Address')"></span></button> + <div id="opc-new-shipping-address" data-bind="visible: isFormPopUpVisible()"> + <!-- ko template: 'Magento_Checkout/shipping-address/form' --><!-- /ko --> + </div> + <!-- /ko --> + + <!-- ko foreach: getRegion('before-form') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + + <!-- Inline address form --> + <!-- ko if: (isFormInline) --> + <!-- ko template: 'Magento_Checkout/shipping-address/form' --><!-- /ko --> + <!-- /ko --> + </div> +</li> + + +<!--Shipping method template--> +<li id="opc-shipping_method" data-bind="fadeVisible: visible(), blockLoader: isLoading" role="presentation"> + <div class="checkout-shipping-method"> + <div class="step-title" data-bind="text: $t('Shipping Method')" data-role="title"></div> + <!-- ko foreach: getRegion('before-shipping-method-form') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + <div id="checkout-step-shipping_method" + class="step-content" + data-role="content" + role="tabpanel" + aria-hidden="false"> + <!-- ko if: rates().length --> + <form class="form methods-shipping" id="co-shipping-method-form" data-bind="submit: setShippingInformation" novalidate="novalidate"> + <div id="checkout-shipping-method-load"> + <table class="table-checkout-shipping-method"> + <thead> + <tr class="row"> + <th class="col"> </th> + <th class="col col-price" data-bind="text: $t('Price')"></th> + <th class="col col-method" data-bind="text: $t('Method Title')"></th> + <th class="col col-carrier" data-bind="text: $t('Carrier Title')"></th> + </tr> + </thead> + <tbody> + + <!--ko foreach: { data: rates(), as: 'method'}--> + <tr class="row" data-bind="click: $parent.selectShippingMethod"> + <td class="col"> + <!-- ko ifnot: method.error_message --> + <!-- ko if: $parent.rates().length == 1 --> + <input name="shipping_method" + class="radio" + type="radio" + data-bind="attr: {checked: $parent.rates().length == 1, 'value' : method.carrier_code + '_' + method.method_code, 'id': 's_method_' + method.method_code}" /> + <!-- /ko --> + <!--ko ifnot: ($parent.rates().length == 1)--> + <input name="shipping_method" type="radio" + data-bind=" + value: method.carrier_code + '_' + method.method_code, + checked: $parent.isSelected, + attr: {'id': 's_method_' + method.carrier_code + '_' + method.method_code}, + click: $parent.selectShippingMethod" + class="radio"/> + <!--/ko--> + <!-- /ko --> + </td> + <td class="col col-price"> + <!-- ko foreach: $parent.getRegion('price') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </td> + <td class="col col-method" data-bind="text: $t(method.method_title)"></td> + <td class="col col-carrier" data-bind="text: $t(method.carrier_title)"></td> + </tr> + + <!-- ko if: method.error_message --> + <tr class="row row-error"> + <td class="col col-error" colspan="4"> + <div class="message error"> + <div data-bind="text: $t(method.error_message)"></div> + </div> + <span class="no-display"> + <input name="shipping_method" type="radio" data-bind="attr: {'value' : method.method_code, 'id': 's_method_' + method.method_code}"/> + </span> + </td> + </tr> + <!-- /ko --> + + <!-- /ko --> + </tbody> + </table> + </div> + + <div id="onepage-checkout-shipping-method-additional-load"> + <!-- ko foreach: getRegion('shippingAdditional') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </div> + <div class="actions-toolbar" id="shipping-method-buttons-container"> + <div class="primary"> + <button data-role="opc-continue" type="submit" class="button action continue primary"> + <span><!-- ko text: $t('Next')--><!-- /ko --></span> + </button> + </div> + </div> + </form> + <!-- /ko --> + <!-- ko ifnot: rates().length > 0 --><div class="no-quotes-block"><!-- ko text: $t('Sorry, no quotes are available for this order at this time')--><!-- /ko --></div><!-- /ko --> + </div> + </div> +</li> diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/review/agreements.html b/app/code/Magento/Checkout/view/frontend/web/template/summary.html similarity index 55% rename from app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/review/agreements.html rename to app/code/Magento/Checkout/view/frontend/web/template/summary.html index 7de21298dcc66e6e6d094e5be4d5b9163fb5830a..322ef76b8f053604505b4f054ceedde082c362e0 100644 --- a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/review/agreements.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary.html @@ -4,8 +4,9 @@ * See COPYING.txt for license details. */ --> -<ol id="checkout-agreements" class="agreements checkout items"> +<div class="opc-block-summary" data-bind="blockLoader: isLoading"> + <span data-bind="text: $t('Order Summary')" class="title"></span> <!-- ko foreach: elems() --> <!-- ko template: getTemplate() --><!-- /ko --> - <!--/ko--> -</ol> + <!-- /ko --> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/cart-items.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/cart-items.html new file mode 100644 index 0000000000000000000000000000000000000000..b262445e97dcaaf4972312823ea20b772a9cca7f --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/cart-items.html @@ -0,0 +1,54 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko ifnot: isItemsBlockExpanded() --> +<div class="block items-in-cart" data-bind="mageInit: {'collapsible':{'openedState': 'active'}}"> + <div class="title" data-role="title"> + <strong role="heading"><span data-bind="text: getItemsQty()"></span> + <!-- ko text: $t('Items in cart') --><!-- /ko --> + </strong> + </div> + <div class="content minicart-items" data-role="content"> + <div class="minicart-items-wrapper overflowed"> + <ol class="minicart-items"> + <!-- ko foreach: getItems --> + <li class="product-item"> + <div class="product"> + <!-- ko foreach: $parent.elems() --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </div> + </li> + <!-- /ko --> + </ol> + </div> + </div> +</div> +<!-- /ko --> +<!-- ko if: isItemsBlockExpanded() --> +<div class="block items-in-cart" data-bind="mageInit: {'collapsible':{'openedState': 'active', 'active': true}}"> + <div class="title" data-role="title"> + <strong role="heading"><span data-bind="text: getItemsQty()"></span> + <!-- ko text: $t('Items in cart') --><!-- /ko --> + </strong> + </div> + <div class="content minicart-items" data-role="content"> + <div class="minicart-items-wrapper overflowed"> + <ol class="minicart-items"> + <!-- ko foreach: getItems --> + <li class="product-item"> + <div class="product"> + <!-- ko foreach: $parent.elems() --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </div> + </li> + <!-- /ko --> + </ol> + </div> + </div> +</div> +<!-- /ko --> \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/grand-total.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/grand-total.html new file mode 100644 index 0000000000000000000000000000000000000000..78954c0a4feff1a869912afebbb6051c57f34922 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/grand-total.html @@ -0,0 +1,17 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: isDisplayed() --> +<tr> + <td colspan="2" data-bind="text: $t(title)"></td> + <td class="col grandtotal"> + <span data-bind ="text: getValue(), attr:{'data-label': $t(title)}"></span> + <!-- ko foreach: elems() --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </td> +</tr> +<!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details.html new file mode 100644 index 0000000000000000000000000000000000000000..dab4d8393326c266bbdff3cf1f54883b6b218c73 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details.html @@ -0,0 +1,45 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<!-- ko foreach: getRegion('before_details') --> + <!-- ko template: getTemplate() --><!-- /ko --> +<!-- /ko --> +<div class="product-item-details"> + + <div class="product-item-inner"> + <div class="product-item-name-block"> + <strong class="product-item-name" data-bind="text: $t($parent.name)"></strong> + <div class="details-qty"> + <span class="label"><!-- ko text: $t('Qty') --><!-- /ko --></span> + <span class="value" data-bind="text: $parent.qty"></span> + </div> + </div> + <!-- ko foreach: getRegion('after_details') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </div> + + <!-- ko if: (JSON.parse($parent.options).length > 0)--> + <div class="product options" data-bind="mageInit: {'collapsible':{'openedState': 'active'}}"> + <span data-role="title" class="toggle"><!-- ko text: $t('View Details') --><!-- /ko --></span> + <div data-role="content" class="content"> + <strong class="subtitle"><!-- ko text: $t('Options Details') --><!-- /ko --></strong> + <dl class="item-options"> + <!--ko foreach: JSON.parse($parent.options)--> + <dt class="label" data-bind="text: $t(label)"></dt> + <!-- ko if: ($data.full_view)--> + <dd class="values" data-bind="html: full_view"></dd> + <!-- /ko --> + <!-- ko ifnot: ($data.full_view)--> + <dd class="values" data-bind="html: value"></dd> + <!-- /ko --> + <!-- /ko --> + </dl> + </div> + </div> + <!-- /ko --> +</div> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/item.js b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details/subtotal.html similarity index 54% rename from app/code/Magento/Checkout/view/frontend/web/js/model/item.js rename to app/code/Magento/Checkout/view/frontend/web/template/summary/item/details/subtotal.html index d1927d19e9288d2b244ff8f5761bc12556b605a2..f90013fcebbca354cb4ee7c7d3a0c756145ace6a 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/item.js +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details/subtotal.html @@ -1,9 +1,7 @@ +<!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define([], function() { - -}); +--> +<span class="subtotal" data-bind="text: getValue($parents[1])"></span> \ No newline at end of file diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details/thumbnail.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details/thumbnail.html new file mode 100644 index 0000000000000000000000000000000000000000..1b8cb1fada8c6d21332167f59d4a5cf68d342ca0 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/item/details/thumbnail.html @@ -0,0 +1,13 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<span class="product-image-container" + data-bind="attr: {'style': 'height: ' + getHeight($parents[1]) + 'px; width: ' + getWidth($parents[1]) + 'px;' }"> + <span class="product-image-wrapper"> + <img + data-bind="attr: {'src': getSrc($parents[1]), 'width': getWidth($parents[1]), 'height': getHeight($parents[1]), 'alt': getAlt($parents[1]) }"/> + </span> +</span> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/shipping.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/shipping.html new file mode 100644 index 0000000000000000000000000000000000000000..34707698e61b6d43a73c743b908c3b4c8c246fbc --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/shipping.html @@ -0,0 +1,24 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: quoteIsVirtual == 0 --> + <tr class="totals shipping excl"> + <th class="mark" scope="row"> + <span class="label" data-bind="text: $t(title)"></span> + <span class="value" data-bind="text: $t(getShippingMethodTitle())"></span> + </th> + <td class="amount"> + <!-- ko if: isCalculated() --> + <span class="price" + data-bind="text: $t(getValue()), attr: {'data-th': $t(title)}"></span> + <!-- /ko --> + <!-- ko ifnot: isCalculated() --> + <span class="not-calculated" + data-bind="text: $t(getValue()), attr: {'data-th': $t(title)}"></span> + <!-- /ko --> + </td> + </tr> +<!-- /ko --> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/subtotal.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/subtotal.html new file mode 100644 index 0000000000000000000000000000000000000000..f241430924ac88f2a773699f978c33228d9beb9c --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/subtotal.html @@ -0,0 +1,16 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tr class="totals"> + <th class="mark" scope="row" data-bind="text: $t(title)"></th> + <td class="amount"> + <span class="price" data-bind ="text: getValue(), attr:{'data-label': $t(title)}"></span> + <!-- ko foreach: elems() --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </td> +</tr> diff --git a/app/code/Magento/Checkout/view/frontend/web/template/summary/totals.html b/app/code/Magento/Checkout/view/frontend/web/template/summary/totals.html new file mode 100644 index 0000000000000000000000000000000000000000..074024dee00d9d0bdd55fef06c933f6df9d94330 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/template/summary/totals.html @@ -0,0 +1,14 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<table class="data table table-totals"> + <caption class="table-caption" data-bind="text: $t('Order Summary')"></caption> + <tbody> + <!-- ko foreach: elems() --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + </tbody> +</table> diff --git a/app/code/Magento/CheckoutAgreements/Block/Checkout/LayoutProcessor.php b/app/code/Magento/CheckoutAgreements/Block/Checkout/LayoutProcessor.php index b13012ae47336a32c14f4f96ca9c22cdaa1a5914..ad8bdfc822cd6cf47021150f599f6e43320d709d 100644 --- a/app/code/Magento/CheckoutAgreements/Block/Checkout/LayoutProcessor.php +++ b/app/code/Magento/CheckoutAgreements/Block/Checkout/LayoutProcessor.php @@ -34,34 +34,22 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso */ public function process($jsLayout) { - $form = []; + $agreementConfiguration = []; $agreementsList = $this->checkoutAgreementsRepository->getList(); + foreach ($agreementsList as $agreement) { - $name = $agreement->getAgreementId(); - $form[$name] = [ - 'component' => 'Magento_Ui/js/form/element/abstract', - 'config' => [ - 'customScope' => 'checkoutAgreements', - 'customEntry' => 'checkoutAgreements.' . $name, - 'template' => 'Magento_CheckoutAgreements/form/element/agreement' - ], - 'agreementConfiguration' => [ - 'content' => $agreement->getIsHtml() - ? $agreement->getContent() - : nl2br($this->escaper->escapeHtml($agreement->getContent())), - 'height' => $agreement->getContentHeight(), - 'checkboxText' => $agreement->getCheckboxText() - ], - 'dataScope' => $name, - 'provider' => 'checkoutProvider', - 'validation' => ['checked' => true], - 'customEntry' => null, - 'visible' => true + $agreementConfiguration[] = [ + 'content' => $agreement->getIsHtml() + ? $agreement->getContent() + : nl2br($this->escaper->escapeHtml($agreement->getContent())), + 'height' => $agreement->getContentHeight(), + 'checkboxText' => $agreement->getCheckboxText() ]; } - $result['components']['checkout']['children']['steps']['children']['review']['children'] - ['beforePlaceOrder']['children']['checkoutAgreements']['children'] = $form; + $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']['payment'] + ['children']['payments-list']['children']['before-place-order']['children']['checkout-agreements-modal'] + ['config']['agreementConfiguration'] = $agreementConfiguration; - return array_merge_recursive($jsLayout, $result); + return $jsLayout; } } diff --git a/app/code/Magento/CheckoutAgreements/composer.json b/app/code/Magento/CheckoutAgreements/composer.json index 13f10a6560e989f70548019e6eb5b043740c431b..1c9182b3add4bac268176432b51c4704d97b8cd9 100644 --- a/app/code/Magento/CheckoutAgreements/composer.json +++ b/app/code/Magento/CheckoutAgreements/composer.json @@ -6,7 +6,6 @@ "magento/module-checkout": "0.74.0-beta15", "magento/module-store": "0.74.0-beta15", "magento/module-backend": "0.74.0-beta15", - "magento/module-ui": "0.74.0-beta15", "magento/framework": "0.74.0-beta15", "magento/magento-composer-installer": "*" }, diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/CheckoutAgreements/view/frontend/layout/checkout_onepage_index.xml index b80bfc39aef43beb4d75914c654e68171d66a546..5f883201ee2dc7a65fb206b071dea0216d7c8b3b 100644 --- a/app/code/Magento/CheckoutAgreements/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/CheckoutAgreements/view/frontend/layout/checkout_onepage_index.xml @@ -15,16 +15,25 @@ <item name="children" xsi:type="array"> <item name="steps" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="review" xsi:type="array"> + <item name="billing-step" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="beforePlaceOrder" xsi:type="array"> + <item name="payment" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="checkoutAgreements" xsi:type="array"> - <item name="component" xsi:type="string">Magento_CheckoutAgreements/js/view/checkoutAgreements</item> - <item name="dataScope" xsi:type="string">checkoutAgreements</item> - <item name="displayArea" xsi:type="string">checkoutAgreements</item> - <item name="provider" xsi:type="string">checkoutProvider</item> + <item name="payments-list" xsi:type="array"> <item name="children" xsi:type="array"> + <item name="before-place-order" xsi:type="array"> + <item name="component" xsi:type="string">Magento_CheckoutAgreements/js/view/checkout-agreements-link</item> + <item name="displayArea" xsi:type="string">before-place-order</item> + <item name="dataScope" xsi:type="string">checkoutAgreements</item> + <item name="provider" xsi:type="string">checkoutProvider</item> + <item name="children" xsi:type="array"> + <item name="checkout-agreements-modal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_CheckoutAgreements/js/view/checkout-agreements-modal</item> + <item name="dataScope" xsi:type="string">checkoutAgreements</item> + <item name="provider" xsi:type="string">checkoutProvider</item> + </item> + </item> + </item> </item> </item> </item> diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/layout/checkout_onepage_original.xml b/app/code/Magento/CheckoutAgreements/view/frontend/layout/checkout_onepage_original.xml new file mode 100644 index 0000000000000000000000000000000000000000..89eb6278a7646836ff461eb6955899faae9b5fb9 --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/view/frontend/layout/checkout_onepage_original.xml @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- TODO remove this file as soon as enhanced checkout is implemented --> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="review" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="beforePlaceOrder" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="checkoutAgreements" xsi:type="array"> + <item name="component" xsi:type="string">Magento_CheckoutAgreements/js/view/checkoutAgreements</item> + <item name="dataScope" xsi:type="string">checkoutAgreements</item> + <item name="displayArea" xsi:type="string">checkoutAgreements</item> + <item name="provider" xsi:type="string">checkoutProvider</item> + <item name="children" xsi:type="array"> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-link.js b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-link.js new file mode 100644 index 0000000000000000000000000000000000000000..071602c254c40f864b7654cfb56293d1c250d2dc --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-link.js @@ -0,0 +1,24 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'ko', + 'uiComponent' + ], function (ko, Component) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_CheckoutAgreements/checkout/payment/checkout-agreements-link' + }, + isVisible: window.checkoutConfig.checkoutAgreementsEnabled, + /** + * Opens modal window with Terms&Conditions + */ + showAgreements: function () { + this.elems()[0].showAgreements(); + } + }); + } +); diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-modal.js b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-modal.js new file mode 100644 index 0000000000000000000000000000000000000000..e7762f7ea5b9f1c2448110c50be7ec42d28733a9 --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements-modal.js @@ -0,0 +1,56 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'ko', + 'uiComponent', + 'Magento_Ui/js/modal/modal' + ], function (ko, Component, modal) { + 'use strict'; + + /** + * Provides an empty div to force load template into. + * @todo MAGETWO-39170 Refactor this as soon as modal component is updated to support ko view models. + * @returns {HTMLElement} + */ + function createTemporayContainer() { + var temporaryDiv = document.createElement('div'); + temporaryDiv.style.display = 'none'; + document.body.appendChild(temporaryDiv); + + return temporaryDiv; + } + + return Component.extend({ + defaults: { + template: 'Magento_CheckoutAgreements/checkout/modal/agreements-modal' + }, + /** + * Initialize view and render it's template to temporary div. This will be refactored as soon as + * modal component is integrated with uiComponent. + * @returns {*} + */ + initialize: function () { + var temporaryContainer = createTemporayContainer(); + + this._super(); + ko.renderTemplate(this.template, this, {}, temporaryContainer); + temporaryContainer.parentNode.removeChild(temporaryContainer); + + return this; + }, + modal: modal({ + responsive: true, + innerScroll: true, + buttons: [] + }), + /** + * Show Terms&Conditions pop-up + */ + showAgreements: function () { + ko.renderTemplate(this.template, this, {}, this.modal.openModal(), 'replaceNode'); + } + }); + } +); diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkoutAgreements.js b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkoutAgreements.js deleted file mode 100644 index 094136c756467124a11a6c509263af55c8bd69c1..0000000000000000000000000000000000000000 --- a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkoutAgreements.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*global define*/ -define( - ['Magento_Ui/js/form/form', 'Magento_Checkout/js/view/review', 'underscore'], - function (Component, review, _) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_CheckoutAgreements/checkout/review/agreements' - }, - initialize: function() { - this._super(); - if (window.checkoutConfig.checkoutAgreementsEnabled) { - review.prototype.beforePlaceOrder.checkoutAgreements = this; - } - }, - validate: function() { - this.source.set('params.invalid', false); - this.source.trigger('checkoutAgreements.data.validate'); - return this.source.get('params.invalid'); - }, - getSubmitParams: function() { - return { - agreements: _.keys(this.source.get('checkoutAgreements')) - }; - } - }); - } -); diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/modal/agreements-modal.html b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/modal/agreements-modal.html new file mode 100644 index 0000000000000000000000000000000000000000..0129cab3aebd3c2d9aaba585274e4bfc70413ccb --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/modal/agreements-modal.html @@ -0,0 +1,15 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<ol class="checkout-agreements-items"> + <!-- ko foreach: agreementConfiguration --> + <li class="checkout-agreements-item"> + <div class="checkout-agreements-item-title" data-bind="html: checkboxText"></div> + <div class="checkout-agreements-item-content" + data-bind="style: { height: height || null }, html: content"></div> + </li> + <!-- /ko --> +</ol> diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/payment/checkout-agreements-link.html b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/payment/checkout-agreements-link.html new file mode 100644 index 0000000000000000000000000000000000000000..315bc47af7dac0607ace233f00b8dce7273a96db --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/payment/checkout-agreements-link.html @@ -0,0 +1,14 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<div class="checkout-agreements" data-bind="visible: isVisible"> + <!-- ko text: $t('You automatically accept') --><!-- /ko --> + <button type="button" class="action action-show" data-bind="click: showAgreements"> + <span><!-- ko text: $t('terms and conditions') --><!-- /ko --></span> + </button> + <!-- ko text: $t('before placing the order') --><!-- /ko --> +</div> diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/form/element/agreement.html b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/form/element/agreement.html deleted file mode 100644 index 0f029cfe2f3b4113a83c4b7256f867ce8e5ca592..0000000000000000000000000000000000000000 --- a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/form/element/agreement.html +++ /dev/null @@ -1,18 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<li class="item"> - <div class="agreement content" data-bind="style: { height: agreementConfiguration.height || null }, html: agreementConfiguration.content"></div> - <form class="field choice agree required" id="checkout-agreements"> - <input type="checkbox" class="control-checkbox" data-bind="checked: value, attr: { id: uid, disabled: disabled, name: inputName }, hasFocus: focused"> - <label class="field-label" data-bind="checked: value, attr: { for: uid }"> - <span data-bind="html: agreementConfiguration.checkboxText"></span> - </label> - </form> - <!-- ko if: error() --> - <div class="mage-error" data-bind="attr: { for: uid }, text: error" generated="true"></div> - <!-- /ko --> -</li> diff --git a/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Edit/FormTest.php b/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Edit/FormTest.php index 9fd408462cfc6a5918fa511605c160c3ad05c7fd..d671e0b864fb54e5ffc82f9a5d317debb6d73015 100755 --- a/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Edit/FormTest.php +++ b/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Edit/FormTest.php @@ -90,11 +90,6 @@ class FormTest extends \PHPUnit_Framework_TestCase */ protected $appState; - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $viewFileSystem; - /** * @var \PHPUnit_Framework_MockObject_MockObject */ @@ -130,6 +125,16 @@ class FormTest extends \PHPUnit_Framework_TestCase */ protected $block; + /** + * @var \Magento\Framework\View\Element\Template\File\Resolver|\PHPUnit_Framework_MockObject_MockObject + */ + protected $_resolver; + + /** + * @var \Magento\Framework\View\Element\Template\File\Validator|\PHPUnit_Framework_MockObject_MockObject + */ + protected $_validator; + /** * Sets up the fixture, for example, open a network connection. * This method is called before a test is executed. @@ -138,6 +143,22 @@ class FormTest extends \PHPUnit_Framework_TestCase */ public function setUp() { + $this->_resolver = $this->getMock( + 'Magento\Framework\View\Element\Template\File\Resolver', + [], + [], + '', + false + ); + + $this->_validator = $this->getMock( + 'Magento\Framework\View\Element\Template\File\Validator', + [], + [], + '', + false + ); + $this->model = $this->getMock('Magento\Cms\Model\Block', ['getBlockId', 'setStoreId'], [], '', false); $this->registry = $this->getMock('Magento\Framework\Registry', [], [], '', false); @@ -158,7 +179,6 @@ class FormTest extends \PHPUnit_Framework_TestCase $this->scopeConfig = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface', [], [], '', false); $this->urlBuilder = $this->getMock('Magento\Framework\UrlInterface', [], [], '', false); $this->appState = $this->getMock('Magento\Framework\App\State', [], [], '', false); - $this->viewFileSystem = $this->getMock('Magento\Framework\View\FileSystem', [], [], '', false); $this->logger = $this->getMock('Psr\Log\LoggerInterface', [], [], '', false); $this->rootDirectory = $this->getMock( 'Magento\Framework\Filesystem\Directory\ReadInterface', @@ -193,10 +213,11 @@ class FormTest extends \PHPUnit_Framework_TestCase $this->context->expects($this->once())->method('getStoreManager')->willReturn($this->storeManager); $this->context->expects($this->once())->method('getUrlBuilder')->willReturn($this->urlBuilder); $this->context->expects($this->once())->method('getAppState')->willReturn($this->appState); - $this->context->expects($this->once())->method('getViewFileSystem')->willReturn($this->viewFileSystem); $this->context->expects($this->once())->method('getFilesystem')->willReturn($this->fileSystem); $this->context->expects($this->once())->method('getLogger')->willReturn($this->logger); $this->context->expects($this->once())->method('getLayout')->willReturn($this->layout); + $this->context->expects($this->once())->method('getResolver')->willReturn($this->_resolver); + $this->context->expects($this->once())->method('getValidator')->willReturn($this->_validator); /** @var \Magento\Cms\Block\Adminhtml\Block\Edit\Form $block */ $this->block = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this)) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php index 5f381f0ddad0979e3efa4e6585a8ef09eedb7dd1..9f99ffd9339462f5692d169df9e2aeea0601f837 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/Cart.php @@ -204,7 +204,7 @@ class Cart extends \Magento\Backend\Block\Widget\Grid\Extended */ public function getGridParentHtml() { - $templateName = $this->_viewFileSystem->getTemplateFileName($this->_parentTemplate, ['_relative' => true]); + $templateName = $this->resolver->getTemplateFileName($this->_parentTemplate, ['_relative' => true]); return $this->fetchView($templateName); } diff --git a/app/code/Magento/Customer/Model/Customer/Attribute/Backend/Password.php b/app/code/Magento/Customer/Model/Customer/Attribute/Backend/Password.php index 992c63cf893f541fef9b1458542cd922b5a7e433..59d183ee6510eeba9fc301aeaec0417c464920e1 100644 --- a/app/code/Magento/Customer/Model/Customer/Attribute/Backend/Password.php +++ b/app/code/Magento/Customer/Model/Customer/Attribute/Backend/Password.php @@ -53,17 +53,8 @@ class Password extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBacke ); } - if ($this->string->substr( - $password, - 0, - 1 - ) == ' ' || $this->string->substr( - $password, - $length - 1, - 1 - ) == ' ' - ) { - throw new LocalizedException(__('The password can\'t begin or end with a space.')); + if (trim($password) != $password) { + throw new LocalizedException(__('The password can not begin or end with a space.')); } $object->setPasswordHash($object->hashPassword($password)); diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index 128ccedaf2b5277371680570b8e82fc88f95a2e2..777a78cb6fa05508712a9c07f4b8f7775ec45029 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -9,7 +9,7 @@ use Magento\Eav\Model\Config; use Magento\Eav\Model\Entity\Type; use Magento\Customer\Model\Address; use Magento\Customer\Model\Customer; -use Magento\Ui\DataProvider\EavValidationRul; +use Magento\Ui\DataProvider\EavValidationRules; use Magento\Customer\Model\Resource\Customer\Collection; use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; use Magento\Customer\Model\Resource\Customer\CollectionFactory as CustomerCollectionFactory; @@ -75,7 +75,7 @@ class DataProvider implements DataProviderInterface 'sortOrder' => 'sort_order', 'notice' => 'note', 'default' => 'default_value', - 'size' => 'scope_multiline_count' + 'size' => 'multiline_count' ]; /** @@ -90,9 +90,9 @@ class DataProvider implements DataProviderInterface ]; /** - * @var EavValidationRul + * @var EavValidationRules */ - protected $eavValidationRul; + protected $eavValidationRules; /** * Constructor @@ -100,7 +100,7 @@ class DataProvider implements DataProviderInterface * @param string $name * @param string $primaryFieldName * @param string $requestFieldName - * @param EavValidationRul $eavValidationRul + * @param EavValidationRules $eavValidationRules * @param CustomerCollectionFactory $customerCollectionFactory * @param Config $eavConfig * @param array $meta @@ -110,7 +110,7 @@ class DataProvider implements DataProviderInterface $name, $primaryFieldName, $requestFieldName, - EavValidationRul $eavValidationRul, + EavValidationRules $eavValidationRules, CustomerCollectionFactory $customerCollectionFactory, Config $eavConfig, array $meta = [], @@ -119,7 +119,7 @@ class DataProvider implements DataProviderInterface $this->name = $name; $this->primaryFieldName = $primaryFieldName; $this->requestFieldName = $requestFieldName; - $this->eavValidationRul = $eavValidationRul; + $this->eavValidationRules = $eavValidationRules; $this->collection = $customerCollectionFactory->create(); $this->collection->addAttributeToSelect('*'); $this->eavConfig = $eavConfig; @@ -223,6 +223,7 @@ class DataProvider implements DataProviderInterface * @param string|array $field * @param string|null $alias * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function addField($field, $alias = null) { @@ -260,6 +261,7 @@ class DataProvider implements DataProviderInterface * @param string|null $field * @param bool $isAlias Alias identifier * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function removeField($field, $isAlias = false) { @@ -369,7 +371,7 @@ class DataProvider implements DataProviderInterface } } - $rules = $this->eavValidationRul->build($attribute, $meta[$code]); + $rules = $this->eavValidationRules->build($attribute, $meta[$code]); if (!empty($rules)) { $meta[$code]['validation'] = $rules; } diff --git a/app/code/Magento/Customer/Model/Resource/Address.php b/app/code/Magento/Customer/Model/Resource/Address.php index 3b6ae0a28c8f9e812e762b72dbfe45d35681ebe9..d45f79f9a662574a3ca5c5db2cefadfe299c1274 100644 --- a/app/code/Magento/Customer/Model/Resource/Address.php +++ b/app/code/Magento/Customer/Model/Resource/Address.php @@ -9,7 +9,7 @@ namespace Magento\Customer\Model\Resource; use Magento\Framework\Exception\InputException; -class Address extends \Magento\Eav\Model\Entity\AbstractEntity +class Address extends \Magento\Eav\Model\Entity\VersionControl\AbstractEntity { /** * @var \Magento\Framework\Validator\Factory @@ -23,19 +23,23 @@ class Address extends \Magento\Eav\Model\Entity\AbstractEntity /** * @param \Magento\Eav\Model\Entity\Context $context + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, * @param \Magento\Framework\Validator\Factory $validatorFactory * @param \Magento\Customer\Model\CustomerFactory $customerFactory * @param array $data */ public function __construct( \Magento\Eav\Model\Entity\Context $context, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Framework\Validator\Factory $validatorFactory, \Magento\Customer\Model\CustomerFactory $customerFactory, $data = [] ) { $this->_validatorFactory = $validatorFactory; $this->_customerFactory = $customerFactory; - parent::__construct($context, $data); + parent::__construct($context, $entitySnapshot, $entityRelationComposite, $data); } /** @@ -63,31 +67,6 @@ class Address extends \Magento\Eav\Model\Entity\AbstractEntity return parent::getEntityType(); } - /** - * Set default shipping to address - * - * @param \Magento\Framework\Object $address - * @return $this - */ - protected function _afterSave(\Magento\Framework\Object $address) - { - if ($address->getIsCustomerSaveTransaction()) { - return $this; - } - if ($address->getId() && ($address->getIsDefaultBilling() || $address->getIsDefaultShipping())) { - $customer = $this->_createCustomer()->load($address->getCustomerId()); - - if ($address->getIsDefaultBilling()) { - $customer->setDefaultBilling($address->getId()); - } - if ($address->getIsDefaultShipping()) { - $customer->setDefaultShipping($address->getId()); - } - $customer->save(); - } - return $this; - } - /** * Check customer address before saving * diff --git a/app/code/Magento/Customer/Model/Resource/Address/Collection.php b/app/code/Magento/Customer/Model/Resource/Address/Collection.php index 83018cb25c448d481bebc476493876d476ed9478..771db1c598ca9d09e88de1444bdcd30a27c57adc 100644 --- a/app/code/Magento/Customer/Model/Resource/Address/Collection.php +++ b/app/code/Magento/Customer/Model/Resource/Address/Collection.php @@ -10,7 +10,7 @@ namespace Magento\Customer\Model\Resource\Address; * * @author Magento Core Team <core@magentocommerce.com> */ -class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection +class Collection extends \Magento\Eav\Model\Entity\Collection\VersionControl\AbstractCollection { /** * Resource initialization diff --git a/app/code/Magento/Customer/Model/Resource/Address/Relation.php b/app/code/Magento/Customer/Model/Resource/Address/Relation.php new file mode 100644 index 0000000000000000000000000000000000000000..0e10e2bb4612b3f55f4f9640264442608e6d9a41 --- /dev/null +++ b/app/code/Magento/Customer/Model/Resource/Address/Relation.php @@ -0,0 +1,73 @@ +<?php +/** + * Customer address entity resource model + * + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Model\Resource\Address; + +use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface; + +/** + * Class represents save operations for customer address relations + */ +class Relation implements RelationInterface +{ + /** + * @var \Magento\Customer\Model\CustomerFactory + */ + protected $customerFactory; + + /** + * @param \Magento\Customer\Model\CustomerFactory $customerFactory + */ + public function __construct(\Magento\Customer\Model\CustomerFactory $customerFactory) + { + $this->customerFactory = $customerFactory; + } + + /** + * Process object relations + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return void + */ + public function processRelation(\Magento\Framework\Model\AbstractModel $object) + { + /** + * @var $object \Magento\Customer\Model\Address + */ + if (!$object->getIsCustomerSaveTransaction() && $this->isAddressDefault($object)) { + $customer = $this->customerFactory->create()->load($object->getCustomerId()); + $changedAddresses = []; + + if ($object->getIsDefaultBilling()) { + $changedAddresses['default_billing'] = $object->getId(); + } + + if ($object->getIsDefaultShipping()) { + $changedAddresses['default_shipping'] = $object->getId(); + } + + if ($changedAddresses) { + $customer->getResource()->getWriteConnection()->update( + $customer->getResource()->getTable('customer_entity'), + $changedAddresses, + $customer->getResource()->getWriteConnection()->quoteInto('entity_id = ?', $customer->getId()) + ); + } + } + } + + /** + * Checks if address has chosen as default and has had an id + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return bool + */ + protected function isAddressDefault(\Magento\Framework\Model\AbstractModel $object) + { + return $object->getId() && ($object->getIsDefaultBilling() || $object->getIsDefaultShipping()); + } +} diff --git a/app/code/Magento/Customer/Model/Resource/Customer.php b/app/code/Magento/Customer/Model/Resource/Customer.php index 682e429411b7806b6c4695fcacaaecade20a7c88..16666b61689da0ccd4a50124c4128410b3bea0db 100644 --- a/app/code/Magento/Customer/Model/Resource/Customer.php +++ b/app/code/Magento/Customer/Model/Resource/Customer.php @@ -12,7 +12,7 @@ use Magento\Framework\Exception\AlreadyExistsException; * Customer entity resource model * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class Customer extends \Magento\Eav\Model\Entity\AbstractEntity +class Customer extends \Magento\Eav\Model\Entity\VersionControl\AbstractEntity { /** * @var \Magento\Framework\Validator\Factory @@ -33,6 +33,8 @@ class Customer extends \Magento\Eav\Model\Entity\AbstractEntity /** * @param \Magento\Eav\Model\Entity\Context $context + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Framework\Validator\Factory $validatorFactory * @param \Magento\Framework\Stdlib\DateTime $dateTime @@ -40,12 +42,14 @@ class Customer extends \Magento\Eav\Model\Entity\AbstractEntity */ public function __construct( \Magento\Eav\Model\Entity\Context $context, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Framework\Validator\Factory $validatorFactory, \Magento\Framework\Stdlib\DateTime $dateTime, $data = [] ) { - parent::__construct($context, $data); + parent::__construct($context, $entitySnapshot, $entityRelationComposite, $data); $this->_scopeConfig = $scopeConfig; $this->_validatorFactory = $validatorFactory; $this->dateTime = $dateTime; @@ -149,72 +153,14 @@ class Customer extends \Magento\Eav\Model\Entity\AbstractEntity /** * Save customer addresses and set default addresses in attributes backend * - * @param \Magento\Customer\Model\Customer $customer + * @param \Magento\Framework\Object $customer * @return $this */ protected function _afterSave(\Magento\Framework\Object $customer) { - $this->_saveAddresses($customer); return parent::_afterSave($customer); } - /** - * Save/delete customer address - * - * @param \Magento\Customer\Model\Customer $customer - * @return $this - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - protected function _saveAddresses(\Magento\Customer\Model\Customer $customer) - { - $defaultBillingId = $customer->getData('default_billing'); - $defaultShippingId = $customer->getData('default_shipping'); - /** @var \Magento\Customer\Model\Address $address */ - foreach ($customer->getAddresses() as $address) { - if ($address->getData('_deleted')) { - if ($address->getId() == $defaultBillingId) { - $customer->setData('default_billing', null); - } - if ($address->getId() == $defaultShippingId) { - $customer->setData('default_shipping', null); - } - $removedAddressId = $address->getId(); - $address->delete(); - // Remove deleted address from customer address collection - $customer->getAddressesCollection()->removeItemByKey($removedAddressId); - } else { - $address->setParentId( - $customer->getId() - )->setStoreId( - $customer->getStoreId() - )->setIsCustomerSaveTransaction( - true - )->save(); - if (($address->getIsPrimaryBilling() || - $address->getIsDefaultBilling()) && $address->getId() != $defaultBillingId - ) { - $customer->setData('default_billing', $address->getId()); - } - if (($address->getIsPrimaryShipping() || - $address->getIsDefaultShipping()) && $address->getId() != $defaultShippingId - ) { - $customer->setData('default_shipping', $address->getId()); - } - } - } - $changedAddresses = []; - - $changedAddresses['default_billing'] = $customer->getData('default_billing'); - $changedAddresses['default_shipping'] = $customer->getData('default_shipping'); - $this->_getWriteAdapter()->update( - $this->getTable('customer_entity'), - $changedAddresses, - $this->_getWriteAdapter()->quoteInto('entity_id = ?', $customer->getId()) - ); - - return $this; - } - /** * Retrieve select object for loading base entity row * diff --git a/app/code/Magento/Customer/Model/Resource/Customer/Collection.php b/app/code/Magento/Customer/Model/Resource/Customer/Collection.php index 6e0cdd7780452fed7563bd6df4de70d75ceb84f1..2353c59e91c5556f340720af805bbd512658d081 100644 --- a/app/code/Magento/Customer/Model/Resource/Customer/Collection.php +++ b/app/code/Magento/Customer/Model/Resource/Customer/Collection.php @@ -9,8 +9,9 @@ namespace Magento\Customer\Model\Resource\Customer; * Customers collection * * @author Magento Core Team <core@magentocommerce.com> + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection +class Collection extends \Magento\Eav\Model\Entity\Collection\VersionControl\AbstractCollection { /** * Name of collection model @@ -37,6 +38,7 @@ class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory * @param \Magento\Eav\Model\Resource\Helper $resourceHelper * @param \Magento\Framework\Validator\UniversalFactory $universalFactory + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Framework\Object\Copy\Config $fieldsetConfig * @param \Zend_Db_Adapter_Abstract $connection * @param string $modelName @@ -53,6 +55,7 @@ class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection \Magento\Eav\Model\EntityFactory $eavEntityFactory, \Magento\Eav\Model\Resource\Helper $resourceHelper, \Magento\Framework\Validator\UniversalFactory $universalFactory, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\Object\Copy\Config $fieldsetConfig, $connection = null, $modelName = self::CUSTOMER_MODEL_NAME @@ -69,6 +72,7 @@ class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection $eavEntityFactory, $resourceHelper, $universalFactory, + $entitySnapshot, $connection ); } diff --git a/app/code/Magento/Customer/Model/Resource/Customer/Relation.php b/app/code/Magento/Customer/Model/Resource/Customer/Relation.php new file mode 100644 index 0000000000000000000000000000000000000000..3967a981b6e95cfb610febd4d5019f4c3ace74a8 --- /dev/null +++ b/app/code/Magento/Customer/Model/Resource/Customer/Relation.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Model\Resource\Customer; + +/** + * Class Relation + */ +class Relation implements \Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface +{ + /** + * Save relations for Customer + * + * @param \Magento\Framework\Model\AbstractModel $customer + * @return void + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + public function processRelation(\Magento\Framework\Model\AbstractModel $customer) + { + $defaultBillingId = $customer->getData('default_billing'); + $defaultShippingId = $customer->getData('default_shipping'); + + /** @var \Magento\Customer\Model\Address $address */ + foreach ($customer->getAddresses() as $address) { + if ($address->getData('_deleted')) { + if ($address->getId() == $defaultBillingId) { + $customer->setData('default_billing', null); + } + + if ($address->getId() == $defaultShippingId) { + $customer->setData('default_shipping', null); + } + + $removedAddressId = $address->getId(); + $address->delete(); + + // Remove deleted address from customer address collection + $customer->getAddressesCollection()->removeItemByKey($removedAddressId); + } else { + $address->setParentId( + $customer->getId() + )->setStoreId( + $customer->getStoreId() + )->setIsCustomerSaveTransaction( + true + )->save(); + + if (($address->getIsPrimaryBilling() || + $address->getIsDefaultBilling()) && $address->getId() != $defaultBillingId + ) { + $customer->setData('default_billing', $address->getId()); + } + + if (($address->getIsPrimaryShipping() || + $address->getIsDefaultShipping()) && $address->getId() != $defaultShippingId + ) { + $customer->setData('default_shipping', $address->getId()); + } + } + } + + $changedAddresses = []; + + $changedAddresses['default_billing'] = $customer->getData('default_billing'); + $changedAddresses['default_shipping'] = $customer->getData('default_shipping'); + + $customer->getResource()->getWriteConnection()->update( + $customer->getResource()->getTable('customer_entity'), + $changedAddresses, + $customer->getResource()->getWriteConnection()->quoteInto('entity_id = ?', $customer->getId()) + ); + } +} diff --git a/app/code/Magento/Customer/Model/Resource/Group.php b/app/code/Magento/Customer/Model/Resource/Group.php index 6dc9888d7715024c2edb1d84158b0407df5a79c5..145ec38181b851afea01714368c2dbbb48a4e1f3 100644 --- a/app/code/Magento/Customer/Model/Resource/Group.php +++ b/app/code/Magento/Customer/Model/Resource/Group.php @@ -5,12 +5,15 @@ */ namespace Magento\Customer\Model\Resource; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; + /** * Customer group resource model * * @author Magento Core Team <core@magentocommerce.com> */ -class Group extends \Magento\Framework\Model\Resource\Db\AbstractDb +class Group extends \Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb { /** * Group Management @@ -26,19 +29,23 @@ class Group extends \Magento\Framework\Model\Resource\Db\AbstractDb /** * @param \Magento\Framework\Model\Resource\Db\Context $context + * @param Snapshot $entitySnapshot, + * @param RelationComposite $entityRelationComposite, * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement * @param Customer\CollectionFactory $customersFactory * @param string|null $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + RelationComposite $entityRelationComposite, \Magento\Customer\Api\GroupManagementInterface $groupManagement, \Magento\Customer\Model\Resource\Customer\CollectionFactory $customersFactory, $resourcePrefix = null ) { $this->_groupManagement = $groupManagement; $this->_customersFactory = $customersFactory; - parent::__construct($context, $resourcePrefix); + parent::__construct($context, $entitySnapshot, $entityRelationComposite, $resourcePrefix); } /** diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..eab40c46f84bbc63098fe6222250db2ecd9ed2d7 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php @@ -0,0 +1,249 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Test\Unit\Model\Customer; + +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Type; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Customer\Model\Customer\DataProvider; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Customer\Model\Resource\Customer\CollectionFactory; + +/** + * Class DataProviderTest + * + * Test for class \Magento\Customer\Model\Customer\DataProvider + */ +class DataProviderTest extends \PHPUnit_Framework_TestCase +{ + const ATTRIBUTE_CODE = 'test-code'; + const OPTIONS_RESULT = 'test-options'; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavConfigMock; + + /** + * @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $customerCollectionFactoryMock; + + /** + * @var EavValidationRules|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavValidationRulesMock; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->eavConfigMock = $this->getMockBuilder('Magento\Eav\Model\Config') + ->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionFactoryMock = $this->getMock( + 'Magento\Customer\Model\Resource\Customer\CollectionFactory', + ['create'], + [], + '', + false + ); + $this->eavValidationRulesMock = $this + ->getMockBuilder('Magento\Ui\DataProvider\EavValidationRules') + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * Run test getAttributesMeta method + * + * @param array $expected + * @return void + * + * @dataProvider getAttributesMetaDataProvider + */ + public function testGetAttributesMetaWithOptions(array $expected) + { + $helper = new ObjectManager($this); + $dataProvider = $helper->getObject( + '\Magento\Customer\Model\Customer\DataProvider', + [ + 'name' => 'test-name', + 'primaryFieldName' => 'primary-field-name', + 'requestFieldName' => 'request-field-name', + 'eavValidationRules' => $this->eavValidationRulesMock, + 'customerCollectionFactory' => $this->getCustomerCollectionFactoryMock(), + 'eavConfig' => $this->getEavConfigMock() + ] + ); + + $meta = $dataProvider->getMeta(); + $this->assertNotEmpty($meta); + $this->assertEquals($expected, $meta); + } + + /** + * Data provider for testGetAttributesMeta + * + * @return array + */ + public function getAttributesMetaDataProvider() + { + return [ + [ + 'expected' => [ + 'customer' => [ + 'fields' => [ + self::ATTRIBUTE_CODE => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ] + ] + ], + 'address' => [ + 'fields' => [ + self::ATTRIBUTE_CODE => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ] + ] + ] + ] + ] + ]; + } + + /** + * @return CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getCustomerCollectionFactoryMock() + { + $collectionMock = $this->getMockBuilder('Magento\Customer\Model\Resource\Customer\Collection') + ->disableOriginalConstructor() + ->getMock(); + + $collectionMock->expects($this->once()) + ->method('addAttributeToSelect') + ->with('*'); + + $this->customerCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($collectionMock); + + return $this->customerCollectionFactoryMock; + } + + /** + * @return Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getEavConfigMock() + { + $this->eavConfigMock->expects($this->at(0)) + ->method('getEntityType') + ->with('customer') + ->willReturn($this->getTypeCustomerMock()); + $this->eavConfigMock->expects($this->at(1)) + ->method('getEntityType') + ->with('customer_address') + ->willReturn($this->getTypeAddressMock()); + + return $this->eavConfigMock; + } + + /** + * @return Type|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getTypeCustomerMock() + { + $typeCustomerMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Type') + ->disableOriginalConstructor() + ->getMock(); + + $typeCustomerMock->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn($this->getAttributeMock()); + + return $typeCustomerMock; + } + + /** + * @return Type|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getTypeAddressMock() + { + $typeAddressMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Type') + ->disableOriginalConstructor() + ->getMock(); + + $typeAddressMock->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn($this->getAttributeMock()); + + return $typeAddressMock; + } + + /** + * @return AbstractAttribute[]|\PHPUnit_Framework_MockObject_MockObject[] + */ + protected function getAttributeMock() + { + $attributeMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute\AbstractAttribute') + ->setMethods(['getAttributeCode', 'getDataUsingMethod', 'usesSource', 'getSource']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $sourceMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute\Source\AbstractSource') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $sourceMock->expects($this->any()) + ->method('getAllOptions') + ->willReturn(self::OPTIONS_RESULT); + + $attributeMock->expects($this->once()) + ->method('getAttributeCode') + ->willReturn(self::ATTRIBUTE_CODE); + + $attributeMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback( + function ($origName) { + return $origName; + } + ); + $attributeMock->expects($this->any()) + ->method('usesSource') + ->willReturn(true); + $attributeMock->expects($this->any()) + ->method('getSource') + ->willReturn($sourceMock); + + $this->eavValidationRulesMock->expects($this->any()) + ->method('build') + ->with($attributeMock, $this->logicalNot($this->isEmpty())); + + return [$attributeMock]; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Resource/Address/RelationTest.php b/app/code/Magento/Customer/Test/Unit/Model/Resource/Address/RelationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0d72b965ace153289868b83e6ff6bc507d936fe9 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Resource/Address/RelationTest.php @@ -0,0 +1,144 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Test\Unit\Model\Resource\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Class AddressTest + */ +class RelationTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\Customer\Model\CustomerFactory | \PHPUnit_Framework_MockObject_MockObject */ + protected $customerFactoryMock; + + /** @var \Magento\Customer\Model\Resource\Address\Relation */ + protected $relation; + + protected function setUp() + { + $this->customerFactoryMock = $this->getMock( + 'Magento\Customer\Model\CustomerFactory', + ['create'], + [], + '', + false + ); + $this->relation = (new ObjectManagerHelper($this))->getObject( + 'Magento\Customer\Model\Resource\Address\Relation', + [ + 'customerFactory' => $this->customerFactoryMock + ] + ); + } + + /** + * @param $addressId + * @param $isDefaultBilling + * @param $isDefaultShipping + * @dataProvider getRelationDataProvider + */ + public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShipping) + { + $addressModel = $this->getMock( + 'Magento\Framework\Model\AbstractModel', + [ + '__wakeup', + 'getId', + 'getEntityTypeId', + 'getIsDefaultBilling', + 'getIsDefaultShipping', + 'hasDataChanges', + 'validateBeforeSave', + 'beforeSave', + 'afterSave', + 'isSaveAllowed' + ], + [], + '', + false + ); + $customerModel = $this->getMock( + 'Magento\Customer\Model\Customer', + ['__wakeup', 'setDefaultBilling', 'setDefaultShipping', 'save', 'load', 'getResource', 'getId'], + [], + '', + false + ); + $customerResource = $this->getMockForAbstractClass( + 'Magento\Framework\Model\Resource\Db\AbstractDb', + [], + '', + false, + false, + true, + ['getWriteConnection', 'getTable'] + ); + $adapter = $this->getMockForAbstractClass( + 'Magento\Framework\DB\Adapter\AdapterInterface', + [], + '', + false, + false, + true, + ['update', 'quoteInto'] + ); + $customerModel->expects($this->any())->method('getResource')->willReturn($customerResource); + $addressModel->expects($this->any())->method('getId')->willReturn($addressId); + $addressModel->expects($this->any())->method('getIsDefaultShipping')->willReturn($isDefaultShipping); + $addressModel->expects($this->any())->method('getIsDefaultBilling')->willReturn($isDefaultBilling); + $addressModel->expects($this->any())->method('getIsCustomerSaveTransaction')->willReturn(false); + + $customerModel->expects($this->any()) + ->method('load') + ->willReturnSelf(); + + $this->customerFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($customerModel); + if ($addressId && ($isDefaultBilling || $isDefaultShipping)) { + $customerId = 1; + $customerResource->expects($this->exactly(2))->method('getWriteConnection')->willReturn($adapter); + $customerModel->expects($this->any())->method('getId')->willReturn(1); + $conditionSql = "entity_id = $customerId"; + $adapter->expects($this->once())->method('quoteInto') + ->with('entity_id = ?', $customerId) + ->willReturn($conditionSql); + $customerResource->expects($this->once())->method('getTable') + ->with('customer_entity') + ->willReturn('customer_entity'); + $toUpdate = []; + if ($isDefaultBilling) { + $toUpdate['default_billing'] = $addressId; + } + if ($isDefaultShipping) { + $toUpdate['default_shipping'] = $addressId; + } + $adapter->expects($this->once())->method('update')->with( + 'customer_entity', + $toUpdate, + $conditionSql + ); + } + $this->relation->processRelation($addressModel); + } + + /** + * Data provider for processRelation method + * + * @return array + */ + public function getRelationDataProvider() + { + return [ + [null, true, true], + [1, true, true], + [1, true, false], + [1, false, true], + [1, false, false], + ]; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php b/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php index c15cf1596c8245fb30d8a79ba097923d545c26b0..11c8a8378e134a4eb9747d88c261421d9c8d41c1 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php @@ -8,6 +8,8 @@ namespace Magento\Customer\Test\Unit\Model\Resource; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; class AddressTest extends \PHPUnit_Framework_TestCase @@ -21,12 +23,37 @@ class AddressTest extends \PHPUnit_Framework_TestCase /** @var \Magento\Eav\Model\Entity\Type */ protected $eavConfigType; + /** @var Snapshot|\PHPUnit_Framework_MockObject_MockObject */ + protected $entitySnapshotMock; + + /** @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject */ + protected $entityRelationCompositeMock; + protected function setUp() { + $this->entitySnapshotMock = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', + [], + [], + '', + false + ); + + + $this->entityRelationCompositeMock = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite', + [], + [], + '', + false + ); + $this->addressResource = (new ObjectManagerHelper($this))->getObject( 'Magento\Customer\Model\Resource\Address', [ 'resource' => $this->prepareResource(), + 'entitySnapshot' => $this->entitySnapshotMock, + 'entityRelationComposite' => $this->entityRelationCompositeMock, 'eavConfig' => $this->prepareEavConfig(), 'validatorFactory' => $this->prepareValidatorFactory(), 'customerFactory' => $this->prepareCustomerFactory() @@ -43,22 +70,6 @@ class AddressTest extends \PHPUnit_Framework_TestCase */ public function testSave($addressId, $isDefaultBilling, $isDefaultShipping) { - /** @var $customer \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject */ - $customer = $this->getMock( - 'Magento\Customer\Model\Customer', - ['__wakeup', 'setDefaultBilling', 'setDefaultShipping', 'save', 'load'], - [], - '', - false - ); - $customer->expects($this->any()) - ->method('load') - ->willReturnSelf(); - - $this->customerFactory->expects($this->any()) - ->method('create') - ->willReturn($customer); - /** @var $address \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject */ $address = $this->getMock( 'Magento\Customer\Model\Address', @@ -78,7 +89,8 @@ class AddressTest extends \PHPUnit_Framework_TestCase '', false ); - $address->expects($this->once())->method('hasDataChanges')->willReturn(true); + $this->entitySnapshotMock->expects($this->once())->method('isModified')->willReturn(true); + $this->entityRelationCompositeMock->expects($this->once())->method('processRelations'); $address->expects($this->once())->method('isSaveAllowed')->willReturn(true); $address->expects($this->once())->method('validateBeforeSave'); $address->expects($this->once())->method('beforeSave'); @@ -87,19 +99,6 @@ class AddressTest extends \PHPUnit_Framework_TestCase $address->expects($this->any())->method('getId')->willReturn($addressId); $address->expects($this->any())->method('getIsDefaultShipping')->willReturn($isDefaultShipping); $address->expects($this->any())->method('getIsDefaultBilling')->willReturn($isDefaultBilling); - if ($addressId && ($isDefaultBilling || $isDefaultShipping)) { - if ($isDefaultBilling) { - $customer->expects($this->once())->method('setDefaultBilling')->with($addressId); - } - if ($isDefaultShipping) { - $customer->expects($this->once())->method('setDefaultShipping')->with($addressId); - } - $customer->expects($this->once())->method('save'); - } else { - $customer->expects($this->never())->method('setDefaultBilling'); - $customer->expects($this->never())->method('setDefaultShipping'); - $customer->expects($this->never())->method('save'); - } $this->addressResource->setType('customer_address'); $this->addressResource->save($address); } diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 692eba9dc08461d96d0c449b7ef3e158c31f0c66..cc98e7676b3fa9f7825da52d2d647966661a0978 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -126,4 +126,45 @@ </argument> </arguments> </type> + <virtualType name="EavVersionControlSnapshot" type="Magento\Framework\Model\Resource\Db\VersionControl\Snapshot"> + <arguments> + <argument name="metadata" xsi:type="object">Magento\Eav\Model\Entity\VersionControl\Metadata</argument> + </arguments> + </virtualType> + <virtualType name="CustomerRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> + <arguments> + <argument name="relationProcessors" xsi:type="array"> + <item name="default" xsi:type="object">Magento\Customer\Model\Resource\Customer\Relation</item> + </argument> + </arguments> + </virtualType> + <virtualType name="CustomerAddressRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> + <arguments> + <argument name="relationProcessors" xsi:type="array"> + <item name="default" xsi:type="object">Magento\Customer\Model\Resource\Address\Relation</item> + </argument> + </arguments> + </virtualType> + <type name="Magento\Customer\Model\Resource\Customer"> + <arguments> + <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument> + <argument name="entityRelationComposite" xsi:type="object">CustomerRelationsComposite</argument> + </arguments> + </type> + <type name="Magento\Customer\Model\Resource\Customer\Collection"> + <arguments> + <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument> + </arguments> + </type> + <type name="Magento\Customer\Model\Resource\Address"> + <arguments> + <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument> + <argument name="entityRelationComposite" xsi:type="object">CustomerAddressRelationsComposite</argument> + </arguments> + </type> + <type name="Magento\Customer\Model\Resource\Address\Collection"> + <arguments> + <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 21762022d84e565b42a9808389c03c6777d0d5ae..8bf281411f8b171dce5a5b627a8c3e9c3fbe4b77 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -303,6 +303,9 @@ <item name="validation" xsi:type="array"> <item name="required-entry" xsi:type="boolean">true</item> </item> + <item name="imports" xsi:type="array"> + <item name="default" xsi:type="string">${ $.provider }:data.customer.firstname</item> + </item> </item> </argument> </field> @@ -325,6 +328,9 @@ <item name="validation" xsi:type="array"> <item name="required-entry" xsi:type="boolean">true</item> </item> + <item name="imports" xsi:type="array"> + <item name="default" xsi:type="string">${ $.provider }:data.customer.lastname</item> + </item> </item> </argument> </field> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/check-email-availability.js b/app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js similarity index 66% rename from app/code/Magento/Checkout/view/frontend/web/js/action/check-email-availability.js rename to app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js index f25cd3f00ac28fb40a4a560426d5644e2f7855ba..6c658bace739f0f4343fe2b74836a7cab053febf 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/action/check-email-availability.js +++ b/app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js @@ -2,22 +2,21 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*jshint browser:true*/ -/*global define*/ define( [ 'mage/storage', - '../model/url-builder', - 'Magento_Customer/js/model/customer' + 'Magento_Checkout/js/model/url-builder' ], - function(storage, urlBuilder, customer) { - "use strict"; - return function(deferred) { - storage.post( + function (storage, urlBuilder) { + 'use strict'; + + return function (deferred, email) { + return storage.post( urlBuilder.createUrl('/customers/isEmailAvailable', {}), JSON.stringify({ - customerEmail: customer.customerData.email - }) + customerEmail: email + }), + false ).done( function (isEmailAvailable) { if (isEmailAvailable) { diff --git a/app/code/Magento/Customer/view/frontend/web/js/action/login.js b/app/code/Magento/Customer/view/frontend/web/js/action/login.js index 11dcaeec5cb4b0943bd8b5d043bb59238a4df1c5..31d928825415b94304ca8b6f57fb912f6760a8cd 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/action/login.js +++ b/app/code/Magento/Customer/view/frontend/web/js/action/login.js @@ -7,30 +7,45 @@ define( [ 'jquery', 'mage/storage', - 'Magento_Ui/js/model/errorlist', - 'Magento_Customer/js/model/customer' + 'Magento_Ui/js/model/messageList', + 'Magento_Customer/js/customer-data' ], - function($, storage, errorlist, customer) { - "use strict"; - return function(loginData, redirectUrl) { - return storage.post( - 'customer/ajax/login', - JSON.stringify(loginData) - ).done(function (response) { - if (response.errors) { - customer.increaseFailedLoginAttempt(); - errorlist.add(response); - } else { - if (redirectUrl) { - window.location.href = redirectUrl; + function($, storage, messageList, customerData) { + 'use strict'; + var callbacks = [], + action = function(loginData, redirectUrl) { + return storage.post( + 'customer/ajax/login', + JSON.stringify(loginData) + ).done(function (response) { + if (response.errors) { + messageList.addErrorMessage(response); + callbacks.forEach(function(callback) { + callback(loginData); + }); } else { - location.reload(); + callbacks.forEach(function(callback) { + callback(loginData); + }); + customerData.invalidate(['customer']); + if (redirectUrl) { + window.location.href = redirectUrl; + } else { + location.reload(); + } } - } - }).fail(function () { - customer.increaseFailedLoginAttempt(); - errorlist.add({'message': 'Could not authenticate. Please try again later'}); - }); + }).fail(function () { + messageList.addErrorMessage({'message': 'Could not authenticate. Please try again later'}); + callbacks.forEach(function(callback) { + callback(loginData); + }); + }); + }; + + action.registerLoginCallback = function(callback) { + callbacks.push(callback); }; + + return action; } ); diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index 2f5c1181ea10d44c4a4e99294dac2ee068822387..bfb277c067d57bb85961c7824bdaf3919f1340b1 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -9,7 +9,6 @@ define([ 'Magento_Customer/js/section-config', 'jquery/jquery-storageapi', 'jquery/jquery.cookie' - ], function ($, _, ko, sectionConfig) { 'use strict'; diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/address-list.js b/app/code/Magento/Customer/view/frontend/web/js/model/address-list.js new file mode 100644 index 0000000000000000000000000000000000000000..a67a3e0b693973ad41af5205b6887abef0ffa797 --- /dev/null +++ b/app/code/Magento/Customer/view/frontend/web/js/model/address-list.js @@ -0,0 +1,15 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'ko', + './customer-addresses' + ], + function(ko, defaultProvider) { + "use strict"; + return ko.observableArray(defaultProvider.getAddressItems()); + } +); \ No newline at end of file diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js new file mode 100644 index 0000000000000000000000000000000000000000..c14cffb2c59e3e8edb233a90f34e25a374688d65 --- /dev/null +++ b/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'ko', + './customer/address' + ], + function($, ko, address) { + "use strict"; + var isLoggedIn = ko.observable(window.isCustomerLoggedIn); + return { + getAddressItems: function() { + var items = []; + if (isLoggedIn) { + var customerData = window.customerData; + if (Object.keys(customerData).length) { + $.each(customerData.addresses, function (key, item) { + items.push(new address(item)); + }); + } + } + return items; + } + } + } +); \ No newline at end of file diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/customer.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer.js index 28a43254db2efdcf3e2e6e5d52b1eeca3841f9d4..25654444d6cc5ee783b134afdf41c44eaac28bdf 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/model/customer.js +++ b/app/code/Magento/Customer/view/frontend/web/js/model/customer.js @@ -9,46 +9,31 @@ define( 'ko', 'underscore', 'mage/storage', - 'Magento_Checkout/js/model/addresslist', - './customer/address' + './address-list' ], - function($, ko, _, storage, addressList, address) { + function($, ko, _, storage, addressList) { "use strict"; var isLoggedIn = ko.observable(window.isCustomerLoggedIn), - failedLoginAttempts = ko.observable(0), customerData = {}; if (isLoggedIn()) { customerData = window.customerData; - if (Object.keys(customerData).length) { - $.each(customerData.addresses, function (key, item) { - addressList.add(new address(item)); - }); - } } else { customerData = {}; } + return { customerData: customerData, customerDetails: {}, - isLoggedIn: function() { - return isLoggedIn; - }, + isLoggedIn: isLoggedIn, setIsLoggedIn: function (flag) { isLoggedIn(flag); }, - getFailedLoginAttempts: function() { - return failedLoginAttempts; - }, - increaseFailedLoginAttempt: function() { - var oldAttempts = failedLoginAttempts(); - failedLoginAttempts(++oldAttempts); - }, getBillingAddressList: function () { - return addressList.getAddresses(); + return addressList(); }, getShippingAddressList: function () { - return addressList.getAddresses(); + return addressList(); }, setDetails: function (fieldName, value) { if (fieldName) { diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js index 104655e0f2224625ceb03f07e78453fa9cfb9e14..c3f656411450d8f6a9603d7688a93d5e8f788fd7 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js +++ b/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js @@ -5,6 +5,10 @@ /*jshint browser:true jquery:true*/ /*global alert*/ define([], function() { + /** + * @param addressData + * Returns new address object + */ return function (addressData) { return { customerAddressId: addressData.id, @@ -26,9 +30,28 @@ define([], function() { prefix: addressData.prefix, suffix: addressData.suffix, vatId: addressData.vat_id, - sameAsBilling: null, + sameAsBilling: addressData.same_as_billing, + saveInAddressBook: addressData.save_in_address_book, + isDefaultShipping: function() { + return addressData.default_shipping; + }, + isDefaultBilling: function() { + return addressData.default_billing; + }, getAddressInline: function() { return addressData.inline; + }, + getType: function() { + return 'customer-address' + }, + getKey: function() { + return this.getType() + this.customerAddressId; + }, + isEditable: function() { + return false; + }, + canUseForBilling: function() { + return true; } } } diff --git a/app/code/Magento/Customer/view/frontend/web/js/view/customer-email.js b/app/code/Magento/Customer/view/frontend/web/js/view/customer-email.js new file mode 100644 index 0000000000000000000000000000000000000000..ae864756661c84ffe7ab65d320d6b80d32822bca --- /dev/null +++ b/app/code/Magento/Customer/view/frontend/web/js/view/customer-email.js @@ -0,0 +1,116 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'jquery', + 'uiComponent', + 'ko', + 'Magento_Customer/js/model/customer', + 'Magento_Customer/js/action/check-email-availability', + 'Magento_Customer/js/action/login', + 'Magento_Checkout/js/model/quote', + 'mage/validation' + ], + function ($, Component, ko, customer, checkEmailAvailability, loginAction, quote) { + "use strict"; + return Component.extend({ + defaults: { + template: 'Magento_Customer/customer-email', + email: '', + isLoading: false, + isPasswordVisible: false + }, + checkDelay: 2000, + checkRequest: null, + isEmailCheckComplete: null, + isCustomerLoggedIn: customer.isLoggedIn, + forgotPasswordUrl: window.checkoutConfig.forgotPasswordUrl, + emailCheckTimeout: 0, + + initialize: function() { + this._super(); + var self = this; + this.email.subscribe(function() { + self.emailHasChanged(); + }); + }, + + /** Initialize observable properties */ + initObservable: function () { + this._super() + .observe(['email', 'isLoading', 'isPasswordVisible']); + return this; + }, + + emailHasChanged: function () { + var self = this; + clearTimeout(this.emailCheckTimeout); + this.emailCheckTimeout = setTimeout(function () { + if (self.validateEmail()) { + self.checkEmailAvailability(); + quote.guestEmail = self.email(); + } else { + self.isPasswordVisible(false); + } + }, self.checkDelay); + + }, + + checkEmailAvailability: function() { + var self = this; + this.validateRequest(); + this.isEmailCheckComplete = $.Deferred(); + this.isLoading(true); + this.checkRequest = checkEmailAvailability(this.isEmailCheckComplete, this.email()); + + $.when(this.isEmailCheckComplete).done(function() { + self.isPasswordVisible(false); + }).fail( function() { + self.isPasswordVisible(true); + }).always(function () { + self.isLoading(false); + }); + }, + + validateRequest: function() { + /* + * If request has been sent -> abort it. + * ReadyStates for request aborting: + * 1 - The request has been set up + * 2 - The request has been sent + * 3 - The request is in process + */ + if (this.checkRequest != null && $.inArray(this.checkRequest.readyState, [1, 2, 3])) { + this.checkRequest.abort(); + this.checkRequest = null; + } + }, + + validateEmail: function() { + var loginFormSelector = 'form[data-role=email-with-possible-login]'; + $(loginFormSelector).validation(); + var validationResult = $(loginFormSelector + ' input[name=username]').valid(); + return Boolean(validationResult); + }, + + login: function(loginForm) { + var loginData = {}, + formDataArray = $(loginForm).serializeArray(); + + formDataArray.forEach(function (entry) { + loginData[entry.name] = entry.value; + }); + if (this.isPasswordVisible() + && $(loginForm).validation() + && $(loginForm).validation('isValid') + ) { + loginAction(loginData); + } + } + }); + } +); diff --git a/app/code/Magento/Customer/view/frontend/web/template/customer-email.html b/app/code/Magento/Customer/view/frontend/web/template/customer-email.html new file mode 100644 index 0000000000000000000000000000000000000000..898a3300ed78e3e2262baaf6fbf040fef297620c --- /dev/null +++ b/app/code/Magento/Customer/view/frontend/web/template/customer-email.html @@ -0,0 +1,67 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko ifnot: isCustomerLoggedIn() --> + +<!-- ko foreach: getRegion('before-login-form') --> +<!-- ko template: getTemplate() --><!-- /ko --> +<!-- /ko --> +<form class="form form-login" data-role="email-with-possible-login" + data-bind="submit:login" + method="post"> + <fieldset id="customer-email-fieldset" class="fieldset" data-bind="blockLoader: isLoading"> + <div class="field required"> + <label class="label" for="customer-email"> + <span data-bind="text: $t('Email Address')"></span> + </label> + <div class="control _with-tooltip"> + <input class="input-text" + type="email" + data-bind="textInput: email" + name="username" + data-validate="{required:true, 'validate-email':true}" + id="customer-email" /> + <!-- ko template: 'ui/form/element/helper/tooltip' --><!-- /ko --> + <span class="note"><!-- ko text: $t("(You can create an account after checkout)")--><!-- /ko --></span> + </div> + </div> + + <!--Hidden fields --> + <fieldset class="fieldset hidden-fields" data-bind="fadeVisible: isPasswordVisible"> + <div class="field"> + <label class="label" for="customer-password"> + <span data-bind="text: $t('Password')"></span> + </label> + <div class="control"> + <input class="input-text" + placeholder="optional" + type="password" + name="password" + id="customer-password" + data-validate="{required:true, 'validate-password':true}" /> + <span class="note" data-bind="text: $t('You already have an account with us. Sign in or continue as guest.')"></span> + </div> + + </div> + <!-- ko foreach: getRegion('additional-login-form-fields') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!-- /ko --> + <div class="actions-toolbar"> + <input name="context" type="hidden" value="checkout" /> + <div class="primary"> + <button type="submit" class="action login primary" data-action="checkout-method-login"><span data-bind="text: $t('Login')"></span></button> + </div> + <div class="secondary"> + <a class="action remind" data-bind="attr: { href: forgotPasswordUrl }"> + <span data-bind="text: $t('Forgot Your Password?')"></span> + </a> + </div> + </div> + </fieldset> + <!--Hidden fields --> + </fieldset> +</form> +<!-- /ko --> diff --git a/app/code/Magento/Dhl/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Dhl/view/frontend/layout/checkout_onepage_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac3abe1cd6cb6fa38d82426add0139152f4b1e5b --- /dev/null +++ b/app/code/Magento/Dhl/view/frontend/layout/checkout_onepage_index.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="step-config" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-rates-validation" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="dhl-rates-validation" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Dhl/js/view/shipping-rates-validation</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validation-rules.js b/app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validation-rules.js new file mode 100644 index 0000000000000000000000000000000000000000..9f22914a8d29b73f75c2dfc51dfc776ed284e557 --- /dev/null +++ b/app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validation-rules.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function () { + "use strict"; + return { + getRules: function() { + return { + 'postcode': { + 'required': true + }, + 'country_id': { + 'required': true + } + }; + } + }; + } +); diff --git a/app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validator.js b/app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..71dac1b92c10ff0cab212709c93478227c2262c1 --- /dev/null +++ b/app/code/Magento/Dhl/view/frontend/web/js/model/shipping-rates-validator.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'mageUtils', + './shipping-rates-validation-rules', + 'mage/translate' + ], + function ($, utils, validationRules, $t) { + "use strict"; + return { + validationErrors: [], + validate: function(address) { + var self = this; + this.validationErrors = []; + $.each(validationRules.getRules(), function(field, rule) { + if (rule.required && utils.isEmpty(address[field])) { + var message = $t('Field ') + field + $t(' is required.'); + self.validationErrors.push(message); + } + }); + return !Boolean(this.validationErrors.length); + } + }; + } +); diff --git a/app/code/Magento/Dhl/view/frontend/web/js/view/shipping-rates-validation.js b/app/code/Magento/Dhl/view/frontend/web/js/view/shipping-rates-validation.js new file mode 100644 index 0000000000000000000000000000000000000000..de18ca91237cd6affd9e4f56b167bcdbcfd056ef --- /dev/null +++ b/app/code/Magento/Dhl/view/frontend/web/js/view/shipping-rates-validation.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-rates-validation-rules', + '../model/shipping-rates-validator', + '../model/shipping-rates-validation-rules' + ], + function ( + Component, + defaultShippingRatesValidator, + defaultShippingRatesValidationRules, + dhlShippingRatesValidator, + dhlShippingRatesValidationRules + ) { + "use strict"; + defaultShippingRatesValidator.registerValidator('dhl', dhlShippingRatesValidator); + defaultShippingRatesValidationRules.registerRules('dhl', dhlShippingRatesValidationRules); + return Component; + } +); diff --git a/app/code/Magento/Directory/Helper/Data.php b/app/code/Magento/Directory/Helper/Data.php index 1f7bae3fd00d0910f2c2c9589c180bd1be37cf16..fbd071c13824eb155d3adbd91b6ee9595beb8a5c 100644 --- a/app/code/Magento/Directory/Helper/Data.php +++ b/app/code/Magento/Directory/Helper/Data.php @@ -160,28 +160,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper $cacheKey = 'DIRECTORY_REGIONS_JSON_STORE' . $this->_storeManager->getStore()->getId(); $json = $this->_configCacheType->load($cacheKey); if (empty($json)) { - $countryIds = []; - foreach ($this->getCountryCollection() as $country) { - $countryIds[] = $country->getCountryId(); - } - $collection = $this->_regCollectionFactory->create(); - $collection->addCountryFilter($countryIds)->load(); - $regions = [ - 'config' => [ - 'show_all_regions' => $this->isShowNonRequiredState(), - 'regions_required' => $this->getCountriesWithStatesRequired(), - ], - ]; - foreach ($collection as $region) { - /** @var $region \Magento\Directory\Model\Region */ - if (!$region->getRegionId()) { - continue; - } - $regions[$region->getCountryId()][$region->getRegionId()] = [ - 'code' => $region->getCode(), - 'name' => (string)__($region->getName()), - ]; - } + $regions = $this->getRegionData(); $json = $this->jsonHelper->jsonEncode($regions); if ($json === false) { $json = 'false'; @@ -324,4 +303,36 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper $store ); } + + /** + * Retrieve regions data + * + * @return array + */ + public function getRegionData() + { + $countryIds = []; + foreach ($this->getCountryCollection() as $country) { + $countryIds[] = $country->getCountryId(); + } + $collection = $this->_regCollectionFactory->create(); + $collection->addCountryFilter($countryIds)->load(); + $regions = [ + 'config' => [ + 'show_all_regions' => $this->isShowNonRequiredState(), + 'regions_required' => $this->getCountriesWithStatesRequired(), + ], + ]; + foreach ($collection as $region) { + /** @var $region \Magento\Directory\Model\Region */ + if (!$region->getRegionId()) { + continue; + } + $regions[$region->getCountryId()][$region->getRegionId()] = [ + 'code' => $region->getCode(), + 'name' => (string)__($region->getName()), + ]; + } + return $regions; + } } diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Config.php b/app/code/Magento/Directory/Model/Country/Postcode/Config.php new file mode 100644 index 0000000000000000000000000000000000000000..344938c4aaf54bc448544d2439235adddcd0700d --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/Config.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode; + +class Config implements ConfigInterface +{ + /** + * @var Config\Data + */ + protected $dataStorage; + + /** + * @param Config\Data $dataStorage + */ + public function __construct(\Magento\Directory\Model\Country\Postcode\Config\Data $dataStorage) + { + $this->dataStorage = $dataStorage; + } + + /** + * {@inheritdoc} + */ + public function getPostCodes() + { + return $this->dataStorage->get(); + } +} diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Config/Converter.php b/app/code/Magento/Directory/Model/Country/Postcode/Config/Converter.php new file mode 100644 index 0000000000000000000000000000000000000000..be9ee4dca475c8be5b5be9364a3741f1b0cde6cd --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/Config/Converter.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode\Config; + +class Converter implements \Magento\Framework\Config\ConverterInterface +{ + /** + * @var \Magento\Framework\Stdlib\BooleanUtils + */ + protected $booleanUtils; + + /** + * @param \Magento\Framework\Stdlib\BooleanUtils $booleanUtils + */ + public function __construct(\Magento\Framework\Stdlib\BooleanUtils $booleanUtils) + { + $this->booleanUtils = $booleanUtils; + } + + /** + * Convert dom node tree to array + * + * @param \DOMDocument $source + * @return array + */ + public function convert($source) + { + $result = []; + /** @var \DOMNode $zipNode */ + foreach ($source->documentElement->childNodes as $zipNode) { + if ($zipNode->nodeType != XML_ELEMENT_NODE) { + continue; + } + $groupName = $zipNode->attributes->getNamedItem('countryCode')->nodeValue; + /** @var \DOMNode $codesNode */ + foreach ($zipNode->childNodes as $codesNode) { + if ($codesNode->nodeType != XML_ELEMENT_NODE) { + continue; + } + /** @var \DOMNode $code */ + foreach ($codesNode->childNodes as $code) { + if ($code->nodeType != XML_ELEMENT_NODE + || !$this->booleanUtils->toBoolean($code->attributes->getNamedItem('active')->nodeValue) + ) { + continue; + } + $result[$groupName][$code->attributes->getNamedItem('id')->nodeValue] = [ + 'example' => $code->attributes->getNamedItem('example')->nodeValue, + 'pattern' => $code->nodeValue + ]; + } + } + } + return $result; + } +} diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Config/Data.php b/app/code/Magento/Directory/Model/Country/Postcode/Config/Data.php new file mode 100644 index 0000000000000000000000000000000000000000..b3dc1a7a6c7a3c575172f6d2ddc8e87efff99488 --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/Config/Data.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode\Config; + +class Data extends \Magento\Framework\Config\Data +{ + /** + * @param \Magento\Directory\Model\Country\Postcode\Config\Reader $reader + * @param \Magento\Framework\Config\CacheInterface $cache + */ + public function __construct( + \Magento\Directory\Model\Country\Postcode\Config\Reader $reader, + \Magento\Framework\Config\CacheInterface $cache + ) { + parent::__construct($reader, $cache, 'country_postcodes'); + } +} diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php b/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php new file mode 100644 index 0000000000000000000000000000000000000000..7fb5878318dccc009756dc4feacf15ab015f22fd --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/Config/Reader.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode\Config; + +class Reader extends \Magento\Framework\Config\Reader\Filesystem +{ + /** + * Construct the FileSystem Reader Class + * + * @param \Magento\Framework\Config\FileResolverInterface $fileResolver + * @param Converter $converter + * @param SchemaLocator $schemaLocator + * @param \Magento\Framework\Config\ValidationStateInterface $validationState + * @param string $fileName + * @param array $idAttributes + * @param string $domDocumentClass + * @param string $defaultScope + */ + public function __construct( + \Magento\Framework\Config\FileResolverInterface $fileResolver, + Converter $converter, + \Magento\Directory\Model\Country\Postcode\Config\SchemaLocator $schemaLocator, + \Magento\Framework\Config\ValidationStateInterface $validationState, + $fileName = 'zip_codes.xml', + $idAttributes = [], + $domDocumentClass = 'Magento\Framework\Config\Dom', + $defaultScope = 'global' + ) { + parent::__construct( + $fileResolver, + $converter, + $schemaLocator, + $validationState, + $fileName, + $idAttributes, + $domDocumentClass, + $defaultScope + ); + } +} diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Config/SchemaLocator.php b/app/code/Magento/Directory/Model/Country/Postcode/Config/SchemaLocator.php new file mode 100644 index 0000000000000000000000000000000000000000..5984a2e501b71983b6c9c6a00bdf546e7f81827a --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/Config/SchemaLocator.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode\Config; + +class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface +{ + /** + * Path to corresponding XSD file with validation rules for both individual and merged configs + * + * @var string + */ + private $schema; + + /** + * @param \Magento\Framework\Module\Dir\Reader $moduleReader + */ + public function __construct(\Magento\Framework\Module\Dir\Reader $moduleReader) + { + $this->schema = $moduleReader->getModuleDir('etc', 'Magento_Directory') . '/zip_codes.xsd'; + } + + /** + * {@inheritdoc} + */ + public function getSchema() + { + return $this->schema; + } + + /** + * {@inheritdoc} + */ + public function getPerFileSchema() + { + return $this->schema; + } +} diff --git a/app/code/Magento/Directory/Model/Country/Postcode/ConfigInterface.php b/app/code/Magento/Directory/Model/Country/Postcode/ConfigInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..ac1d487d47575c814c8c364f3e4d438494aaca87 --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/ConfigInterface.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode; + +interface ConfigInterface +{ + + /** + * Returns array of postcodes validation patterns + * + * @return array + */ + public function getPostCodes(); +} diff --git a/app/code/Magento/Directory/Model/Country/Postcode/Validator.php b/app/code/Magento/Directory/Model/Country/Postcode/Validator.php new file mode 100644 index 0000000000000000000000000000000000000000..a57d379683b3c802f1ac7060e5f8460a88416907 --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/Validator.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode; + +class Validator implements ValidatorInterface +{ + /** + * @var ConfigInterface + */ + protected $postCodesConfig; + + /** + * @param ConfigInterface $postCodesConfig + */ + public function __construct(\Magento\Directory\Model\Country\Postcode\ConfigInterface $postCodesConfig) + { + $this->postCodesConfig = $postCodesConfig; + } + + /** + * {@inheritdoc} + */ + public function validate($postcode, $countryId) + { + $postCodes = $this->postCodesConfig->getPostCodes(); + if (isset($postCodes[$countryId]) && is_array($postCodes[$countryId])) { + $patterns = $postCodes[$countryId]; + foreach ($patterns as $pattern) { + preg_match('/' . $pattern['pattern'] . '/', $postcode, $matches); + if (count($matches)) { + return true; + } + } + return false; + } + throw new \InvalidArgumentException('Provided countryId does not exist.'); + } +} diff --git a/app/code/Magento/Directory/Model/Country/Postcode/ValidatorInterface.php b/app/code/Magento/Directory/Model/Country/Postcode/ValidatorInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..b6517be656a31a4ace53ffec657867ae22360ace --- /dev/null +++ b/app/code/Magento/Directory/Model/Country/Postcode/ValidatorInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode; + +interface ValidatorInterface +{ + /** + * Validate postcode for selected country by mask + * + * @param string $postcode + * @param string $countryId + * @return bool + * @throws \InvalidArgumentException + */ + public function validate($postcode, $countryId); +} diff --git a/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/ConverterTest.php b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/ConverterTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a4f4d4b5bbd79536735e3a78a5b1b99bf0ef7893 --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/ConverterTest.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Test\Unit\Model\Country\Postcode\Config; + +class ConverterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Customer\Model\Address\Config\Converter + */ + protected $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $booleanUtilsMock; + + public function setUp() + { + $this->booleanUtilsMock = $this->getMock('Magento\Framework\Stdlib\BooleanUtils', [], [], '', false); + $this->model = new \Magento\Directory\Model\Country\Postcode\Config\Converter($this->booleanUtilsMock); + } + + public function testConvert() + { + $inputData = new \DOMDocument(); + $this->booleanUtilsMock->expects($this->any())->method('toBoolean')->willReturn(true); + $inputData->load(__DIR__ . '/../../../../_files/zip_codes.xml'); + $expectedResult = require __DIR__ . '/../../../../_files/zip_codes.php'; + $this->assertEquals($expectedResult, $this->model->convert($inputData)); + } +} diff --git a/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/DataTest.php b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/DataTest.php new file mode 100644 index 0000000000000000000000000000000000000000..18663e83e74f9c63b1a2ca9f51e9b84cc8d82882 --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/DataTest.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Test\Unit\Model\Country\Postcode\Config; + +class DataTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $readerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $cacheMock; + + protected function setUp() + { + $this->readerMock = $this->getMockBuilder( + 'Magento\Directory\Model\Country\Postcode\Config\Reader' + )->disableOriginalConstructor()->getMock(); + $this->cacheMock = $this->getMockBuilder( + 'Magento\Framework\App\Cache\Type\Config' + )->disableOriginalConstructor()->getMock(); + } + + public function testGet() + { + $expected = ['someData' => ['someValue', 'someKey' => 'someValue']]; + $this->cacheMock->expects($this->any())->method('load')->will($this->returnValue(serialize($expected))); + $configData = new \Magento\Directory\Model\Country\Postcode\Config\Data($this->readerMock, $this->cacheMock); + + $this->assertEquals($expected, $configData->get()); + } +} diff --git a/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/ReaderTest.php b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/ReaderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..066dcbcbd6668e319b1ea9c9e9b2a5c728f69064 --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/ReaderTest.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Test\Unit\Model\Country\Postcode\Config; + +class ReaderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Sales\Model\Config\Reader + */ + protected $reader; + + /** + * Prepare parameters + */ + public function setUp() + { + $fileResolver = $this->getMockBuilder( + 'Magento\Framework\App\Config\FileResolver' + )->disableOriginalConstructor()->getMock(); + $converter = $this->getMockBuilder( + 'Magento\Directory\Model\Country\Postcode\Config\Converter' + )->disableOriginalConstructor()->getMock(); + $schema = $this->getMockBuilder( + 'Magento\Directory\Model\Country\Postcode\Config\SchemaLocator' + )->disableOriginalConstructor()->getMock(); + $validator = $this->getMockBuilder( + 'Magento\Framework\Config\ValidationStateInterface' + )->disableOriginalConstructor()->getMock(); + $this->reader = new \Magento\Directory\Model\Country\Postcode\Config\Reader( + $fileResolver, + $converter, + $schema, + $validator + ); + } + + /** + * Test creating object + */ + public function testInstanceof() + { + $this->assertInstanceOf('Magento\Directory\Model\Country\Postcode\Config\Reader', $this->reader); + } +} diff --git a/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/SchemaLocatorTest.php b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/SchemaLocatorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..794dc5a1ce9fe90129b8e8f47e8f73a004d1f2e6 --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/Config/SchemaLocatorTest.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Test\Unit\Model\Country\Postcode\Config; + +class SchemaLocatorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $moduleReaderMock; + + /** + * @var \Magento\Directory\Model\Country\Postcode\Config\SchemaLocator + */ + protected $model; + + protected function setUp() + { + $this->moduleReaderMock = $this->getMock('Magento\Framework\Module\Dir\Reader', [], [], '', false); + $this->moduleReaderMock->expects( + $this->any() + )->method( + 'getModuleDir' + )->with( + 'etc', + 'Magento_Directory' + )->will( + $this->returnValue('schema_dir') + ); + + $this->model = new \Magento\Directory\Model\Country\Postcode\Config\SchemaLocator($this->moduleReaderMock); + } + + public function testGetSchema() + { + $this->assertEquals('schema_dir/zip_codes.xsd', $this->model->getSchema()); + } + + public function testGetPerFileSchema() + { + $this->assertEquals('schema_dir/zip_codes.xsd', $this->model->getPerFileSchema()); + } +} diff --git a/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/ConfigTest.php b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/ConfigTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d24ead182cb394c290616125b3084a466eb8a385 --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/ConfigTest.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Test\Unit\Model\Country\Postcode; + +class ConfigTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $dataStorageMock; + + protected function setUp() + { + $this->dataStorageMock = $this->getMock( + '\Magento\Directory\Model\Country\Postcode\Config\Data', + [], + [], + '', + false + ); + } + + public function testGet() + { + $expected = ['US' => ['pattern_01' => 'pattern_01', 'pattern_02' => 'pattern_02']]; + $this->dataStorageMock->expects($this->once())->method('get')->willReturn($expected); + $configData = new \Magento\Directory\Model\Country\Postcode\Config($this->dataStorageMock); + $this->assertEquals($expected, $configData->getPostCodes()); + } +} diff --git a/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/ValidatorTest.php b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/ValidatorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7bf2562a6ed01b9f0d725a50ba9ce6eae6bf9c01 --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/Model/Country/Postcode/ValidatorTest.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Test\Unit\Model\Country\Postcode; + +class ValidatorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $postcodesConfigMock; + + /** + * @var \Magento\Directory\Model\Country\Postcode\Validator + */ + protected $model; + + protected function setUp() + { + $this->postcodesConfigMock = $this->getMock( + '\Magento\Directory\Model\Country\Postcode\Config', + [], + [], + '', + false + ); + $postCodes = [ + 'US' => [ + 'pattern_1' => ['pattern' => '^[0-9]{5}\-[0-9]{4}$'], + 'pattern_2' => ['pattern' => '^[0-9]{5}$'] + ] + ]; + $this->postcodesConfigMock->expects($this->once())->method('getPostCodes')->willReturn($postCodes); + $this->model = new \Magento\Directory\Model\Country\Postcode\Validator($this->postcodesConfigMock); + } + + public function testValidatePositive() + { + $postcode = '12345-6789'; + $countryId = 'US'; + $this->assertTrue($this->model->validate($postcode, $countryId)); + } + + public function testValidateNegative() + { + $postcode = 'POST-CODE'; + $countryId = 'US'; + $this->assertFalse($this->model->validate($postcode, $countryId)); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Provided countryId does not exist. + */ + public function testValidateThrowExceptionIfCountryDoesNotExist() + { + $postcode = '12345-6789'; + $countryId = 'QQ'; + $this->assertFalse($this->model->validate($postcode, $countryId)); + } +} diff --git a/app/code/Magento/Directory/Test/Unit/_files/zip_codes.php b/app/code/Magento/Directory/Test/Unit/_files/zip_codes.php new file mode 100644 index 0000000000000000000000000000000000000000..7a151e73a3e72cd6b7c86874441aeaa2a1106c87 --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/_files/zip_codes.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'US' => [ + 'pattern_1' => [ + 'example' => 12345, + 'pattern' => '^[0-9]{5}\-[0-9]{4}$' + ], + 'pattern_2' => [ + 'example' => 12345, + 'pattern' => '^[0-9]{5}$' + ] + ] +]; diff --git a/app/code/Magento/Directory/Test/Unit/_files/zip_codes.xml b/app/code/Magento/Directory/Test/Unit/_files/zip_codes.xml new file mode 100644 index 0000000000000000000000000000000000000000..bbe7582ea62c267702eb25b4415ea01ac9585e8f --- /dev/null +++ b/app/code/Magento/Directory/Test/Unit/_files/zip_codes.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../Directory/etc/zip_codes.xsd"> + <zip countryCode="US"> + <codes> + <code id="pattern_1" example="12345" active="true">^[0-9]{5}\-[0-9]{4}$</code> + <code id="pattern_2" example="12345" active="true">^[0-9]{5}$</code> + </codes> + </zip> +</config> diff --git a/app/code/Magento/Directory/etc/di.xml b/app/code/Magento/Directory/etc/di.xml index 36d16743f8363c39e4aa87e8019fcb0a51014af5..c1e11e69808025b7013f0e5837ec784ca0f40be3 100644 --- a/app/code/Magento/Directory/etc/di.xml +++ b/app/code/Magento/Directory/etc/di.xml @@ -27,4 +27,6 @@ <argument name="helperData" xsi:type="object">DirectoryHelperDataProxy</argument> </arguments> </type> + <preference for="Magento\Directory\Model\Country\Postcode\ConfigInterface" type="Magento\Directory\Model\Country\Postcode\Config" /> + <preference for="Magento\Directory\Model\Country\Postcode\ValidatorInterface" type="Magento\Directory\Model\Country\Postcode\Validator" /> </config> diff --git a/app/code/Magento/Directory/etc/zip_codes.xml b/app/code/Magento/Directory/etc/zip_codes.xml new file mode 100644 index 0000000000000000000000000000000000000000..dfca9b740fa036ae66a94aaac0fc60154a79a626 --- /dev/null +++ b/app/code/Magento/Directory/etc/zip_codes.xml @@ -0,0 +1,487 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../Directory/etc/zip_codes.xsd"> + <zip countryCode="DZ"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="AS"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="AR"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="AM"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="AU"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="AT"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="AZ"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + <code id="pattern_2" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="BD"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="BY"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="BE"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="BA"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="BR"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + <code id="pattern_2" active="true" example="12345-678">^[0-9]{5}\-[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="BN"> + <codes> + <code id="pattern_1" active="true" example="AB1234">^[a-zA-z]{2}[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="BG"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="CA"> + <codes> + <code id="pattern_1" active="true" example="A1B 2C3">^[a-zA-z]{1}[0-9]{1}[a-zA-z]{1}\s[0-9]{1}[a-zA-z]{1}[0-9]{1}$</code> + </codes> + </zip> + <zip countryCode="IC"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="CN"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="HR"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="CU"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="CY"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="CZ"> + <codes> + <code id="pattern_1" active="true" example="123 45">^[0-9]{3}\s[0-9]{2}$</code> + </codes> + </zip> + <zip countryCode="DK"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="EE"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="FI"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="FR"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="GF"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="GE"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="DE"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="GR"> + <codes> + <code id="pattern_1" active="true" example="123 45">^[0-9]{3}\s[0-9]{2}$</code> + </codes> + </zip> + <zip countryCode="GL"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="GP"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="GU"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="GG"> + <codes> + <code id="pattern_1" active="true" example="AB1 2CD">^[a-zA-Z]{2}[0-9]{1}\s[0-9]{1}[a-zA-Z]{2}$</code> + </codes> + </zip> + <zip countryCode="HU"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="IS"> + <codes> + <code id="pattern_1" active="true" example="123">^[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="IN"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="ID"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="IL"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="IT"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="JP"> + <codes> + <code id="pattern_1" active="true" example="123-4567">^[0-9]{3}-[0-9]{4}$</code> + <code id="pattern_2" active="true" example="123">^[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="JE"> + <codes> + <code id="pattern_1" active="true" example="AB1 2CD">^[a-zA-Z]{2}[0-9]{1}\s[0-9]{1}[a-zA-Z]{2}$</code> + </codes> + </zip> + <zip countryCode="KZ"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="KE"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="KR"> + <codes> + <code id="pattern_1" active="true" example="123-456">^[0-9]{3}-[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="KG"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="LV"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="LI"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="LT"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="LU"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="MK"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="MG"> + <codes> + <code id="pattern_1" active="true" example="123">^[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="MY"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="MV"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + <code id="pattern_2" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="MT"> + <codes> + <code id="pattern_1" active="true" example="ABC 123">^[a-zA-Z]{3}\s[0-9]{3}$</code> + <code id="pattern_2" active="true" example="ABC 12">^[a-zA-Z]{3}\s[0-9]{2}$</code> + </codes> + </zip> + <zip countryCode="MH"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="MQ"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="MX"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="MD"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="MC"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="MN"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="MA"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="NL"> + <codes> + <code id="pattern_1" active="true" example="1234 AB">^[0-9]{4}\s[a-zA-Z]{2}$</code> + </codes> + </zip> + <zip countryCode="NO"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="PK"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="PH"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="PL"> + <codes> + <code id="pattern_1" active="true" example="12-345">^[0-9]{2}-[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="PT"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + <code id="pattern_2" active="true" example="1234-567">^[0-9]{4}-[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="PR"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="RE"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="RO"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="RU"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="MP"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="CS"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="SG"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="SK"> + <codes> + <code id="pattern_1" active="true" example="123 45">^[0-9]{3}\s[0-9]{2}$</code> + </codes> + </zip> + <zip countryCode="SI"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="ZA"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="ES"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="XY"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="SZ"> + <codes> + <code id="pattern_1" active="true" example="A123">^[a-zA-Z]{1}[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="SE"> + <codes> + <code id="pattern_1" active="true" example="123 45">^[0-9]{3}\s[0-9]{2}$</code> + </codes> + </zip> + <zip countryCode="CH"> + <codes> + <code id="pattern_1" active="true" example="1234">^[0-9]{4}$</code> + </codes> + </zip> + <zip countryCode="TW"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + <code id="pattern_2" active="true" example="123">^[0-9]{3}$</code> + </codes> + </zip> + <zip countryCode="TJ"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="TH"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="TR"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="TM"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="UA"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="GB"> + <codes> + <code id="pattern_1" active="true" example="AB12 3CD">^[a-zA-Z]{2}[0-9]{2}\s[0-9]{1}[a-zA-Z]{2}$</code> + <code id="pattern_2" active="true" example="A1B 2CD">^[a-zA-Z]{1}[0-9]{1}[a-zA-Z]{1}\s[0-9]{1}[a-zA-Z]{2}$</code> + <code id="pattern_3" active="true" example="AB1 2CD">^[a-zA-Z]{2}[0-9]{1}\s[0-9]{1}[a-zA-Z]{2}$</code> + <code id="pattern_4" active="true" example="AB1C 2DF">^[a-zA-Z]{2}[0-9]{1}[a-zA-Z]{1}\s[0-9]{1}[a-zA-Z]{2}$</code> + <code id="pattern_5" active="true" example="A12 3BC">^[a-zA-Z]{1}[0-9]{2}\s[0-9]{1}[a-zA-Z]{2}$</code> + <code id="pattern_6" active="true" example="A1 2BC">^[a-zA-Z]{1}[0-9]{1}\s[0-9]{1}[a-zA-Z]{2}$</code> + </codes> + </zip> + <zip countryCode="US"> + <codes> + <code id="pattern_1" active="true" example="12345-6789">^[0-9]{5}\-[0-9]{4}$</code> + <code id="pattern_2" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="UY"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> + <zip countryCode="UZ"> + <codes> + <code id="pattern_1" active="true" example="123456">^[0-9]{6}$</code> + </codes> + </zip> + <zip countryCode="VI"> + <codes> + <code id="pattern_1" active="true" example="12345">^[0-9]{5}$</code> + </codes> + </zip> +</config> diff --git a/app/code/Magento/Directory/etc/zip_codes.xsd b/app/code/Magento/Directory/etc/zip_codes.xsd new file mode 100644 index 0000000000000000000000000000000000000000..5400633a0df327bc20546c074d4b5b89d6ccdd12 --- /dev/null +++ b/app/code/Magento/Directory/etc/zip_codes.xsd @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="config" type="configType"> + </xs:element> + + <xs:complexType name="zipType"> + <xs:sequence> + <xs:element type="codesType" name="codes"/> + </xs:sequence> + <xs:attribute type="xs:string" name="countryCode" use="required"/> + </xs:complexType> + + <xs:complexType name="codesType"> + <xs:sequence> + <xs:element type="codeType" name="code" maxOccurs="unbounded" minOccurs="0"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="configType"> + <xs:sequence> + <xs:element type="zipType" name="zip" maxOccurs="unbounded" minOccurs="1"/> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="codeType"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute type="xs:string" name="id" use="required"/> + <xs:attribute type="xs:string" name="example" use="required"/> + <xs:attribute type="xs:boolean" name="active" use="optional"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> +</xs:schema> \ No newline at end of file diff --git a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php index 96465ce1dfb580896dec931e5ee40ea2c7fec76a..0c36e420156d691b5a2cd7f1db7691117bc9ff7e 100755 --- a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php +++ b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php @@ -896,6 +896,7 @@ abstract class AbstractCollection extends \Magento\Framework\Data\Collection\Abs \Magento\Framework\Profiler::start('set_orig_data'); foreach ($this->_items as $item) { $item->setOrigData(); + $this->beforeAddLoadedItem($item); } \Magento\Framework\Profiler::stop('set_orig_data'); diff --git a/app/code/Magento/Eav/Model/Entity/Collection/VersionControl/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/VersionControl/AbstractCollection.php new file mode 100644 index 0000000000000000000000000000000000000000..57e071e2f846dbfd51e1de43ba6c49ebdf0eb2b8 --- /dev/null +++ b/app/code/Magento/Eav/Model/Entity/Collection/VersionControl/AbstractCollection.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Eav\Model\Entity\Collection\VersionControl; + +/** + * Class Abstract Collection + */ +abstract class AbstractCollection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection +{ + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot + */ + protected $entitySnapshot; + + /** + * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory + * @param \Psr\Log\LoggerInterface $logger + * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy + * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param \Magento\Eav\Model\Config $eavConfig + * @param \Magento\Framework\App\Resource $resource + * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory + * @param \Magento\Eav\Model\Resource\Helper $resourceHelper + * @param \Magento\Framework\Validator\UniversalFactory $universalFactory + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, + * @param mixed $connection + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __construct( + \Magento\Framework\Data\Collection\EntityFactory $entityFactory, + \Psr\Log\LoggerInterface $logger, + \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, + \Magento\Framework\Event\ManagerInterface $eventManager, + \Magento\Eav\Model\Config $eavConfig, + \Magento\Framework\App\Resource $resource, + \Magento\Eav\Model\EntityFactory $eavEntityFactory, + \Magento\Eav\Model\Resource\Helper $resourceHelper, + \Magento\Framework\Validator\UniversalFactory $universalFactory, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, + $connection = null + ) { + $this->entitySnapshot = $entitySnapshot; + + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $eavConfig, + $resource, + $eavEntityFactory, + $resourceHelper, + $universalFactory, + $connection + ); + } + + /** + * @inheritdoc + */ + public function fetchItem() + { + $item = parent::fetchItem(); + if ($item) { + $this->entitySnapshot->registerSnapshot($item); + } + return $item; + } + + /** + * @inheritdoc + */ + protected function beforeAddLoadedItem(\Magento\Framework\Object $item) + { + $this->entitySnapshot->registerSnapshot($item); + return $item; + } +} diff --git a/app/code/Magento/Eav/Model/Entity/VersionControl/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/VersionControl/AbstractEntity.php new file mode 100644 index 0000000000000000000000000000000000000000..781c1baae9a6e564cdad284fe5d6e175489bb8f0 --- /dev/null +++ b/app/code/Magento/Eav/Model/Entity/VersionControl/AbstractEntity.php @@ -0,0 +1,118 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Eav\Model\Entity\VersionControl; + +/** + * Class AbstractEntity + */ +abstract class AbstractEntity extends \Magento\Eav\Model\Entity\AbstractEntity +{ + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot + */ + protected $entitySnapshot; + + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite + */ + protected $entityRelationComposite; + + /** + * @param \Magento\Eav\Model\Entity\Context $context + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite + * @param array $data + */ + public function __construct( + \Magento\Eav\Model\Entity\Context $context, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, + $data = [] + ) { + $this->entitySnapshot = $entitySnapshot; + $this->entityRelationComposite = $entityRelationComposite; + + parent::__construct($context, $data); + } + + /** + * @inheritdoc + */ + protected function _afterLoad(\Magento\Framework\Object $object) + { + $this->entitySnapshot->registerSnapshot($object); + return parent::_afterLoad($object); + } + + /** + * @inheritdoc + */ + public function save(\Magento\Framework\Model\AbstractModel $object) + { + /** + * Direct deleted items to delete method + */ + if ($object->isDeleted()) { + return $this->delete($object); + } + + $this->beginTransaction(); + + try { + if (!$this->isModified($object)) { + $this->entityRelationComposite->processRelations($object); + $this->commit(); + return $this; + } + + $object->validateBeforeSave(); + $object->beforeSave(); + + if ($object->isSaveAllowed()) { + if (!$this->isPartialSave()) { + $this->loadAllAttributes($object); + } + + if ($this->getEntityTable() == \Magento\Eav\Model\Entity::DEFAULT_ENTITY_TABLE + && !$object->getEntityTypeId() + ) { + $object->setEntityTypeId($this->getTypeId()); + } + + $object->setParentId((int)$object->getParentId()); + + $this->objectRelationProcessor->validateDataIntegrity($this->getEntityTable(), $object->getData()); + + $this->_beforeSave($object); + $this->_processSaveData($this->_collectSaveData($object)); + $this->_afterSave($object); + $this->entitySnapshot->registerSnapshot($object); + $object->afterSave(); + $this->entityRelationComposite->processRelations($object); + } + + $this->addCommitCallback([$object, 'afterCommitCallback'])->commit(); + $object->setHasDataChanges(false); + } catch (\Exception $e) { + $this->rollBack(); + $object->setHasDataChanges(true); + throw $e; + } + + return $this; + } + + /** + * Checks if entity was modified + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return bool + */ + protected function isModified(\Magento\Framework\Model\AbstractModel $object) + { + return $this->entitySnapshot->isModified($object); + } +} diff --git a/app/code/Magento/Eav/Model/Entity/VersionControl/Metadata.php b/app/code/Magento/Eav/Model/Entity/VersionControl/Metadata.php new file mode 100644 index 0000000000000000000000000000000000000000..c628f450b7a18a2197c24756bec82c0a6801e8c0 --- /dev/null +++ b/app/code/Magento/Eav/Model/Entity/VersionControl/Metadata.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Eav\Model\Entity\VersionControl; + +/** + * Class Metadata represents a list of entity fields that are applicable for persistence operations + */ +class Metadata extends \Magento\Framework\Model\Resource\Db\VersionControl\Metadata +{ + /** + * Returns list of entity fields that are applicable for persistence operations + * + * @param \Magento\Framework\Object $entity + * @return array + */ + public function getFields(\Magento\Framework\Object $entity) + { + $entityClass = get_class($entity); + if (!isset($this->metadataInfo[$entityClass])) { + $fields = $entity->getResource()->getReadConnection()->describeTable( + $entity->getResource()->getEntityTable() + ); + + $fields = array_merge($fields, $entity->getAttributes()); + + $fields = array_fill_keys( + array_keys($fields), + null + ); + + $this->metadataInfo[$entityClass] = $fields; + } + + return $this->metadataInfo[$entityClass]; + } +} diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php similarity index 99% rename from app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractTest.php rename to app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php index 3034b99b8714fa00a525568147f29c554be3db85..cce1b9d07a087bc140f09acb27b5c43b86570c0e 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php @@ -7,7 +7,7 @@ namespace Magento\Eav\Test\Unit\Model\Entity; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -class AbstractTest extends \PHPUnit_Framework_TestCase +class AbstractEntityTest extends \PHPUnit_Framework_TestCase { /** * Entity model to be tested @@ -115,7 +115,7 @@ class AbstractTest extends \PHPUnit_Framework_TestCase * * @return \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\DB\Adapter\Pdo\Mysql */ - private function _getAdapterMock() + protected function _getAdapterMock() { $adapter = $this->getMock( 'Magento\Framework\DB\Adapter\Pdo\Mysql', diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php index cd7b8d2bc528bc197164bbecd83e58920dfe76b8..4d89903528b32dafe7beebaf68028b6f62eb848a 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php @@ -5,10 +5,17 @@ */ namespace Magento\Eav\Test\Unit\Model\Entity\Collection; +use Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionStub; + +/** + * AbstractCollection test + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase { /** - * @var \Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionStub|\PHPUnit_Framework_MockObject_MockObject + * @var AbstractCollectionStub|\PHPUnit_Framework_MockObject_MockObject */ protected $model; @@ -57,6 +64,11 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase */ protected $validatorFactoryMock; + /** + * @var \Magento\Framework\DB\Statement\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject + */ + protected $statementMock; + public function setUp() { $this->coreEntityFactoryMock = $this->getMock( @@ -100,6 +112,7 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase $this->entityFactoryMock = $this->getMock('Magento\Eav\Model\EntityFactory', [], [], '', false); /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject */ $connectionMock = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false); + $this->statementMock = $this->getMock('Magento\Framework\DB\Statement\Pdo\Mysql', ['fetch'], [], '', false); /** @var $selectMock \Zend_Db_Select|\PHPUnit_Framework_MockObject_MockObject */ $selectMock = $this->getMock('Zend_Db_Select', [], [], '', false); $this->coreEntityFactoryMock->expects( @@ -110,6 +123,7 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase $this->returnCallback([$this, 'getMagentoObject']) ); $connectionMock->expects($this->any())->method('select')->will($this->returnValue($selectMock)); + $connectionMock->expects($this->any())->method('query')->willReturn($this->statementMock); $this->coreResourceMock->expects( $this->any() @@ -119,11 +133,11 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase $this->returnValue($connectionMock) ); $entityMock = $this->getMock('Magento\Eav\Model\Entity\AbstractEntity', [], [], '', false); - $entityMock->expects($this->once())->method('getReadConnection')->will($this->returnValue($connectionMock)); - $entityMock->expects($this->once())->method('getDefaultAttributes')->will($this->returnValue([])); + $entityMock->expects($this->any())->method('getReadConnection')->will($this->returnValue($connectionMock)); + $entityMock->expects($this->any())->method('getDefaultAttributes')->will($this->returnValue([])); $this->validatorFactoryMock->expects( - $this->once() + $this->any() )->method( 'create' )->with( @@ -132,7 +146,7 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase $this->returnValue($entityMock) ); - $this->model = new \Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionStub( + $this->model = new AbstractCollectionStub( $this->coreEntityFactoryMock, $this->loggerMock, $this->fetchStrategyMock, diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionStub.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionStub.php new file mode 100644 index 0000000000000000000000000000000000000000..ab2aa4dacd95e3f15d879205d09bf31dbd52bf9d --- /dev/null +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionStub.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl; + +/** + * Stub for version control abstract collection model. + */ +class AbstractCollectionStub extends \Magento\Eav\Model\Entity\Collection\VersionControl\AbstractCollection +{ + /** + * Retrieve item by id + * + * @param mixed $id + * @return \Magento\Framework\Object + */ + public function getItemById($id) + { + if (isset($this->_itemsById[$id])) { + return $this->_itemsById[$id]; + } + return null; + } + + /** + * Initialize collection + * + * @return void + */ + protected function _construct() + { + return $this->_init('Magento\Framework\Object', 'test_entity_model'); + } +} diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f3c890c71a1c0aed698a56ce0ff652c23a9f5c2f --- /dev/null +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionTest.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl; + +use Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl\AbstractCollectionStub; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +/** + * Test for version control abstract collection model. + */ +class AbstractCollectionTest extends \Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionTest +{ + /** + * Subject of testing. + * + * @var AbstractCollectionStub|\PHPUnit_Framework_MockObject_MockObject + */ + protected $subject; + + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entitySnapshot; + + public function setUp() + { + parent::setUp(); + + $objectManager = new ObjectManager($this); + + $this->entitySnapshot = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', + ['registerSnapshot'], + [], + '', + false + ); + + $this->subject = $objectManager->getObject( + 'Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl\AbstractCollectionStub', + [ + 'entityFactory' => $this->coreEntityFactoryMock, + 'universalFactory' => $this->validatorFactoryMock, + 'entitySnapshot' => $this->entitySnapshot + ] + ); + } + + /** + * @param array $data + * @dataProvider fetchItemDataProvider + */ + public function testFetchItem(array $data) + { + $item = $this->getMagentoObject()->setData($data); + + $this->statementMock->expects($this->once()) + ->method('fetch') + ->willReturn($data); + + if (!$data) { + $this->entitySnapshot->expects($this->never())->method('registerSnapshot'); + + $this->assertEquals(false, $this->subject->fetchItem()); + } else { + $this->entitySnapshot->expects($this->once())->method('registerSnapshot')->with($item); + + $this->assertEquals($item, $this->subject->fetchItem()); + } + } + + public static function fetchItemDataProvider() + { + return [ + [[]], + [['attribute' => 'test']] + ]; + } +} diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/AbstractEntityTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/AbstractEntityTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9c1865c483f8f3e048b6e7815fe919fdbed82ad9 --- /dev/null +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/AbstractEntityTest.php @@ -0,0 +1,192 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Eav\Test\Unit\Model\Entity\VersionControl; + +use Magento\Eav\Model\Entity\VersionControl\AbstractEntity; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +/** + * Test for version control abstract entity model. + */ +class AbstractEntityTest extends \Magento\Eav\Test\Unit\Model\Entity\AbstractEntityTest +{ + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entitySnapshot; + + /** + * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entityRelationComposite; + + protected function setUp() + { + $this->entitySnapshot = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', + ['isModified', 'registerSnapshot'], + [], + '', + false + ); + + $this->entityRelationComposite = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite', + ['processRelations'], + [], + '', + false + ); + + parent::setUp(); + } + + /** + * @param string $attributeCode + * @param int $attributeSetId + * @param array $productData + * @param array $productOrigData + * + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @dataProvider productAttributesDataProvider + */ + public function testSave($attributeCode, $attributeSetId, $productData, $productOrigData) + { + $object = $this->getMock( + 'Magento\Catalog\Model\Product', + ['getOrigData', '__wakeup', 'beforeSave', 'afterSave', 'validateBeforeSave'], + [], + '', + false + ); + + $object->setEntityTypeId(1); + foreach ($productData as $key => $value) { + $object->setData($key, $value); + } + $object->expects($this->any())->method('getOrigData')->will($this->returnValue($productOrigData)); + + $entityType = new \Magento\Framework\Object(); + $entityType->setEntityTypeCode('test'); + $entityType->setEntityTypeId(0); + $entityType->setEntityTable('table'); + + $attributes = $this->_getAttributes(); + + $attribute = $this->_getAttributeMock($attributeCode, $attributeSetId); + + /** @var $backendModel \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend */ + $backendModel = $this->getMock( + 'Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend', + [ + 'getBackend', + 'getBackendTable', + 'getAffectedFields', + 'isStatic', + 'getEntityValueId', + 'getEntityIdField' + ] + ); + + $backendModel->expects( + $this->once() + )->method( + 'getAffectedFields' + )->will( + $this->returnValue(['test_table' => [['value_id' => 0, 'attribute_id' => $attributeCode]]]) + ); + + $backendModel->expects($this->any())->method('isStatic')->will($this->returnValue(false)); + $backendModel->expects($this->never())->method('getEntityValueId'); + $backendModel->expects( + isset($productData['entity_id']) ? $this->never() : $this->once() + )->method( + 'getEntityIdField' + )->will( + $this->returnValue('entity_id') + ); + + $backendModel->setAttribute($attribute); + + $attribute->expects($this->any())->method('getBackend')->will($this->returnValue($backendModel)); + $attribute->setId(222); + $attributes[$attributeCode] = $attribute; + $eavConfig = $this->getMockBuilder('Magento\Eav\Model\Config') + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new ObjectManager($this); + + $this->entitySnapshot->expects($this->once())->method('isModified')->willReturn(true); + $this->entitySnapshot->expects($this->once())->method('registerSnapshot')->with($object); + + $this->entityRelationComposite->expects($this->once())->method('processRelations')->with($object); + + $arguments = $objectManager->getConstructArguments( + 'Magento\Eav\Model\Entity\VersionControl\AbstractEntity', + [ + 'eavConfig' => $eavConfig, + 'entitySnapshot' => $this->entitySnapshot, + 'entityRelationComposite' => $this->entityRelationComposite, + 'data' => [ + 'type' => $entityType, + 'entityTable' => 'entityTable', + 'attributesByCode' => $attributes + ] + ] + ); + + /** @var $model AbstractEntity|\PHPUnit_Framework_MockObject_MockObject */ + $model = $this->getMockBuilder('Magento\Eav\Model\Entity\VersionControl\AbstractEntity') + ->setConstructorArgs($arguments) + ->setMethods(['_getValue', 'beginTransaction', 'commit', 'rollback']) + ->getMock(); + + $model->expects($this->any())->method('_getValue')->will($this->returnValue($eavConfig)); + + $eavConfig->expects($this->any())->method('getAttribute')->will( + $this->returnCallback( + function ($entityType, $attributeCode) use ($attributes) { + return $entityType && isset($attributes[$attributeCode]) ? $attributes[$attributeCode] : null; + } + ) + ); + + $model->setConnection($this->_getAdapterMock()); + $model->isPartialSave(true); + $model->save($object); + } + + public function testSaveNotModified() + { + $objectManager = new ObjectManager($this); + + /** @var $object \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject */ + $object = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false); + + $arguments = $objectManager->getConstructArguments( + 'Magento\Eav\Model\Entity\VersionControl\AbstractEntity', + [ + 'entitySnapshot' => $this->entitySnapshot, + 'entityRelationComposite' => $this->entityRelationComposite, + ] + ); + + /** @var $model AbstractEntity|\PHPUnit_Framework_MockObject_MockObject */ + $model = $this->getMockBuilder('Magento\Eav\Model\Entity\VersionControl\AbstractEntity') + ->setConstructorArgs($arguments) + ->setMethods(['beginTransaction', 'commit']) + ->getMock(); + + $this->entitySnapshot->expects($this->once())->method('isModified')->willReturn(false); + $this->entitySnapshot->expects($this->never())->method('registerSnapshot'); + + $this->entityRelationComposite->expects($this->once())->method('processRelations')->with($object); + + $model->save($object); + } +} diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/MetadataTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/MetadataTest.php new file mode 100644 index 0000000000000000000000000000000000000000..77e00daf49c9b623a851c86b7fbf5679d8e39faf --- /dev/null +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/MetadataTest.php @@ -0,0 +1,104 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Eav\Test\Unit\Model\Entity\VersionControl; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +/** + * Test for version control metadata model. + */ +class MetadataTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Eav\Model\Entity\VersionControl\Metadata + */ + protected $metadata; + + /** + * @var \Magento\Framework\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject + */ + protected $model; + + /** + * @var \Magento\Framework\Model\Resource\Db\AbstractDb|\PHPUnit_Framework_MockObject_MockObject + */ + protected $resource; + + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $connection; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + + $this->model = $this->getMock( + 'Magento\Framework\Model\AbstractModel', + ['getResource', 'getAttributes'], + [], + '', + false + ); + + $this->resource = $this->getMockForAbstractClass( + 'Magento\Framework\DB\Adapter\AdapterInterface', + [], + '', + false, + false, + true, + ['getReadConnection', 'getEntityTable'] + ); + + $this->connection = $this->getMockForAbstractClass( + 'Magento\Framework\DB\Adapter\AdapterInterface', + [], + '', + false, + false + ); + + $this->model->expects($this->any())->method('getResource')->willReturn($this->resource); + + $this->resource->expects($this->any())->method('getReadConnection')->willReturn($this->connection); + + $this->metadata = $objectManager->getObject( + 'Magento\Eav\Model\Entity\VersionControl\Metadata' + ); + } + + public function testGetFields() + { + $entityTable = 'entity_table'; + + $expectedDescribedTable = ['field1' => null, 'field2' => null]; + $expectedAttributes = ['attribute1' => 'value1', 'attribute2' => 'value2']; + + $expectedResults = array_merge($expectedDescribedTable, $expectedAttributes); + + $this->resource->expects($this->any())->method('getEntityTable')->willReturn($entityTable); + + $this->connection->expects($this->once())->method('describeTable')->with($entityTable)->willReturn( + $expectedDescribedTable + ); + + $this->model->expects($this->any())->method('getAttributes')->willReturn($expectedAttributes); + //check that fields load with null initial value + $this->assertEquals( + array_fill_keys(array_keys($expectedResults), null), + $this->metadata->getFields($this->model) + ); + + // Testing loading data from cache. + $this->connection->expects($this->never())->method('describeTable'); + + $this->assertEquals( + array_fill_keys(array_keys($expectedResults), null), + $this->metadata->getFields($this->model) + ); + } +} diff --git a/app/code/Magento/Fedex/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Fedex/view/frontend/layout/checkout_onepage_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..541e46a36a627814c6989c5c8d237e7d1e83aaf5 --- /dev/null +++ b/app/code/Magento/Fedex/view/frontend/layout/checkout_onepage_index.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="step-config" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-rates-validation" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="fedex-rates-validation" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Fedex/js/view/shipping-rates-validation</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validation-rules.js b/app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validation-rules.js new file mode 100644 index 0000000000000000000000000000000000000000..9f22914a8d29b73f75c2dfc51dfc776ed284e557 --- /dev/null +++ b/app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validation-rules.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function () { + "use strict"; + return { + getRules: function() { + return { + 'postcode': { + 'required': true + }, + 'country_id': { + 'required': true + } + }; + } + }; + } +); diff --git a/app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validator.js b/app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..71dac1b92c10ff0cab212709c93478227c2262c1 --- /dev/null +++ b/app/code/Magento/Fedex/view/frontend/web/js/model/shipping-rates-validator.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'mageUtils', + './shipping-rates-validation-rules', + 'mage/translate' + ], + function ($, utils, validationRules, $t) { + "use strict"; + return { + validationErrors: [], + validate: function(address) { + var self = this; + this.validationErrors = []; + $.each(validationRules.getRules(), function(field, rule) { + if (rule.required && utils.isEmpty(address[field])) { + var message = $t('Field ') + field + $t(' is required.'); + self.validationErrors.push(message); + } + }); + return !Boolean(this.validationErrors.length); + } + }; + } +); diff --git a/app/code/Magento/Fedex/view/frontend/web/js/view/shipping-rates-validation.js b/app/code/Magento/Fedex/view/frontend/web/js/view/shipping-rates-validation.js new file mode 100644 index 0000000000000000000000000000000000000000..dc9bc66b93e5ee503719ef80794bf1fb91a9acfe --- /dev/null +++ b/app/code/Magento/Fedex/view/frontend/web/js/view/shipping-rates-validation.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-rates-validation-rules', + '../model/shipping-rates-validator', + '../model/shipping-rates-validation-rules' + ], + function ( + Component, + defaultShippingRatesValidator, + defaultShippingRatesValidationRules, + fedexShippingRatesValidator, + fedexShippingRatesValidationRules + ) { + "use strict"; + defaultShippingRatesValidator.registerValidator('fedex', fedexShippingRatesValidator); + defaultShippingRatesValidationRules.registerRules('fedex', fedexShippingRatesValidationRules); + return Component; + } +); diff --git a/app/code/Magento/GiftMessage/view/frontend/web/js/action/gift-options.js b/app/code/Magento/GiftMessage/view/frontend/web/js/action/gift-options.js index 4896aeb00b5b87c57ad90cdcc86c26e68da0b794..51e72540458efd1cd3a3f8fe564f148e9357a0b7 100644 --- a/app/code/Magento/GiftMessage/view/frontend/web/js/action/gift-options.js +++ b/app/code/Magento/GiftMessage/view/frontend/web/js/action/gift-options.js @@ -7,10 +7,10 @@ define( [ '../model/url-builder', 'mage/storage', - 'Magento_Ui/js/model/errorlist', + 'Magento_Ui/js/model/messageList', 'mage/url' ], - function(urlBuilder, storage, errorList, url) { + function(urlBuilder, storage, messageList, url) { "use strict"; return function(giftMessage, remove) { url.setBaseUrl(giftMessage.getConfigValue('baseUrl')); @@ -30,7 +30,7 @@ define( ); } } - errorList.clear(); + messageList.clear(); storage.post( serviceUrl, @@ -49,7 +49,7 @@ define( ).fail( function(response) { var error = JSON.parse(response.responseText); - errorList.add(error); + messageList.addErrorMessage(error); } ); }; diff --git a/app/code/Magento/OfflinePayments/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/OfflinePayments/view/frontend/layout/checkout_onepage_index.xml index c6140255ab7f1141c453b557d25a282a92abc897..8e1eb709250e00164ef7c62f3dc6468334b0ef73 100644 --- a/app/code/Magento/OfflinePayments/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/OfflinePayments/view/frontend/layout/checkout_onepage_index.xml @@ -15,30 +15,34 @@ <item name="children" xsi:type="array"> <item name="steps" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="payment" xsi:type="array"> + <item name="billing-step" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="sortOrder" xsi:type="string">2</item> <item name="children" xsi:type="array"> - <item name="checkmo" xsi:type="array"> - <item name="component" xsi:type="string">Magento_OfflinePayments/js/view/payment/checkmo-method</item> - <item name="config" xsi:type="array"> - <item name="formTemplate" xsi:type="string">Magento_OfflinePayments/payment/checkmo-form</item> - </item> - </item> - <item name="cashondelivery" xsi:type="array"> - <item name="component" xsi:type="string">Magento_OfflinePayments/js/view/payment/instructions-method</item> - <item name="config" xsi:type="array"> - <item name="formTemplate" xsi:type="string">Magento_OfflinePayments/payment/instructions-form</item> - </item> - </item> - <item name="banktransfer" xsi:type="array"> - <item name="component" xsi:type="string">Magento_OfflinePayments/js/view/payment/instructions-method</item> - <item name="config" xsi:type="array"> - <item name="formTemplate" xsi:type="string">Magento_OfflinePayments/payment/instructions-form</item> - </item> - </item> - <item name="purchaseorder" xsi:type="array"> - <item name="component" xsi:type="string">Magento_OfflinePayments/js/view/payment/purchaseorder-method</item> - <item name="config" xsi:type="array"> - <item name="formTemplate" xsi:type="string">Magento_OfflinePayments/payment/purchaseorder-form</item> + <item name="payment" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="renders" xsi:type="array"> + <!-- merge payment method renders here --> + <item name="children" xsi:type="array"> + <item name="offline-payments" xsi:type="array"> + <item name="component" xsi:type="string">Magento_OfflinePayments/js/view/payment/offline-payments</item> + <item name="methods" xsi:type="array"> + <item name="checkmo" xsi:type="array"> + <item name="isBillingAddressRequired" xsi:type="boolean">true</item> + </item> + <item name="banktransfer" xsi:type="array"> + <item name="isBillingAddressRequired" xsi:type="boolean">true</item> + </item> + <item name="cashondelivery" xsi:type="array"> + <item name="isBillingAddressRequired" xsi:type="boolean">true</item> + </item> + <item name="purchaseorder" xsi:type="array"> + <item name="isBillingAddressRequired" xsi:type="boolean">true</item> + </item> + </item> + </item> + </item> + </item> </item> </item> </item> @@ -52,4 +56,4 @@ </arguments> </referenceBlock> </body> -</page> +</page> \ No newline at end of file diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/checkmo-method.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/checkmo-method.js deleted file mode 100644 index 5093e525aaea7e12e2e138f33884d33217120b54..0000000000000000000000000000000000000000 --- a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/checkmo-method.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'Magento_Checkout/js/view/payment/method-info', - 'mage/translate' - ], - function (methodInfo, $t) { - return methodInfo.extend({ - getMailingAddress: function() { - return window.checkoutConfig.payment.checkmo.mailingAddress; - }, - getPayableTo: function() { - return window.checkoutConfig.payment.checkmo.payableTo; - }, - getInfo: function() { - var info = []; - if (this.getPayableTo()) { - info.push({name: $t('Make Check payable to')}); - info.push({value: this.getPayableTo()}); - } - if (this.getMailingAddress()) { - info.push({name: $t('Send Check to')}); - info.push({html: this.getMailingAddress()}); - } - return info; - } - }); - } -); diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/instructions-method.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/instructions-method.js deleted file mode 100644 index a3d9e9cdbae67265888a71dfe8aaae79fdbf778c..0000000000000000000000000000000000000000 --- a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/instructions-method.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'Magento_Checkout/js/view/payment/method-info' - ], - function (methodInfo) { - return methodInfo.extend({ - getInstructions: function() { - return window.checkoutConfig.payment.instructions[this.getCode()]; - }, - getInfo: function() { - var info = []; - if (this.getInstructions()) { - info.push({html: this.getInstructions()}); - } - return info; - } - }); - } -); diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/banktransfer-method.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/banktransfer-method.js new file mode 100644 index 0000000000000000000000000000000000000000..e139bbf2fa4b1d5148317167bc8d4a1ae2392bc9 --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/banktransfer-method.js @@ -0,0 +1,26 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'ko', + 'Magento_Checkout/js/view/payment/default' + ], + function (ko, Component) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_OfflinePayments/payment/banktransfer' + }, + /** + * Get value of instruction field. + * @returns {String} + */ + getInstructions: function () { + return window.checkoutConfig.payment.instructions[this.item.method]; + } + }); + } +); diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/cashondelivery-method.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/cashondelivery-method.js new file mode 100644 index 0000000000000000000000000000000000000000..9dea96883c3235d087e106bc20b728f9fc8315da --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/cashondelivery-method.js @@ -0,0 +1,24 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'Magento_Checkout/js/view/payment/default' + ], + function (Component) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Magento_OfflinePayments/payment/cashondelivery' + }, + + /** Returns payment method instructions */ + getInstructions: function() { + return window.checkoutConfig.payment.instructions[this.item.method]; + } + }); + } +); diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/checkmo-method.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/checkmo-method.js new file mode 100644 index 0000000000000000000000000000000000000000..6eb00662593f1e0a2213af36b50fc6ca29f271c7 --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/checkmo-method.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'Magento_Checkout/js/view/payment/default' + ], + function (Component) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_OfflinePayments/payment/checkmo' + }, + + /** Returns send check to info */ + getMailingAddress: function() { + return window.checkoutConfig.payment.checkmo.mailingAddress; + }, + + /** Returns payable to info */ + getPayableTo: function() { + return window.checkoutConfig.payment.checkmo.payableTo; + } + }); + } +); diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/purchaseorder-method.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/purchaseorder-method.js new file mode 100644 index 0000000000000000000000000000000000000000..a5d09084f5cb8c5fefdb256cfdf94079f2b9e9e6 --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/method-renderer/purchaseorder-method.js @@ -0,0 +1,44 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'Magento_Checkout/js/view/payment/default', + 'jquery', + "mage/validation" + ], + function (Component, $) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Magento_OfflinePayments/payment/purchaseorder-form', + purchaseOrderNumber: '' + }, + initObservable: function () { + this._super() + .observe('purchaseOrderNumber'); + return this; + }, + getData: function () { + return { + "method": this.item.method, + 'po_number': this.purchaseOrderNumber(), + "cc_owner": null, + "cc_number": null, + "cc_type": null, + "cc_exp_year": null, + "cc_exp_month": null, + "additional_data": null + }; + + }, + validate: function () { + var form = '#purchaseorder'; + return $(form).validation() && $(form).validation('isValid'); + } + }); + } +); diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/offline-payments.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/offline-payments.js new file mode 100644 index 0000000000000000000000000000000000000000..809df962245fb2c225f117b2866c6b3d4c70a5bd --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/offline-payments.js @@ -0,0 +1,38 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/payment/renderer-list' + ], + function ( + Component, + rendererList + ) { + 'use strict'; + rendererList.push( + { + type: 'checkmo', + component: 'Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method' + }, + { + type: 'banktransfer', + component: 'Magento_OfflinePayments/js/view/payment/method-renderer/banktransfer-method' + }, + { + type: 'cashondelivery', + component: 'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method' + }, + { + type: 'purchaseorder', + component: 'Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method' + } + ); + /** Add view logic here if needed */ + return Component.extend({}); + } +); \ No newline at end of file diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/purchaseorder-method.js b/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/purchaseorder-method.js deleted file mode 100644 index 1233199cc2d862f2048fb7bcf1f0f05e72502a2a..0000000000000000000000000000000000000000 --- a/app/code/Magento/OfflinePayments/view/frontend/web/js/view/payment/purchaseorder-method.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'jquery', - "mage/translate", - 'Magento_Checkout/js/view/payment/method-info' - ], - function ($, $t, methodInfo) { - return methodInfo.extend({ - defaults: { - purchaseOrderNumber: '' - }, - initObservable: function () { - this._super() - .observe('purchaseOrderNumber'); - return this; - }, - getData: function() { - return {'po_number': this.purchaseOrderNumber()}; - }, - getInfo: function() { - return [ - {'name': 'Purchase Order Number', value: this.purchaseOrderNumber()} - ]; - } - }); - } -); diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/banktransfer.html b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/banktransfer.html new file mode 100644 index 0000000000000000000000000000000000000000..dfcbf3131970749bfec9ab0537c3ef12f689fae7 --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/banktransfer.html @@ -0,0 +1,40 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}"> + <div class="payment-method-title field choice"> + <input type="radio" + name="payment[method]" + class="radio" + data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()" /> + <label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label> + </div> + + <div class="payment-method-content"> + <div class="payment-method-billing-address"> + <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <p data-bind="text: getInstructions()"></p> + <div class="checkout-agreements-block"> + <!-- ko foreach: $parent.getRegion('before-place-order') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <div class="actions-toolbar"> + <div class="primary"> + <button class="action primary checkout" + type="submit" + data-bind="click: placeOrder, attr: {'title': $t('Place Order')}, enable: (getCode() == isChecked())" + disabled> + <span data-bind="text: $t('Place Order')"></span> + </button> + </div> + </div> + </div> +</div> + \ No newline at end of file diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/cashondelivery.html b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/cashondelivery.html new file mode 100644 index 0000000000000000000000000000000000000000..569d5b0a48eb368622fee51306a8d9c30b075cf7 --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/cashondelivery.html @@ -0,0 +1,41 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}"> + <div class="payment-method-title field choice"> + <input type="radio" + name="payment[method]" + class="radio" + data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/> + <label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label> + </div> + + <div class="payment-method-content"> + <div class="payment-method-billing-address"> + <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <p data-bind="text: getInstructions()"></p> + <div class="checkout-agreements-block"> + <!-- ko foreach: $parent.getRegion('before-place-order') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <div class="actions-toolbar"> + <div class="primary"> + <button class="action primary checkout" + type="submit" + data-bind="click: placeOrder, attr: {title: $t('Place Order')}, enable: (getCode() == isChecked())" + disabled> + <span data-bind="text: $t('Place Order')"></span> + </button> + </div> + </div> + + </div> +</div> + \ No newline at end of file diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/checkmo-form.html b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/checkmo-form.html deleted file mode 100644 index 92c84f0662ddda6acf0fdff41ed3233ff69fe447..0000000000000000000000000000000000000000 --- a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/checkmo-form.html +++ /dev/null @@ -1,20 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko if: getMailingAddress() || getPayableTo() --> -<dl class="items check payable" id="payment_form_<?php echo $block->getMethodCode() ?>"> - <!-- ko if: getPayableTo() --> - <dt class="title"><!-- ko text: $t('Make Check payable to:') --><!-- /ko --></dt> - <dd class="content"><!-- ko text: $t(getPayableTo()) --><!-- /ko --></dd> - <!-- /ko --> - <!-- ko if: getMailingAddress() --> - <dt class="title"><!-- ko text: $t('Send Check to:') --><!-- /ko --></dt> - <dd class="content"> - <address class="checkmo mailing address" data-bind="html: $t(getMailingAddress())"></address> - </dd> - <!-- /ko --> -</dl> -<!-- /ko --> diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/checkmo.html b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/checkmo.html new file mode 100644 index 0000000000000000000000000000000000000000..58f85845434792ab778b177461ac493a743d649d --- /dev/null +++ b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/checkmo.html @@ -0,0 +1,52 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}"> + <div class="payment-method-title field choice"> + <input type="radio" + name="payment[method]" + class="radio" + data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/> + <label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label> + </div> + <div class="payment-method-content"> + <div class="payment-method-billing-address"> + <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <!-- ko if: getMailingAddress() || getPayableTo() --> + <dl class="items check payable"> + <!-- ko if: getPayableTo() --> + <dt class="title"><!-- ko text: $t('Make Check payable to:') --><!-- /ko --></dt> + <dd class="content"><!-- ko text: $t(getPayableTo()) --><!-- /ko --></dd> + <!-- /ko --> + <!-- ko if: getMailingAddress() --> + <dt class="title"><!-- ko text: $t('Send Check to:') --><!-- /ko --></dt> + <dd class="content"> + <address class="checkmo mailing address" data-bind="html: $t(getMailingAddress())"></address> + </dd> + <!-- /ko --> + </dl> + <!-- /ko --> + <div class="checkout-agreements-block"> + <!-- ko foreach: $parent.getRegion('before-place-order') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <div class="actions-toolbar"> + <div class="primary"> + <button class="action primary checkout" + type="submit" + data-bind="click: placeOrder, attr: {title: $t('Place Order')}, enable: (getCode() == isChecked())" + disabled> + <span data-bind="text: $t('Place Order')"></span> + </button> + </div> + </div> + </div> +</div> + \ No newline at end of file diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/instructions-form.html b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/instructions-form.html deleted file mode 100644 index 56f30d9cc42c14d7997f02c5c51b0dd22624fb21..0000000000000000000000000000000000000000 --- a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/instructions-form.html +++ /dev/null @@ -1,9 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko if: getInstructions() --> -<div data-bind="attr: {class: 'items ' + getCode() + ' instructions agreement content', id: 'payment_form_' + getCode()}, html: $t(getInstructions())"></div> -<!-- /ko --> \ No newline at end of file diff --git a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/purchaseorder-form.html b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/purchaseorder-form.html index 828045b5b7321a6893dc0493cb48d2e5ea14341e..585d61feae7d7c7423285c3db12f5351adc2d385 100644 --- a/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/purchaseorder-form.html +++ b/app/code/Magento/OfflinePayments/view/frontend/web/template/payment/purchaseorder-form.html @@ -4,19 +4,59 @@ * See COPYING.txt for license details. */ --> -<fieldset class="fieldset payment method" data-bind='attr: {id: "payment_form_" + getCode()}'> - <div class="field field-number required"> - <label for="po_number" class="label"><span><!-- ko text: $t('Purchase Order Number')--><!-- /ko --></span></label> - <div class="control"> - <input type="text" - id="po_number" - name="payment[po_number]" - data-validate="{required:true}" - data-bind=' - attr: {title: $t("Purchase Order Number")}, - value: purchaseOrderNumber, - enable: isActive($parent)' - class="input-text"/> +<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}"> + <form id="purchaseorder-form" class="form form-purchase-order"> + + <div class="payment-method-title field choice"> + <input type="radio" + name="payment[method]" + class="radio" + data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/> + <label data-bind="attr: {'for': getCode()}" class="label"> + <span data-bind="text: getTitle()"></span> + </label> </div> - </div> -</fieldset> \ No newline at end of file + + <div class="payment-method-content"> + <div class="payment-method-billing-address"> + <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + + <fieldset class="fieldset payment method" data-bind='attr: {id: "payment_form_" + getCode()}'> + <div class="field field-number required"> + <label for="po_number" class="label"> + <span><!-- ko text: $t('Purchase Order Number')--><!-- /ko --></span> + </label> + <div class="control"> + <input type="text" + id="po_number" + name="payment[po_number]" + data-validate="{required:true}" + data-bind=' + attr: {title: $t("Purchase Order Number")}, + value: purchaseOrderNumber' + class="input-text"/> + </div> + </div> + <div class="checkout-agreements-block"> + <!-- ko foreach: $parent.getRegion('before-place-order') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <div class="actions-toolbar" id="review-buttons-container"> + <div class="primary"> + <button class="action primary checkout" + type="submit" + data-bind="click: placeOrder, attr: {title: $t('Place Order')}, enable: (getCode() == isChecked())" + data-role="review-save"> + <span data-bind="text: $t('Place Order')"></span> + </button> + </div> + </div> + </fieldset> + </div> + </form> +</div> + \ No newline at end of file diff --git a/app/code/Magento/OfflineShipping/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/OfflineShipping/view/frontend/layout/checkout_onepage_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..f97709a21bd0aa5313a6bdc0f44ef0167205a1e1 --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/layout/checkout_onepage_index.xml @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="step-config" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-rates-validation" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="freeshipping-rates-validation" xsi:type="array"> + <item name="component" xsi:type="string">Magento_OfflineShipping/js/view/shipping-rates-validation/freeshipping</item> + </item> + <item name="flatrate-rates-validation" xsi:type="array"> + <item name="component" xsi:type="string">Magento_OfflineShipping/js/view/shipping-rates-validation/flatrate</item> + </item> + <item name="tablerate-rates-validation" xsi:type="array"> + <item name="component" xsi:type="string">Magento_OfflineShipping/js/view/shipping-rates-validation/tablerate</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/flatrate.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/flatrate.js new file mode 100644 index 0000000000000000000000000000000000000000..f45450e5359e06c86e85badb235aa193797c3a48 --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/flatrate.js @@ -0,0 +1,20 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function () { + "use strict"; + return { + getRules: function() { + return { + 'country_id': { + 'required': true + } + }; + } + }; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/freeshipping.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/freeshipping.js new file mode 100644 index 0000000000000000000000000000000000000000..f45450e5359e06c86e85badb235aa193797c3a48 --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/freeshipping.js @@ -0,0 +1,20 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function () { + "use strict"; + return { + getRules: function() { + return { + 'country_id': { + 'required': true + } + }; + } + }; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/tablerate.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/tablerate.js new file mode 100644 index 0000000000000000000000000000000000000000..174ca5d9b9506d9c7ea4d39d45b4bf1502ba6104 --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validation-rules/tablerate.js @@ -0,0 +1,26 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function () { + "use strict"; + return { + getRules: function() { + return { + 'postcode': { + 'required': true + }, + 'country_id': { + 'required': true + }, + 'region_id': { + 'required': true + } + }; + } + }; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/flatrate.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/flatrate.js new file mode 100644 index 0000000000000000000000000000000000000000..39faae263931600a6eec596c1e127ce6098b595d --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/flatrate.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'mageUtils', + '../shipping-rates-validation-rules/flatrate', + 'mage/translate' + ], + function ($, utils, validationRules, $t) { + "use strict"; + return { + validationErrors: [], + validate: function(address) { + var self = this; + this.validationErrors = []; + $.each(validationRules.getRules(), function(field, rule) { + if (rule.required && utils.isEmpty(address[field])) { + var message = $t('Field ') + field + $t(' is required.'); + self.validationErrors.push(message); + } + }); + return !Boolean(this.validationErrors.length); + } + }; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/freeshipping.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/freeshipping.js new file mode 100644 index 0000000000000000000000000000000000000000..d3e970cc8f7676a446ab94bc1c727cc7ad7a11cf --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/freeshipping.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'mageUtils', + '../shipping-rates-validation-rules/freeshipping', + 'mage/translate' + ], + function ($, utils, validationRules, $t) { + "use strict"; + return { + validationErrors: [], + validate: function(address) { + var self = this; + this.validationErrors = []; + $.each(validationRules.getRules(), function(field, rule) { + if (rule.required && utils.isEmpty(address[field])) { + var message = $t('Field ') + field + $t(' is required.'); + self.validationErrors.push(message); + } + }); + return !Boolean(this.validationErrors.length); + } + }; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/tablerate.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/tablerate.js new file mode 100644 index 0000000000000000000000000000000000000000..3a04b4cf03756da06de7a377ef65df08fe8599de --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/model/shipping-rates-validator/tablerate.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'mageUtils', + '../shipping-rates-validation-rules/tablerate', + 'mage/translate' + ], + function ($, utils, validationRules, $t) { + "use strict"; + return { + validationErrors: [], + validate: function(address) { + var self = this; + this.validationErrors = []; + $.each(validationRules.getRules(), function(field, rule) { + if (rule.required && utils.isEmpty(address[field])) { + var message = $t('Field ') + field + $t(' is required.'); + self.validationErrors.push(message); + } + }); + return !Boolean(this.validationErrors.length); + } + }; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/flatrate.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/flatrate.js new file mode 100644 index 0000000000000000000000000000000000000000..c7cd3490469ad1b1c18a30fb1873ee7b2d9b9e2b --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/flatrate.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-rates-validation-rules', + '../../model/shipping-rates-validator/flatrate', + '../../model/shipping-rates-validation-rules/flatrate' + ], + function ( + Component, + defaultShippingRatesValidator, + defaultShippingRatesValidationRules, + flatrateShippingRatesValidator, + flatrateShippingRatesValidationRules + ) { + "use strict"; + defaultShippingRatesValidator.registerValidator('flatrate', flatrateShippingRatesValidator); + defaultShippingRatesValidationRules.registerRules('flatrate', flatrateShippingRatesValidationRules); + return Component; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/freeshipping.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/freeshipping.js new file mode 100644 index 0000000000000000000000000000000000000000..a58024dcff35edb777ec6f6da89a3707364ae75f --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/freeshipping.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-rates-validation-rules', + '../../model/shipping-rates-validator/freeshipping', + '../../model/shipping-rates-validation-rules/freeshipping' + ], + function ( + Component, + defaultShippingRatesValidator, + defaultShippingRatesValidationRules, + freeshippingShippingRatesValidator, + freeshippingShippingRatesValidationRules + ) { + "use strict"; + defaultShippingRatesValidator.registerValidator('freeshipping', freeshippingShippingRatesValidator); + defaultShippingRatesValidationRules.registerRules('freeshipping', freeshippingShippingRatesValidationRules); + return Component; + } +); diff --git a/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/tablerate.js b/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/tablerate.js new file mode 100644 index 0000000000000000000000000000000000000000..9f9754eedd202d1a8fb6c766d44de4e91f66bdd3 --- /dev/null +++ b/app/code/Magento/OfflineShipping/view/frontend/web/js/view/shipping-rates-validation/tablerate.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-rates-validation-rules', + '../../model/shipping-rates-validator/tablerate', + '../../model/shipping-rates-validation-rules/tablerate' + ], + function ( + Component, + defaultShippingRatesValidator, + defaultShippingRatesValidationRules, + tablerateShippingRatesValidator, + tablerateShippingRatesValidationRules + ) { + "use strict"; + defaultShippingRatesValidator.registerValidator('tablerate', tablerateShippingRatesValidator); + defaultShippingRatesValidationRules.registerRules('tablerate', tablerateShippingRatesValidationRules); + return Component; + } +); diff --git a/app/code/Magento/PageCache/Model/Observer/ProcessLayoutRenderElement.php b/app/code/Magento/PageCache/Model/Observer/ProcessLayoutRenderElement.php index c95ad9995ef88ff4943fb0dbd5e0c3673776857b..ea4d21869bda7c09e933ded3f741ff297808f0d2 100644 --- a/app/code/Magento/PageCache/Model/Observer/ProcessLayoutRenderElement.php +++ b/app/code/Magento/PageCache/Model/Observer/ProcessLayoutRenderElement.php @@ -16,6 +16,22 @@ class ProcessLayoutRenderElement protected $_config; /** + * Is varnish enabled flag + * + * @var bool + */ + protected $isVarnishEnabled; + + /** + * Is full page cache enabled flag + * + * @var bool + */ + protected $isFullPageCacheEnabled; + + /** + * Class constructor + * * @param \Magento\PageCache\Model\Config $config */ public function __construct(\Magento\PageCache\Model\Config $config) @@ -44,6 +60,32 @@ class ProcessLayoutRenderElement return sprintf('<esi:include src="%s" />', $url); } + /** + * Is full page cache enabled + * + * @return bool + */ + protected function isFullPageCacheEnabled() + { + if ($this->isFullPageCacheEnabled === null) { + $this->isFullPageCacheEnabled = $this->_config->isEnabled(); + } + return $this->isFullPageCacheEnabled; + } + + /** + * Is varnish cache engine enabled + * + * @return bool + */ + protected function isVarnishEnabled() + { + if ($this->isVarnishEnabled === null) { + $this->isVarnishEnabled = ($this->_config->getType() == \Magento\PageCache\Model\Config::VARNISH); + } + return $this->isVarnishEnabled; + } + /** * Add comment cache containers to private blocks * Blocks are wrapped only if page is cacheable @@ -56,15 +98,15 @@ class ProcessLayoutRenderElement $event = $observer->getEvent(); /** @var \Magento\Framework\View\Layout $layout */ $layout = $event->getLayout(); - if ($layout->isCacheable() && $this->_config->isEnabled()) { + if ($this->isFullPageCacheEnabled() && $layout->isCacheable()) { $name = $event->getElementName(); + /** @var \Magento\Framework\View\Element\AbstractBlock $block */ $block = $layout->getBlock($name); $transport = $event->getTransport(); if ($block instanceof \Magento\Framework\View\Element\AbstractBlock) { $blockTtl = $block->getTtl(); - $varnishIsEnabledFlag = ($this->_config->getType() == \Magento\PageCache\Model\Config::VARNISH); $output = $transport->getData('output'); - if ($varnishIsEnabledFlag && isset($blockTtl)) { + if (isset($blockTtl) && $this->isVarnishEnabled()) { $output = $this->_wrapEsi($block, $layout); } elseif ($block->isScopePrivate()) { $output = sprintf( diff --git a/app/code/Magento/PageCache/Test/Unit/Model/Observer/ProcessLayoutRenderElementTest.php b/app/code/Magento/PageCache/Test/Unit/Model/Observer/ProcessLayoutRenderElementTest.php index 370edc3a369e53f2f49de43de5e26a367fb3bd7c..1601b85f477494d942138fae8a8cbbcf8cc35c54 100644 --- a/app/code/Magento/PageCache/Test/Unit/Model/Observer/ProcessLayoutRenderElementTest.php +++ b/app/code/Magento/PageCache/Test/Unit/Model/Observer/ProcessLayoutRenderElementTest.php @@ -99,19 +99,29 @@ class ProcessLayoutRenderElementTest extends \PHPUnit_Framework_TestCase $this->_configMock->expects($this->any())->method('isEnabled')->will($this->returnValue($cacheState)); if ($cacheState) { - $eventMock->expects($this->once())->method('getElementName')->will($this->returnValue('blockName')); - $eventMock->expects($this->once())->method('getTransport')->will($this->returnValue($this->_transport)); - $this->_layoutMock->expects($this->once())->method('isCacheable')->will($this->returnValue(true)); - - $this->_layoutMock->expects($this->any())->method('getUpdate')->will($this->returnSelf()); - $this->_layoutMock->expects($this->any())->method('getHandles')->will($this->returnValue([])); - $this->_layoutMock->expects( - $this->once() - )->method( - 'getBlock' - )->will( - $this->returnValue($this->_blockMock) - ); + $eventMock->expects($this->once()) + ->method('getElementName') + ->will($this->returnValue('blockName')); + + $eventMock->expects($this->once()) + ->method('getTransport') + ->will($this->returnValue($this->_transport)); + + $this->_layoutMock->expects($this->once()) + ->method('isCacheable') + ->will($this->returnValue(true)); + + $this->_layoutMock->expects($this->any()) + ->method('getUpdate') + ->will($this->returnSelf()); + + $this->_layoutMock->expects($this->any()) + ->method('getHandles') + ->will($this->returnValue([])); + + $this->_layoutMock->expects($this->once()) + ->method('getBlock') + ->will($this->returnValue($this->_blockMock)); if ($varnishIsEnabled) { $this->_blockMock->expects($this->once()) @@ -123,20 +133,12 @@ class ProcessLayoutRenderElementTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue('page_cache/block/wrapesi/with/handles/and/other/stuff')); } if ($scopeIsPrivate) { - $this->_blockMock->expects( - $this->once() - )->method( - 'getNameInLayout' - )->will( - $this->returnValue('testBlockName') - ); - $this->_blockMock->expects( - $this->once() - )->method( - 'isScopePrivate' - )->will( - $this->returnValue($scopeIsPrivate) - ); + $this->_blockMock->expects($this->once()) + ->method('getNameInLayout') + ->will($this->returnValue('testBlockName')); + $this->_blockMock->expects($this->once()) + ->method('isScopePrivate') + ->will($this->returnValue($scopeIsPrivate)); } $this->_configMock->expects($this->any())->method('getType')->will($this->returnValue($varnishIsEnabled)); } diff --git a/app/code/Magento/Payment/Gateway/Command/CommandException.php b/app/code/Magento/Payment/Gateway/Command/CommandException.php new file mode 100644 index 0000000000000000000000000000000000000000..7c4409fb42e62ff9a8afc3a5356891e3ffd3172b --- /dev/null +++ b/app/code/Magento/Payment/Gateway/Command/CommandException.php @@ -0,0 +1,13 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Gateway\Command; + +use Magento\Framework\Exception\LocalizedException; + +class CommandException extends LocalizedException +{ + +} diff --git a/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php b/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php index a6044462cded037192b2ca675ba06ce32e89549c..b04491622d4ba58b1a54b257388e38f82ba1515b 100644 --- a/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php +++ b/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php @@ -52,8 +52,8 @@ class GatewayCommand implements CommandInterface BuilderInterface $requestBuilder, TransferFactoryInterface $transferFactory, ClientInterface $client, - HandlerInterface $handler, - ValidatorInterface $validator + HandlerInterface $handler = null, + ValidatorInterface $validator = null ) { $this->requestBuilder = $requestBuilder; $this->transferFactory = $transferFactory; @@ -67,6 +67,7 @@ class GatewayCommand implements CommandInterface * * @param array $commandSubject * @return null + * @throws \Exception */ public function execute(array $commandSubject) { @@ -76,16 +77,22 @@ class GatewayCommand implements CommandInterface ); $response = $this->client->placeRequest($transferO); - - $result = $this->validator->validate(array_merge($commandSubject, ['response' => $response])); - if ($result !== null && !$result->isValid()) { - $commandSubject['payment']->getPayment()->setIsTransactionPending(true); - return; + if ($this->validator) { + $result = $this->validator->validate( + array_merge($commandSubject, ['response' => $response]) + ); + if (!$result->isValid()) { + throw new CommandException( + __(implode("\n", $result->getFailsDescription())) + ); + } } - $this->handler->handle( - $commandSubject, - $response - ); + if ($this->handler) { + $this->handler->handle( + $commandSubject, + $response + ); + } } } diff --git a/app/code/Magento/Payment/Gateway/Config/ConfigValueHandler.php b/app/code/Magento/Payment/Gateway/Config/ConfigValueHandler.php index 17566610aa29e171681ff4ade6829053e0a49c51..4811a6426816a538f702db7e0b1d9cfea0dd9a7c 100644 --- a/app/code/Magento/Payment/Gateway/Config/ConfigValueHandler.php +++ b/app/code/Magento/Payment/Gateway/Config/ConfigValueHandler.php @@ -6,6 +6,7 @@ namespace Magento\Payment\Gateway\Config; use Magento\Payment\Gateway\ConfigInterface; +use Magento\Payment\Gateway\Helper\SubjectReader; class ConfigValueHandler implements ValueHandlerInterface { @@ -26,13 +27,13 @@ class ConfigValueHandler implements ValueHandlerInterface /** * Retrieve method configured value * - * @param string $field + * @param array $subject * @param int|null $storeId * * @return mixed */ - public function handle($field, $storeId = null) + public function handle(array $subject, $storeId = null) { - return $this->configInterface->getValue($field, $storeId); + return $this->configInterface->getValue(SubjectReader::readField($subject), $storeId); } } diff --git a/app/code/Magento/Payment/Gateway/Config/ValueHandlerInterface.php b/app/code/Magento/Payment/Gateway/Config/ValueHandlerInterface.php index 5f857ea3cf539bceec121eb2af09120147774bb3..70e13466bfe30df92d45d4a8c8239819f497b0ea 100644 --- a/app/code/Magento/Payment/Gateway/Config/ValueHandlerInterface.php +++ b/app/code/Magento/Payment/Gateway/Config/ValueHandlerInterface.php @@ -10,10 +10,10 @@ interface ValueHandlerInterface /** * Retrieve method configured value * - * @param string $field + * @param array $subject * @param int|null $storeId * * @return mixed */ - public function handle($field, $storeId = null); + public function handle(array $subject, $storeId = null); } diff --git a/app/code/Magento/Payment/Gateway/Data/Order/OrderAdapter.php b/app/code/Magento/Payment/Gateway/Data/Order/OrderAdapter.php index f01bee1d7c77ab2b4c695ea4f00229f165e29132..f9be150d4761af45d4214edc702771444b0e5a08 100644 --- a/app/code/Magento/Payment/Gateway/Data/Order/OrderAdapter.php +++ b/app/code/Magento/Payment/Gateway/Data/Order/OrderAdapter.php @@ -106,4 +106,14 @@ class OrderAdapter implements OrderAdapterInterface { return $this->order->getEntityId(); } + + /** + * Returns order grand total amount + * + * @return float|null + */ + public function getGrandTotalAmount() + { + return $this->order->getBaseGrandTotal(); + } } diff --git a/app/code/Magento/Payment/Gateway/Data/OrderAdapterInterface.php b/app/code/Magento/Payment/Gateway/Data/OrderAdapterInterface.php index 0d925d823a9906c6d1bedbe4f488338f33493d64..c15bf289b2bfeeb0657912aec5beea99d7e36b33 100644 --- a/app/code/Magento/Payment/Gateway/Data/OrderAdapterInterface.php +++ b/app/code/Magento/Payment/Gateway/Data/OrderAdapterInterface.php @@ -55,4 +55,11 @@ interface OrderAdapterInterface * @return int */ public function getId(); + + /** + * Returns order grand total amount + * + * @return float + */ + public function getGrandTotalAmount(); } diff --git a/app/code/Magento/Payment/Gateway/Data/Quote/QuoteAdapter.php b/app/code/Magento/Payment/Gateway/Data/Quote/QuoteAdapter.php index 43a6a9ded86e61c539b5f64dfbbd89de57bc1c94..5e9ab098109729c78375d05cfbff6489e4cb1fb7 100644 --- a/app/code/Magento/Payment/Gateway/Data/Quote/QuoteAdapter.php +++ b/app/code/Magento/Payment/Gateway/Data/Quote/QuoteAdapter.php @@ -106,4 +106,14 @@ class QuoteAdapter implements OrderAdapterInterface { return $this->quote->getId(); } + + /** + * Returns order grand total amount + * + * @return null + */ + public function getGrandTotalAmount() + { + return null; + } } diff --git a/app/code/Magento/Payment/Gateway/Helper/SubjectReader.php b/app/code/Magento/Payment/Gateway/Helper/SubjectReader.php new file mode 100644 index 0000000000000000000000000000000000000000..bef0a4e463301a4ddda60ce704ea817a85f5488a --- /dev/null +++ b/app/code/Magento/Payment/Gateway/Helper/SubjectReader.php @@ -0,0 +1,58 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Gateway\Helper; + +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; + +class SubjectReader +{ + /** + * Reads payment from subject + * + * @param array $subject + * @return PaymentDataObjectInterface + */ + public static function readPayment(array $subject) + { + if (!isset($subject['payment']) + || !$subject['payment'] instanceof PaymentDataObjectInterface + ) { + throw new \InvalidArgumentException('Payment data object should be provided'); + } + + return $subject['payment']; + } + + /** + * Reads amount from subject + * + * @param array $subject + * @return mixed + */ + public static function readAmount(array $subject) + { + if (!isset($subject['amount']) || !is_numeric($subject['amount'])) { + throw new \InvalidArgumentException('Amount should be provided'); + } + + return $subject['amount']; + } + + /** + * Reads field from subject + * + * @param array $subject + * @return string + */ + public static function readField(array $subject) + { + if (!isset($subject['field']) || !is_string($subject['field'])) { + throw new \InvalidArgumentException(); + } + + return $subject['field']; + } +} diff --git a/app/code/Magento/Payment/Gateway/Http/Client/Soap.php b/app/code/Magento/Payment/Gateway/Http/Client/Soap.php new file mode 100644 index 0000000000000000000000000000000000000000..80479f0b768b2eb618f71458678a027bb8a663e3 --- /dev/null +++ b/app/code/Magento/Payment/Gateway/Http/Client/Soap.php @@ -0,0 +1,86 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Gateway\Http\Client; + +use Magento\Framework\Webapi\Soap\ClientFactory; +use Magento\Payment\Gateway\Http\ClientInterface; +use Magento\Payment\Gateway\Http\ConverterInterface; +use Magento\Payment\Gateway\Http\TransferInterface; +use Magento\Payment\Model\Method\Logger; + +class Soap implements ClientInterface +{ + /** + * @var Logger + */ + private $logger; + + /** + * @var ConverterInterface | null + */ + private $converter; + + /** + * @var ClientFactory + */ + private $clientFactory; + + /** + * @param Logger $logger + * @param ClientFactory $clientFactory + * @param ConverterInterface | null $converter + */ + public function __construct( + Logger $logger, + ClientFactory $clientFactory, + ConverterInterface $converter = null + ) { + $this->logger = $logger; + $this->converter = $converter; + $this->clientFactory = $clientFactory; + } + + /** + * Places request to gateway. Returns result as ENV array + * + * @param TransferInterface $transferObject + * @return array + * @throws \Magento\Payment\Gateway\Http\ClientException + * @throws \Magento\Payment\Gateway\Http\ConverterException + * @throws \Exception + */ + public function placeRequest(TransferInterface $transferObject) + { + $this->logger->debug(['request' => $transferObject->getBody()]); + + $client = $this->clientFactory->create( + $transferObject->getClientConfig()['wsdl'], + ['trace' => true] + ); + + try { + $client->__setSoapHeaders($transferObject->getHeaders()); + + $response = $client->__soapCall( + $transferObject->getMethod(), + [$transferObject->getBody()] + ); + + $result = $this->converter + ? $this->converter->convert( + $response + ) + : [$response]; + + $this->logger->debug(['response' => $result]); + } catch (\Exception $e) { + $this->logger->debug(['trace' => $client->__getLastRequest()]); + throw $e; + } + + return $result; + } +} diff --git a/app/code/Magento/Payment/Gateway/Http/Client/Zend.php b/app/code/Magento/Payment/Gateway/Http/Client/Zend.php index 0ea8ffbc871b8e49261c641a5bb71e3669e830d2..0415aab562b97e92f742315a48eca0ace2d56a9e 100644 --- a/app/code/Magento/Payment/Gateway/Http/Client/Zend.php +++ b/app/code/Magento/Payment/Gateway/Http/Client/Zend.php @@ -9,6 +9,7 @@ use Magento\Framework\HTTP\ZendClientFactory; use Magento\Framework\HTTP\ZendClient; use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\ConverterInterface; +use Magento\Payment\Gateway\Http\TransferInterface; use Magento\Payment\Model\Method\Logger; class Zend implements ClientInterface @@ -19,7 +20,7 @@ class Zend implements ClientInterface private $clientFactory; /** - * @var ConverterInterface + * @var ConverterInterface | null */ private $converter; @@ -30,13 +31,13 @@ class Zend implements ClientInterface /** * @param ZendClientFactory $clientFactory - * @param ConverterInterface $converter * @param Logger $logger + * @param ConverterInterface | null $converter */ public function __construct( ZendClientFactory $clientFactory, - ConverterInterface $converter, - Logger $logger + Logger $logger, + ConverterInterface $converter = null ) { $this->clientFactory = $clientFactory; $this->converter = $converter; @@ -46,10 +47,11 @@ class Zend implements ClientInterface /** * {inheritdoc} */ - public function placeRequest(\Magento\Payment\Gateway\Http\TransferInterface $transferObject) + public function placeRequest(TransferInterface $transferObject) { $log = [ - 'request' => $transferObject->getBody() + 'request' => $transferObject->getBody(), + 'request_uri' => $transferObject->getUri() ]; $result = []; /** @var ZendClient $client */ @@ -66,7 +68,12 @@ class Zend implements ClientInterface $client->setParameterPost($transferObject->getBody()); break; default: - throw new \LogicException(sprintf('Unsupported HTTP method %s', $transferObject->getMethod())); + throw new \LogicException( + sprintf( + 'Unsupported HTTP method %s', + $transferObject->getMethod() + ) + ); } $client->setHeaders($transferObject->getHeaders()); @@ -76,10 +83,14 @@ class Zend implements ClientInterface try { $response = $client->request(); - $result = $this->converter->convert($response->getBody()); + $result = $this->converter + ? $this->converter->convert($response->getBody()) + : [$response->getBody()]; $log['response'] = $result; } catch (\Zend_Http_Client_Exception $e) { - throw new \Magento\Payment\Gateway\Http\ClientException(__($e->getMessage())); + throw new \Magento\Payment\Gateway\Http\ClientException( + __($e->getMessage()) + ); } catch (\Magento\Payment\Gateway\Http\ConverterException $e) { throw $e; } finally { diff --git a/app/code/Magento/Payment/Gateway/Http/Converter/Soap/ObjectToArrayConverter.php b/app/code/Magento/Payment/Gateway/Http/Converter/Soap/ObjectToArrayConverter.php new file mode 100644 index 0000000000000000000000000000000000000000..e0045085417715e81b6251b719b6a326c63dcdbb --- /dev/null +++ b/app/code/Magento/Payment/Gateway/Http/Converter/Soap/ObjectToArrayConverter.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Gateway\Http\Converter\Soap; + +use Magento\Payment\Gateway\Http\ConverterInterface; + +class ObjectToArrayConverter implements ConverterInterface +{ + /** + * Converts gateway response to ENV structure + * + * @param mixed $response + * @return array + * @throws \Magento\Payment\Gateway\Http\ConverterException + */ + public function convert($response) + { + $response = (array) $response; + foreach ($response as $key => $value) { + if (is_object($value)) { + $response[$key] = $this->convert($value); + } + } + + return $response; + } +} diff --git a/app/code/Magento/Payment/Gateway/Http/ConverterInterface.php b/app/code/Magento/Payment/Gateway/Http/ConverterInterface.php index 776ea4b11673d8589dfca68b53c203da27986bda..673a0bbc847008af50b59bf41da2f0ed2f0f8af7 100644 --- a/app/code/Magento/Payment/Gateway/Http/ConverterInterface.php +++ b/app/code/Magento/Payment/Gateway/Http/ConverterInterface.php @@ -10,7 +10,7 @@ interface ConverterInterface /** * Converts gateway response to ENV structure * - * @param string $response + * @param mixed $response * @return array * @throws \Magento\Payment\Gateway\Http\ConverterException */ diff --git a/app/code/Magento/Payment/Gateway/Http/TransferInterface.php b/app/code/Magento/Payment/Gateway/Http/TransferInterface.php index abd3d530b2ac59ff37b88ee738d29d79a864e8a8..f2150c8e083f23f8a9fa3f0440a52c884f9cfac3 100644 --- a/app/code/Magento/Payment/Gateway/Http/TransferInterface.php +++ b/app/code/Magento/Payment/Gateway/Http/TransferInterface.php @@ -38,7 +38,7 @@ interface TransferInterface /** * Returns request body * - * @return string + * @return array */ public function getBody(); diff --git a/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php b/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php index e82e0605445a367d1bbf528989c2081393f35c2c..b9e55ef57eca1d31ef32912e1457f8772c5520af 100644 --- a/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php +++ b/app/code/Magento/Payment/Gateway/Validator/AbstractValidator.php @@ -30,6 +30,11 @@ abstract class AbstractValidator implements ValidatorInterface */ protected function createResult($isValid, array $fails = []) { - return $this->resultInterfaceFactory->create(['isValid' => (bool)$isValid, 'failsDescription' => $fails]); + return $this->resultInterfaceFactory->create( + [ + 'isValid' => (bool)$isValid, + 'failsDescription' => $fails + ] + ); } } diff --git a/app/code/Magento/Payment/Gateway/Validator/CountryValidator.php b/app/code/Magento/Payment/Gateway/Validator/CountryValidator.php index 3a0ff81186df3aff134f5e14c79d5a7f409a2e7b..0c65b09785040a45d402bed4653c4ab3b691db23 100644 --- a/app/code/Magento/Payment/Gateway/Validator/CountryValidator.php +++ b/app/code/Magento/Payment/Gateway/Validator/CountryValidator.php @@ -9,7 +9,7 @@ use Magento\Framework\Exception\NotFoundException; use Magento\Payment\Gateway\ConfigInterface; use Magento\Payment\Gateway\Validator\ResultInterfaceFactory; -class CountryValidator implements ValidatorInterface +class CountryValidator extends AbstractValidator { /** * @var \Magento\Payment\Gateway\ConfigInterface @@ -17,20 +17,15 @@ class CountryValidator implements ValidatorInterface private $config; /** - * @var ResultInterfaceFactory - */ - private $resultFactory; - - /** - * @param \Magento\Payment\Gateway\ConfigInterface $config * @param ResultInterfaceFactory $resultFactory + * @param \Magento\Payment\Gateway\ConfigInterface $config */ public function __construct( - ConfigInterface $config, - ResultInterfaceFactory $resultFactory + ResultInterfaceFactory $resultFactory, + ConfigInterface $config ) { $this->config = $config; - $this->resultFactory = $resultFactory; + parent::__construct($resultFactory); } /** @@ -55,10 +50,6 @@ class CountryValidator implements ValidatorInterface } } - return $this->resultFactory->create( - [ - 'isValid' => $isValid - ] - ); + return $this->createResult($isValid); } } diff --git a/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php b/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php index 05a476f9743c12a930052fe27c4dfcb057e54ae5..6e7c5c8c0ab5cecf0031ebc87519306289ea40e2 100644 --- a/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php +++ b/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php @@ -9,18 +9,13 @@ use Magento\Framework\ObjectManager\TMap; use Magento\Framework\ObjectManager\TMapFactory; use Magento\Payment\Gateway\Validator\ResultInterfaceFactory; -class ValidatorComposite implements ValidatorInterface +class ValidatorComposite extends AbstractValidator { /** * @var ValidatorInterface[] | TMap */ private $validators; - /** - * @var ResultInterfaceFactory - */ - private $resultFactory; - /** * @param ResultInterfaceFactory $resultFactory * @param array $validators @@ -37,7 +32,7 @@ class ValidatorComposite implements ValidatorInterface 'type' => 'Magento\Payment\Gateway\Validator\ValidatorInterface' ] ); - $this->resultFactory = $resultFactory; + parent::__construct($resultFactory); } /** @@ -61,11 +56,6 @@ class ValidatorComposite implements ValidatorInterface } } - return $this->resultFactory->create( - [ - 'isValid' => $isValid, - 'failsDescription' => $failsDescriptionAggregate - ] - ); + return $this->createResult($isValid, $failsDescriptionAggregate); } } diff --git a/app/code/Magento/Payment/Model/Method/Adapter.php b/app/code/Magento/Payment/Model/Method/Adapter.php index acb0e56809e30c3c677aebc4bffc5611ac7112f1..314a03d51550fedde3cd9b9e8c795eb25b4f5061 100644 --- a/app/code/Magento/Payment/Model/Method/Adapter.php +++ b/app/code/Magento/Payment/Model/Method/Adapter.php @@ -7,6 +7,9 @@ namespace Magento\Payment\Model\Method; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NotFoundException; +use Magento\Payment\Gateway\Command\CommandPoolInterface; +use Magento\Payment\Gateway\Config\ValueHandlerPoolInterface; +use Magento\Payment\Gateway\Validator\ValidatorPoolInterface; use Magento\Payment\Model\InfoInterface; use Magento\Payment\Model\MethodInterface; @@ -18,17 +21,17 @@ use Magento\Payment\Model\MethodInterface; class Adapter implements MethodInterface { /** - * @var \Magento\Payment\Gateway\Config\ValueHandlerPoolInterface + * @var ValueHandlerPoolInterface */ private $valueHandlerPool; /** - * @var \Magento\Payment\Gateway\Validator\ValidatorPoolInterface + * @var ValidatorPoolInterface */ private $validatorPool; /** - * @var \Magento\Payment\Gateway\Command\CommandPoolInterface + * @var CommandPoolInterface */ private $commandPool; @@ -69,9 +72,9 @@ class Adapter implements MethodInterface /** * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Payment\Gateway\Config\ValueHandlerPoolInterface $valueHandlerPool - * @param \Magento\Payment\Gateway\Validator\ValidatorPoolInterface $validatorPool - * @param \Magento\Payment\Gateway\Command\CommandPoolInterface $commandPool + * @param ValueHandlerPoolInterface $valueHandlerPool + * @param ValidatorPoolInterface $validatorPool + * @param CommandPoolInterface $commandPool * @param \Magento\Payment\Gateway\Data\PaymentDataObjectFactory $paymentDataObjectFactory * @param string $code * @param string $formBlockType @@ -79,9 +82,9 @@ class Adapter implements MethodInterface */ public function __construct( \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Payment\Gateway\Config\ValueHandlerPoolInterface $valueHandlerPool, - \Magento\Payment\Gateway\Validator\ValidatorPoolInterface $validatorPool, - \Magento\Payment\Gateway\Command\CommandPoolInterface $commandPool, + ValueHandlerPoolInterface $valueHandlerPool, + ValidatorPoolInterface $validatorPool, + CommandPoolInterface $commandPool, \Magento\Payment\Gateway\Data\PaymentDataObjectFactory $paymentDataObjectFactory, $code, $formBlockType, @@ -306,7 +309,15 @@ class Adapter implements MethodInterface private function getConfiguredValue($field) { $handler = $this->valueHandlerPool->get($field); - return $handler->handle($field, $this->getStore()); + $subject = [ + 'field' => $field + ]; + + if ($this->getInfoInstance()) { + $subject['payment'] = $this->paymentDataObjectFactory->create($this->getInfoInstance()); + } + + return $handler->handle($subject, $this->getStore()); } /** @@ -522,12 +533,6 @@ class Adapter implements MethodInterface */ public function getInfoInstance() { - if (!$this->infoInstance instanceof InfoInterface) { - throw new LocalizedException( - __('We cannot retrieve the payment information object instance.') - ); - } - return $this->infoInstance; } @@ -548,8 +553,16 @@ class Adapter implements MethodInterface return $this->getConfiguredValue($field); } + $subject = [ + 'field' => $field + ]; + + if ($this->getInfoInstance()) { + $subject['payment'] = $this->paymentDataObjectFactory->create($this->getInfoInstance()); + } + $handler = $this->valueHandlerPool->get($field); - return $handler->handle($field, (int)$storeId); + return $handler->handle($subject, (int)$storeId); } /** @@ -567,6 +580,7 @@ class Adapter implements MethodInterface /** * {inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function initialize($paymentAction, $stateObject) { diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php index 9872e20250bbe2d34c5375f22cbac5916e69cf3a..7a9d60d8acc18d9ce7fc373bdd14d56f0f0e26e6 100644 --- a/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php +++ b/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php @@ -5,50 +5,67 @@ */ namespace Magento\Payment\Test\Unit\Gateway\Command; +use Magento\Payment\Gateway\Command\GatewayCommand; +use Magento\Payment\Gateway\Http\ClientInterface; +use Magento\Payment\Gateway\Http\TransferFactoryInterface; +use Magento\Payment\Gateway\Request\BuilderInterface; +use Magento\Payment\Gateway\Response\HandlerInterface; +use Magento\Payment\Gateway\Validator\ValidatorInterface; + class GatewayCommandTest extends \PHPUnit_Framework_TestCase { - /** @var \Magento\Payment\Gateway\Command\GatewayCommand */ - protected $model; + /** @var GatewayCommand */ + protected $command; /** - * @var \Magento\Payment\Gateway\Request\BuilderInterface|\PHPUnit_Framework_MockObject_MockObject + * @var BuilderInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $requestBuilderMock; /** - * @var \Magento\Payment\Gateway\Http\TransferFactoryInterface|\PHPUnit_Framework_MockObject_MockObject + * @var TransferFactoryInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $transferFactoryMock; /** - * @var \Magento\Payment\Gateway\Http\ClientInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ClientInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $clientMock; /** - * @var \Magento\Payment\Gateway\Response\HandlerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var HandlerInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $responseHandlerMock; /** - * @var \Magento\Payment\Gateway\Validator\ValidatorInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ValidatorInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $validatorMock; protected function setUp() { - $this->requestBuilderMock = $this->getMockBuilder('Magento\Payment\Gateway\Request\BuilderInterface') + $this->requestBuilderMock = $this->getMockBuilder( + 'Magento\Payment\Gateway\Request\BuilderInterface' + ) ->getMockForAbstractClass(); - $this->transferFactoryMock = $this->getMockBuilder('Magento\Payment\Gateway\Http\TransferFactoryInterface') + $this->transferFactoryMock = $this->getMockBuilder( + 'Magento\Payment\Gateway\Http\TransferFactoryInterface' + ) ->getMockForAbstractClass(); - $this->clientMock = $this->getMockBuilder('Magento\Payment\Gateway\Http\ClientInterface') + $this->clientMock = $this->getMockBuilder( + 'Magento\Payment\Gateway\Http\ClientInterface' + ) ->getMockForAbstractClass(); - $this->responseHandlerMock = $this->getMockBuilder('Magento\Payment\Gateway\Response\HandlerInterface') + $this->responseHandlerMock = $this->getMockBuilder( + 'Magento\Payment\Gateway\Response\HandlerInterface' + ) ->getMockForAbstractClass(); - $this->validatorMock = $this->getMockBuilder('Magento\Payment\Gateway\Validator\ValidatorInterface') + $this->validatorMock = $this->getMockBuilder( + 'Magento\Payment\Gateway\Validator\ValidatorInterface' + ) ->getMockForAbstractClass(); - $this->model = new \Magento\Payment\Gateway\Command\GatewayCommand( + $this->command = new GatewayCommand( $this->requestBuilderMock, $this->transferFactoryMock, $this->clientMock, @@ -60,12 +77,19 @@ class GatewayCommandTest extends \PHPUnit_Framework_TestCase public function testExecute() { $commandSubject = ['authorize']; - $request = ['request_field1' => 'request_value1', 'request_field2' => 'request_value2']; + $request = [ + 'request_field1' => 'request_value1', + 'request_field2' => 'request_value2' + ]; $response = ['response_field1' => 'response_value1']; - $validationResult = $this->getMockBuilder('Magento\Payment\Gateway\Validator\ResultInterface') + $validationResult = $this->getMockBuilder( + 'Magento\Payment\Gateway\Validator\ResultInterface' + ) ->getMockForAbstractClass(); - $transferO = $this->getMockBuilder('Magento\Payment\Gateway\Http\TransferInterface') + $transferO = $this->getMockBuilder( + 'Magento\Payment\Gateway\Http\TransferInterface' + ) ->getMockForAbstractClass(); $this->requestBuilderMock->expects(static::once()) @@ -94,6 +118,56 @@ class GatewayCommandTest extends \PHPUnit_Framework_TestCase ->method('handle') ->with($commandSubject, $response); - $this->model->execute($commandSubject); + $this->command->execute($commandSubject); + } + + public function testExecuteValidationFail() + { + $this->setExpectedException( + 'Magento\Payment\Gateway\Command\CommandException' + ); + + $commandSubject = ['authorize']; + $request = [ + 'request_field1' => 'request_value1', + 'request_field2' => 'request_value2' + ]; + $response = ['response_field1' => 'response_value1']; + $validationResult = $this->getMockBuilder( + 'Magento\Payment\Gateway\Validator\ResultInterface' + ) + ->getMockForAbstractClass(); + + $transferO = $this->getMockBuilder( + 'Magento\Payment\Gateway\Http\TransferInterface' + ) + ->getMockForAbstractClass(); + + $this->requestBuilderMock->expects(static::once()) + ->method('build') + ->with($commandSubject) + ->willReturn($request); + + $this->transferFactoryMock->expects(static::once()) + ->method('create') + ->with($request) + ->willReturn($transferO); + + $this->clientMock->expects(static::once()) + ->method('placeRequest') + ->with($transferO) + ->willReturn($response); + $this->validatorMock->expects(static::once()) + ->method('validate') + ->with(array_merge($commandSubject, ['response' =>$response])) + ->willReturn($validationResult); + $validationResult->expects(static::once()) + ->method('isValid') + ->willReturn(false); + $validationResult->expects(static::once()) + ->method('getFailsDescription') + ->willReturn([]); + + $this->command->execute($commandSubject); } } diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Config/ConfigValueHandlerTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Config/ConfigValueHandlerTest.php index eebebfdadf275d0ae66013340594630543dce94e..3f1d4a280ef288d27e52458ecd3950bae936fc05 100644 --- a/app/code/Magento/Payment/Test/Unit/Gateway/Config/ConfigValueHandlerTest.php +++ b/app/code/Magento/Payment/Test/Unit/Gateway/Config/ConfigValueHandlerTest.php @@ -23,7 +23,8 @@ class ConfigValueHandlerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->configMock = $this->getMockBuilder('Magento\Payment\Gateway\ConfigInterface')->getMockForAbstractClass(); + $this->configMock = $this->getMockBuilder('Magento\Payment\Gateway\ConfigInterface') + ->getMockForAbstractClass(); $this->model = new ConfigValueHandler($this->configMock); } @@ -38,7 +39,7 @@ class ConfigValueHandlerTest extends \PHPUnit_Framework_TestCase ->with($field, $storeId) ->willReturn($expected); - $this->assertEquals($expected, $this->model->handle($field, $storeId)); + $this->assertEquals($expected, $this->model->handle(['field' => $field], $storeId)); } public function testHandleWithoutStoreId() @@ -51,6 +52,6 @@ class ConfigValueHandlerTest extends \PHPUnit_Framework_TestCase ->with($field, null) ->willReturn($expected); - $this->assertEquals($expected, $this->model->handle($field)); + $this->assertEquals($expected, $this->model->handle(['field' => $field])); } } diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/SoapTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/SoapTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ef4dd5be64546681d9e328223dad5e9f57386d38 --- /dev/null +++ b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/SoapTest.php @@ -0,0 +1,155 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Test\Unit\Gateway\Http\Client; + +use Magento\Payment\Gateway\Http\Client\Soap; + +class SoapTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $logger; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $clientFactory; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $converter; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $client; + + /** + * @var Soap + */ + private $gatewayClient; + + protected function setUp() + { + $this->logger = $this->getMockBuilder( + 'Magento\Payment\Model\Method\Logger' + ) + ->disableOriginalConstructor() + ->getMock(); + $this->clientFactory = $this->getMockBuilder( + 'Magento\Framework\Webapi\Soap\ClientFactory' + )->getMock(); + $this->converter = $this->getMockBuilder( + 'Magento\Payment\Gateway\Http\ConverterInterface' + )->getMockForAbstractClass(); + $this->client = $this->getMockBuilder('\SoapClient') + ->disableOriginalConstructor() + ->getMock(); + + $this->gatewayClient = new Soap( + $this->logger, + $this->clientFactory, + $this->converter + ); + } + + public function testPlaceRequest() + { + $expectedResult = [ + 'result' => [] + ]; + $soapResult = new \StdClass; + + $this->logger->expects(static::at(0)) + ->method('debug') + ->with( + ['request' => ['body']] + ); + $this->clientFactory->expects(static::once()) + ->method('create') + ->with('path_to_wsdl', ['trace' => true]) + ->willReturn($this->client); + $transferObject = $this->getTransferObject(); + $transferObject->expects(static::any()) + ->method('__setSoapHeaders') + ->with(['headers']); + $this->client->expects(static::once()) + ->method('__soapCall') + ->with('soapMethod', [['body']]) + ->willReturn($soapResult); + $this->converter->expects(static::once()) + ->method('convert') + ->with($soapResult) + ->willReturn($expectedResult); + $this->logger->expects(static::at(1)) + ->method('debug') + ->with(['response' => $expectedResult]); + + static::assertEquals( + $expectedResult, + $this->gatewayClient->placeRequest($transferObject) + ); + } + + public function testPlaceRequestSoapException() + { + $this->setExpectedException('Exception'); + + $this->logger->expects(static::at(0)) + ->method('debug') + ->with( + ['request' => ['body']] + ); + $this->clientFactory->expects(static::once()) + ->method('create') + ->with('path_to_wsdl', ['trace' => true]) + ->willReturn($this->client); + $transferObject = $this->getTransferObject(); + $transferObject->expects(static::any()) + ->method('__setSoapHeaders') + ->with(['headers']); + $this->client->expects(static::once()) + ->method('__soapCall') + ->with('soapMethod', [['body']]) + ->willThrowException(new \Exception); + $this->client->expects(static::once()) + ->method('__getLastRequest') + ->willReturn('RequestTrace'); + $this->logger->expects(static::at(1)) + ->method('debug') + ->with( + ['trace' => 'RequestTrace'] + ); + + $this->gatewayClient->placeRequest($transferObject); + } + + /** + * Returns prepared transfer object + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getTransferObject() + { + $transferObject = $this->getMockBuilder( + 'Magento\Payment\Gateway\Http\TransferInterface' + )->getMock(); + + $transferObject->expects(static::any()) + ->method('getBody') + ->willReturn(['body']); + $transferObject->expects(static::any()) + ->method('getClientConfig') + ->willReturn(['wsdl' => 'path_to_wsdl']); + $transferObject->expects(static::any()) + ->method('getMethod') + ->willReturn('soapMethod'); + + return $transferObject; + } +} diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/ZendTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/ZendTest.php index 43f2a400ccd77100161afbd5596ddf4fdbc7b8b1..e34cb00d5a24b4822ac6de12e6a406304fc5afcc 100644 --- a/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/ZendTest.php +++ b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Client/ZendTest.php @@ -65,7 +65,11 @@ class ZendTest extends \PHPUnit_Framework_TestCase $this->transferObjectMock = $this->getMockBuilder('Magento\Payment\Gateway\Http\TransferInterface') ->getMockForAbstractClass(); - $this->model = new Zend($this->zendClientFactoryMock, $this->converterMock, $this->loggerMock); + $this->model = new Zend( + $this->zendClientFactoryMock, + $this->loggerMock, + $this->converterMock + ); } public function testPlaceRequest() @@ -147,7 +151,7 @@ class ZendTest extends \PHPUnit_Framework_TestCase $this->transferObjectMock->expects($this->once())->method('getHeaders')->willReturn($headers); $this->transferObjectMock->expects($this->atLeastOnce())->method('getBody')->willReturn($body); $this->transferObjectMock->expects($this->once())->method('shouldEncode')->willReturn($shouldEncode); - $this->transferObjectMock->expects($this->once())->method('getUri')->willReturn($uri); + $this->transferObjectMock->expects(static::atLeastOnce())->method('getUri')->willReturn($uri); $this->clientMock->expects($this->once())->method('setConfig')->with($config)->willReturnSelf(); $this->clientMock->expects($this->once())->method('setMethod')->with($method)->willReturnSelf(); diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Http/Converter/Soap/ObjectToArrayConverterTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Converter/Soap/ObjectToArrayConverterTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c39c6dcb1d8b2f8374ba9897b062dd16320479bf --- /dev/null +++ b/app/code/Magento/Payment/Test/Unit/Gateway/Http/Converter/Soap/ObjectToArrayConverterTest.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Test\Unit\Gateway\Http\Converter\Soap; + +use Magento\Payment\Gateway\Http\Converter\Soap\ObjectToArrayConverter; + +class ObjectToArrayConverterTest extends \PHPUnit_Framework_TestCase +{ + public function testConvert() + { + $input = new \stdClass(); + $input->property = new \stdClass(); + $input->property2 = 'bla'; + $input->property->property3 = new \stdClass(); + $input->property->property4 = 'bla'; + $input->property->property3->property5 = 'bla'; + + $output = [ + 'property' => [ + 'property3' => [ + 'property5' => 'bla' + ], + 'property4' => 'bla' + ], + 'property2' => 'bla' + ]; + + $converter = new ObjectToArrayConverter(); + static::assertEquals($output, $converter->convert($input)); + + } +} diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Validator/CountryValidatorTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Validator/CountryValidatorTest.php index 38ac5d69dd3d01176e8f53c8f45a1057dc5ed17c..554b13ef74646f8e1cd6a62f8ede96b1491352ae 100644 --- a/app/code/Magento/Payment/Test/Unit/Gateway/Validator/CountryValidatorTest.php +++ b/app/code/Magento/Payment/Test/Unit/Gateway/Validator/CountryValidatorTest.php @@ -38,8 +38,8 @@ class CountryValidatorTest extends \PHPUnit_Framework_TestCase ->getMock(); $this->model = new \Magento\Payment\Gateway\Validator\CountryValidator( - $this->configMock, - $this->resultFactoryMock + $this->resultFactoryMock, + $this->configMock ); } @@ -62,7 +62,7 @@ class CountryValidatorTest extends \PHPUnit_Framework_TestCase $this->resultFactoryMock->expects($this->once()) ->method('create') - ->with(['isValid' => $isValid]) + ->with(['isValid' => $isValid, 'failsDescription' => []]) ->willReturn($this->resultMock); $this->assertSame($this->resultMock, $this->model->validate($validationSubject)); @@ -90,7 +90,7 @@ class CountryValidatorTest extends \PHPUnit_Framework_TestCase $this->resultFactoryMock->expects($this->once()) ->method('create') - ->with(['isValid' => $isValid]) + ->with(['isValid' => $isValid, 'failsDescription' => []]) ->willReturn($this->resultMock); $this->assertSame($this->resultMock, $this->model->validate($validationSubject)); diff --git a/app/code/Magento/Payment/etc/payment.xml b/app/code/Magento/Payment/etc/payment.xml index 5560a70f11b325ea8d12a85ec5fd2582b29593f1..1d52b718925cddf25f531b1b6d8ea9c941a9b901 100644 --- a/app/code/Magento/Payment/etc/payment.xml +++ b/app/code/Magento/Payment/etc/payment.xml @@ -35,9 +35,6 @@ <type id="DN" order="60"> <label>Diners</label> </type> - <type id="JC" order="70"> - <label>JCB</label> - </type> <type id="MI" order="80"> <label>Maestro International</label> </type> diff --git a/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml b/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml index c6a429a0fbe08f624c53f03d7998879281dfde27..a2cf8e3a6383311ba7b2e20bd57c858fa88d368f 100644 --- a/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml +++ b/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml @@ -7,14 +7,22 @@ <?php // @codingStandardsIgnoreFile -/** @var \Magento\Payment\Block\Transparent\Form $block*/ +/** @var \Magento\Payment\Block\Transparent\Form $block */ $code = $block->getMethodCode(); ?> <!-- IFRAME for request to Payment Gateway --> -<iframe id="<?php echo $code ?>-transparent-iframe" data-container="<?php echo $code ?>-transparent-iframe" allowtransparency="true" frameborder="0" name="iframeTransparent" style="display:none;width:100%;background-color:transparent" src="<?php echo $block->getViewFileUrl('blank.html') ?>"></iframe> -<div id="payment_form_<?php echo $code ?>" - data-mage-init='{ +<iframe id="<?php echo $code ?>-transparent-iframe" + data-container="<?php echo $code ?>-transparent-iframe" + allowtransparency="true" + frameborder="0" + name="iframeTransparent" + style="display: none; width: 100%; background-color: transparent;" + src="<?php echo $block->getViewFileUrl('blank.html') ?>"></iframe> +<fieldset + id="payment_form_<?php echo $code ?>" + class="admin__fieldset" + data-mage-init='{ "transparent":{ "controller":"<?php echo $block->getRequest()->getControllerName() ?>", "gateway":"<?php echo $block->getMethodCode() ?>", @@ -25,71 +33,96 @@ $code = $block->getMethodCode(); "expireYearLength":"<?php echo $block->getMethodConfigData('cc_year_length') ?>", "nativeAction":"<?php echo $block->getUrl('*/*/save', ['_secure' => $block->getRequest()->isSecure()]) ?>" }, "validation":[]}' - style="display:none;"> + style="display: none;"> + <div class="admin__field _required"> + <label for="<?php echo $code ?>_cc_type" class="admin__field-label"> + <span><?php echo __('Credit Card Type') ?></span> + </label> - <div class="field required type"> - <label for="<?php echo $code ?>_cc_type" class="label"><span><?php echo __('Credit Card Type') ?></span></label> - <div class="control"> - <select id="<?php echo $code ?>_cc_type" data-container="<?php echo $code ?>-cc-type" name="payment[cc_type]" data-validate='{required:true, "validate-cc-type-select":"#<?php echo $code ?>_cc_number"}'> - <option value=""><?php echo __('--Please Select--')?></option> - <?php $_ccType = $block->getInfoData('cc_type') ?> - <?php foreach ($block->getCcAvailableTypes() as $_typeCode => $_typeName): ?> - <option value="<?php echo $_typeCode ?>"<?php if ($_typeCode == $_ccType): ?> selected="selected"<?php endif ?>><?php echo $_typeName ?></option> - <?php endforeach ?> - </select> - </div> + <div class="admin__field-control"> + <select id="<?php echo $code ?>_cc_type" + data-container="<?php echo $code ?>-cc-type" + name="payment[cc_type]" + data-validate='{required:true, "validate-cc-type-select":"#<?php echo $code ?>_cc_number"}' + class="admin__control-select"> + <option value=""><?php echo __('Please Select') ?></option> + <?php $_ccType = $block->getInfoData('cc_type') ?> + <?php foreach ($block->getCcAvailableTypes() as $_typeCode => $_typeName): ?> + <option + value="<?php echo $_typeCode ?>"<?php if ($_typeCode == $_ccType): ?> selected="selected"<?php endif ?>><?php echo $_typeName ?></option> + <?php endforeach ?> + </select> </div> + </div> - <div class="field required number"> - <label for="<?php echo $code ?>_cc_number" class="label"><span><?php echo __('Credit Card Number') ?></span></label> - <div class="control"> - <input type="number" id="<?php echo $code ?>_cc_number" data-container="<?php echo $code ?>-cc-number" name="payment[cc_number]" title="<?php echo __('Credit Card Number') ?>" class="input-text" value="" data-validate='{"required-number":true, "validate-cc-number":"#<?php echo $code ?>_cc_type", "validate-cc-type":"#<?php echo $code ?>_cc_type"}' autocomplete="off"/> - </div> + <div class="admin__field _required field-number"> + <label for="<?php echo $code ?>_cc_number" class="admin__field-label"> + <span><?php echo __('Credit Card Number') ?></span> + </label> + + <div class="admin__field-control"> + <input type="text" id="<?php echo $code ?>_cc_number" data-container="<?php echo $code ?>-cc-number" + name="payment[cc_number]" title="<?php echo __('Credit Card Number') ?>" + class="admin__control-text" + value="" + data-validate='{"required-number":true, "validate-cc-number":"#<?php echo $code ?>_cc_type", "validate-cc-type":"#<?php echo $code ?>_cc_type"}' + autocomplete="off"/> </div> + </div> - <div class="field required date" id="<?php echo $code ?>_cc_type_exp_div"> - <label for="<?php echo $code ?>_expiration" class="label"><span><?php echo __('Expiration Date') ?></span></label> - <div class="control"> - <div class="fields group group-2"> - <div class="field no-label month"> - <div class="control"> - <select id="<?php echo $code ?>_expiration" name="payment[cc_exp_month]" data-container="<?php echo $code ?>-cc-month" class="month" data-validate='{required:true, "validate-cc-exp":"#<?php echo $code ?>_expiration_yr"}'> - <?php $_ccExpMonth = $block->getInfoData('cc_exp_month') ?> - <?php foreach ($block->getCcMonths() as $k => $v): ?> - <option value="<?php echo $k ? $k : '' ?>"<?php if ($k == $_ccExpMonth): ?> selected="selected"<?php endif ?>><?php echo $v ?></option> - <?php endforeach ?> - </select> - </div> - </div> - <div class="field no-label year"> - <div class="control"> - <?php $_ccExpYear = $block->getInfoData('cc_exp_year') ?> - <select id="<?php echo $code ?>_expiration_yr" name="payment[cc_exp_year]" class="year" data-container="<?php echo $code ?>-cc-year" data-validate='{required:true}'> - <?php foreach ($block->getCcYears() as $k => $v): ?> - <option value="<?php echo $k ? $k : '' ?>"<?php if ($k == $_ccExpYear): ?> selected="selected"<?php endif ?>><?php echo $v ?></option> - <?php endforeach ?> - </select> - </div> - </div> - </div> - </div> + <div class="admin__field _required field-date" id="<?php echo $code ?>_cc_type_exp_div"> + <label for="<?php echo $code ?>_expiration" class="admin__field-label"> + <span><?php echo __('Expiration Date') ?></span> + </label> + + <div class="admin__field-control"> + <select id="<?php echo $code ?>_expiration" name="payment[cc_exp_month]" + data-container="<?php echo $code ?>-cc-month" + class="admin__control-select admin__control-select-month" + data-validate='{required:true, "validate-cc-exp":"#<?php echo $code ?>_expiration_yr"}'> + <?php $_ccExpMonth = $block->getInfoData('cc_exp_month') ?> + <?php foreach ($block->getCcMonths() as $k => $v): ?> + <option + value="<?php echo $k ? $k : '' ?>"<?php if ($k == $_ccExpMonth): ?> selected="selected"<?php endif ?>><?php echo $v ?></option> + <?php endforeach ?> + </select> + + <?php $_ccExpYear = $block->getInfoData('cc_exp_year') ?> + <select id="<?php echo $code ?>_expiration_yr" name="payment[cc_exp_year]" + class="admin__control-select admin__control-select-year" + data-container="<?php echo $code ?>-cc-year" data-validate='{required:true}'> + <?php foreach ($block->getCcYears() as $k => $v): ?> + <option + value="<?php echo $k ? $k : '' ?>"<?php if ($k == $_ccExpYear): ?> selected="selected"<?php endif ?>><?php echo $v ?></option> + <?php endforeach ?> + </select> </div> - <?php if ($block->hasVerification()): ?> - <div class="field required cvv" id="<?php echo $code ?>_cc_type_cvv_div"> - <label for="<?php echo $code ?>_cc_cid" class="label"><span><?php echo __('Card Verification Number') ?></span></label> - <div class="control"> - <input type="number" title="<?php echo __('Card Verification Number') ?>" data-container="<?php echo $code ?>-cc-cvv" class="input-text cvv" id="<?php echo $code ?>_cc_cid" name="payment[cc_cid]" value="" data-validate='{"required-number":true, "validate-cc-cvn":"#<?php echo $code ?>_cc_type"}' autocomplete="off"/> - </div> + </div> + <?php if ($block->hasVerification()): ?> + <div class="admin__field _required field-cvv" id="<?php echo $code ?>_cc_type_cvv_div"> + <label for="<?php echo $code ?>_cc_cid" class="admin__field-label"> + <span><?php echo __('Card Verification Number') ?></span> + </label> + + <div class="admin__field-control"> + <input type="text" title="<?php echo __('Card Verification Number') ?>" + data-container="<?php echo $code ?>-cc-cvv" + class="admin__control-text cvv" + id="<?php echo $code ?>_cc_cid" name="payment[cc_cid]" + value="" + data-validate='{"required-number":true, "validate-cc-cvn":"#<?php echo $code ?>_cc_type"}' + autocomplete="off"/> </div> - <?php endif; ?> - <?php echo $block->getChildHtml() ?> -</div> + </div> + <?php endif; ?> + <?php echo $block->getChildHtml() ?> +</fieldset> <script> /** * Disable card server validation in admin */ - require(["Magento_Sales/order/create/form"], function(){ + require(["Magento_Sales/order/create/form"], function () { order.addExcludedPaymentMethod('<?php echo $code ?>'); }); </script> diff --git a/app/code/Magento/Payment/view/base/web/images/cc/ae.png b/app/code/Magento/Payment/view/base/web/images/cc/ae.png new file mode 100644 index 0000000000000000000000000000000000000000..f72ae5c26c314ac95ebfabb5887f3a1daf4cdd22 Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/ae.png differ diff --git a/app/code/Magento/Payment/view/base/web/images/cc/di.png b/app/code/Magento/Payment/view/base/web/images/cc/di.png new file mode 100644 index 0000000000000000000000000000000000000000..130d5a4aec88e9eec99e435f94f75725bf5728c7 Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/di.png differ diff --git a/app/code/Magento/Payment/view/base/web/images/cc/dn.png b/app/code/Magento/Payment/view/base/web/images/cc/dn.png new file mode 100644 index 0000000000000000000000000000000000000000..3444db7ea5945a86ac9ca506a5ff25939bb49c6b Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/dn.png differ diff --git a/app/code/Magento/Payment/view/base/web/images/cc/jc.png b/app/code/Magento/Payment/view/base/web/images/cc/jc.png new file mode 100644 index 0000000000000000000000000000000000000000..86df1caa5da6e869e462941402e1129213e9f05c Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/jc.png differ diff --git a/app/code/Magento/Payment/view/base/web/images/cc/mc.png b/app/code/Magento/Payment/view/base/web/images/cc/mc.png new file mode 100644 index 0000000000000000000000000000000000000000..bf0a4c2b8727fa824f3e902e88ee31d4d144a474 Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/mc.png differ diff --git a/app/code/Magento/Payment/view/base/web/images/cc/sm.png b/app/code/Magento/Payment/view/base/web/images/cc/sm.png new file mode 100644 index 0000000000000000000000000000000000000000..d239695ab2a41091981b4f34732276281bf8c992 Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/sm.png differ diff --git a/app/code/Magento/Payment/view/base/web/images/cc/un.png b/app/code/Magento/Payment/view/base/web/images/cc/un.png new file mode 100644 index 0000000000000000000000000000000000000000..b60791a0900184b6aea16155e06777ea7646158c Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/un.png differ diff --git a/app/code/Magento/Payment/view/base/web/images/cc/vi.png b/app/code/Magento/Payment/view/base/web/images/cc/vi.png new file mode 100644 index 0000000000000000000000000000000000000000..0885f78a93765fa61e350c60641302b498b109c0 Binary files /dev/null and b/app/code/Magento/Payment/view/base/web/images/cc/vi.png differ diff --git a/app/code/Magento/Payment/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Payment/view/frontend/layout/checkout_onepage_index.xml index 3f89143cb971ba996a0a3298a3807bec96d2d958..979a1c039cfedda69eb2821b528ad9c246824b68 100644 --- a/app/code/Magento/Payment/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/Payment/view/frontend/layout/checkout_onepage_index.xml @@ -15,10 +15,26 @@ <item name="children" xsi:type="array"> <item name="steps" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="payment" xsi:type="array"> + <item name="billing-step" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="sortOrder" xsi:type="string">2</item> <item name="children" xsi:type="array"> - <item name="free" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Payment/js/view/payment/free-method</item> + <item name="payment" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="renders" xsi:type="array"> + <!-- merge payment method renders here --> + <item name="children" xsi:type="array"> + <item name="free-payments" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Payment/js/view/payment/payments</item> + <item name="methods" xsi:type="array"> + <item name="free" xsi:type="array"> + <item name="isBillingAddressRequired" xsi:type="boolean">true</item> + </item> + </item> + </item> + </item> + </item> + </item> </item> </item> </item> @@ -31,4 +47,4 @@ </arguments> </referenceBlock> </body> -</page> +</page> \ No newline at end of file diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml index 93ac9970e145338451895c1d54d29a977e19f7bc..f71a9bdd9fa412d02330b38ad6cb347b409bfd19 100644 --- a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml +++ b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml @@ -26,9 +26,15 @@ $params = $block->getParams(); window.top.location = "<?php echo $params['order_success'] ?>"; <?php else: ?> var require = window.top.require; - require(['jquery'], function($) { - $('#originalPlaceOrder').click(); - }); + require( + [ + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/action/place-order' + ], + function(quote, placeOrderAction) { + placeOrderAction(quote.paymentMethod(), true); + } + ); <?php endif; ?> </script> </head> diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js new file mode 100644 index 0000000000000000000000000000000000000000..ef6dd82c179b4591a89a43987f72ca91ca974478 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js @@ -0,0 +1,19 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + return { + creditCard: null, + creditCardNumber: null, + expirationMonth: null, + expirationYear: null, + cvvCode: null + } + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..1f13a5af7c60a297dd13867daa9e1ba4694fbe5d --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js @@ -0,0 +1,72 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'mageUtils', + 'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator', + 'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/credit-card-type' + ], + function (utils, luhn10, creditCardTypes) { + 'use strict'; + + function resultWrapper(card, isPotentiallyValid, isValid) { + return { + card: card, + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + return function (value) { + var potentialTypes, + cardType, + valid, + i, + maxLength; + + if (utils.isEmpty(value)) { + return resultWrapper(null, false, false); + } + + value = value.replace(/\-|\s/g, ''); + + if (!/^\d*$/.test(value)) { + return resultWrapper(null, false, false); + } + + potentialTypes = creditCardTypes.getCardTypes(value); + + if (potentialTypes.length === 0) { + return resultWrapper(null, false, false); + } else if (potentialTypes.length !== 1) { + return resultWrapper(null, true, false); + } + + cardType = potentialTypes[0]; + + if (cardType.type === 'unionpay') { // UnionPay is not Luhn 10 compliant + valid = true; + } else { + valid = luhn10(value); + } + + for (i = 0; i < cardType.lengths.length; i++) { + if (cardType.lengths[i] === value.length) { + return resultWrapper(cardType, valid, valid); + } + } + + maxLength = Math.max.apply(null, cardType.lengths); + + if (value.length < maxLength) { + return resultWrapper(cardType, true, false); + } + + return resultWrapper(cardType, false, false); + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js new file mode 100644 index 0000000000000000000000000000000000000000..71e0e57c5c16e71a394d1fa948f35ed807c75495 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js @@ -0,0 +1,144 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'jquery', + 'mageUtils' + ], + function ($, utils) { + 'use strict'; + var types = [ + { + title: 'Visa', + type: 'VI', + pattern: '^4\\d*$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CVV', + size: 3 + } + }, + { + title: 'MasterCard', + type: 'MC', + pattern: '^5([1-5]\\d*)?$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CVC', + size: 3 + } + }, + { + title: 'American Express', + type: 'AE', + pattern: '^3([47]\\d*)?$', + isAmex: true, + gaps: [4, 10], + lengths: [15], + code: { + name: 'CID', + size: 4 + } + }, + { + title: 'Diners', + type: 'DN', + pattern: '^3((0([0-5]\\d*)?)|[689]\\d*)?$', + gaps: [4, 10], + lengths: [14], + code: { + name: 'CVV', + size: 3 + } + }, + { + title: 'Discover', + type: 'DI', + pattern: '^6(0|01|011\\d*|5\\d*|4|4[4-9]\\d*)?$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CID', + size: 3 + } + }, + { + title: 'JCB', + type: 'JC', + pattern: '^((2|21|213|2131\\d*)|(1|18|180|1800\\d*)|(3|35\\d*))$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CVV', + size: 3 + } + }, + { + title: 'UnionPay', + type: 'UN', + pattern: '^6(2\\d*)?$', + gaps: [4, 8, 12], + lengths: [16, 17, 18, 19], + code: { + name: 'CVN', + size: 3 + } + }, + { + title: 'Maestro', + type: 'SM', + pattern: '(^(5[0678])[0-9]{11,18}$)' + + '|(^(6[^05])[0-9]{11,18}$)' + + '|(^(601)[^1][0-9]{9,16}$)' + + '|(^(6011)[0-9]{9,11}$)' + + '|(^(6011)[0-9]{13,16}$)' + + '|(^(65)[0-9]{11,13}$)' + + '|(^(65)[0-9]{15,18}$)' + + '|(^(49030)[2-9]([0-9]{10}$' + + '|[0-9]{12,13}$))' + + '|(^(49033)[5-9]([0-9]{10}$' + + '|[0-9]{12,13}$))' + + '|(^(49110)[1-2]([0-9]{10}$' + + '|[0-9]{12,13}$))' + + '|(^(49117)[4-9]([0-9]{10}$|[0-9]{12,13}$))' + + '|(^(49118)[0-2]([0-9]{10}$|[0-9]{12,13}$))' + + '|(^(4936)([0-9]{12}$|[0-9]{14,15}$))', + gaps: [4, 8, 12], + lengths: [12, 13, 14, 15, 16, 17, 18, 19], + code: { + name: 'CVC', + size: 3 + } + } + ]; + return { + getCardTypes: function (cardNumber) { + var i, value, + result = []; + + if (utils.isEmpty(cardNumber)) { + return result; + } + + if (cardNumber === '') { + return $.extend(true, {}, types); + } + + for (i = 0; i < types.length; i++) { + value = types[i]; + + if (new RegExp(value.pattern).test(cardNumber)) { + result.push($.extend(true, {}, value)); + } + } + return result; + } + } + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..38e93f084a25c72c8be813e52fa4f75b44c46622 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js @@ -0,0 +1,22 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + /** + * Luhn algorithm verification + */ + return function(a, b, c, d, e) { + for(d = +a[b = a.length-1], e = 0; b--;) { + c = +a[b]; + d += ++e % 2 ? 2 * c % 10 + (c > 4) : c; + } + return !(d%10) + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..45733c9f8ff4623727ba757c88f0cd92ad346f21 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js @@ -0,0 +1,41 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + + function resultWrapper(isValid, isPotentiallyValid) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + /** + * CVV number validation + * validate digit count fot CVV code + */ + return function(value, maxLength) { + var DEFAULT_LENGTH = 3; + maxLength = maxLength || DEFAULT_LENGTH; + + if (!/^\d*$/.test(value)) { + return resultWrapper(false, false); + } + if (value.length === maxLength) { + return resultWrapper(true, true); + } + if (value.length < maxLength) { + return resultWrapper(false, true); + } + if (value.length > maxLength) { + return resultWrapper(false, false); + } + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..f7266a282740c6eb258839a7746bf57dbb1b329b --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js @@ -0,0 +1,51 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'mageUtils', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/parse-date', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator' + ], + function(utils, parseDate, expirationMonth, expirationYear) { + 'use strict'; + + function resultWrapper(isValid, isPotentiallyValid, month, year) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid, + month: month, + year: year + }; + } + + return function(value) { + var date, + monthValid, + yearValid; + + if (utils.isEmpty(value)) { + return resultWrapper(false, false, null, null); + } + + value = value.replace(/^(\d\d) (\d\d(\d\d)?)$/, '$1/$2'); + date = parseDate(value); + monthValid = expirationMonth(date.month); + yearValid = expirationYear(date.year); + + if (monthValid.isValid && yearValid.isValid) { + return resultWrapper(true, true, date.month, date.year); + } + + if (monthValid.isPotentiallyValid && yearValid.isPotentiallyValid) { + return resultWrapper(false, true, null, null); + } + + return resultWrapper(false, false, null, null); + } + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..c41ad14a459dbe7f788b8b0e21dd07a62150561c --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js @@ -0,0 +1,41 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function () { + 'use strict'; + + function resultWrapper(isValid, isPotentiallyValid) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + return function (value) { + var month, + monthValid; + + if ((value.replace(/\s/g, '') === '') || (value === '0')) { + return resultWrapper(false, true); + } + + if (!/^\d*$/.test(value)) { + return resultWrapper(false, false); + } + + if (isNaN(value)) { + return resultWrapper(false, false); + } + + month = parseInt(value, 10); + monthValid = month > 0 && month < 13; + + return resultWrapper(monthValid, monthValid); + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..132c8dc42e9f2675647eb4112d09100fae84f7dd --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js @@ -0,0 +1,42 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + + function resultWrapper(isValid, isPotentiallyValid) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + return function(value) { + var currentYear = new Date().getFullYear(), + len = value.length, + valid, + expMaxLifetime = 19; + + if (value.replace(/\s/g, '') === '') { + return resultWrapper(false, true); + } + + if (!/^\d*$/.test(value)) { + return resultWrapper(false, false); + } + + if (len !== 4) { + return resultWrapper(false, true); + } + + value = parseInt(value, 10); + valid = value >= currentYear && value <= currentYear + expMaxLifetime; + return resultWrapper(valid, valid); + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js new file mode 100644 index 0000000000000000000000000000000000000000..119bfa698732ecb0bf8895dad4ec75d8edeac063 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js @@ -0,0 +1,32 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + return function(value) { + var month, len; + + if (value.match('/')) { + value = value.split(/\s*\/\s*/g); + + return { + month: value[0], + year: value.slice(1).join() + }; + } + + len = (value[0] === '0' || value.length > 5 || value.length === 4 || value.length === 3) ? 2 : 1; + month = value.substr(0, len); + + return { + month: month, + year: value.substr(month.length, 4) + }; + } + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js new file mode 100644 index 0000000000000000000000000000000000000000..660f3e3c0471f40d168481723d316bfcf792c0ed --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js @@ -0,0 +1,74 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +(function (factory) { + if (typeof define === 'function' && define.amd) { + define([ + 'jquery', + 'Magento_Payment/js/model/credit-card-validation/cvv-validator', + 'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator', + 'Magento_Payment/js/model/credit-card-validation/credit-card-data' + ], factory); + } else { + factory(jQuery); + } +}(function ($, cvvValidator, creditCardNumberValidator, expirationDateValidator, monthValidator, creditCardData) { + "use strict"; + + $.each({ + 'validate-card-number': [ + /** + * Validate credit card number based on mod 10 + * @param number - credit card number + * @return {boolean} + */ + function (number) { + return creditCardNumberValidator(number).isValid; + }, + 'Please enter a valid credit card number.' + ], + 'validate-card-date': [ + /** + * Validate credit card number based on mod 10 + * @param date - month + * @return {boolean} + */ + function (date) { + return monthValidator(date).isValid; + }, + 'Incorrect credit card expiration month.' + ], + 'validate-card-cvv': [ + /** + * Validate credit card number based on mod 10 + * @param cvv - month + * @return {boolean} + */ + function (cvv) { + var maxLength = creditCardData.creditCard ? creditCardData.creditCard.code.size : 3; + return cvvValidator(cvv, maxLength).isValid; + }, + 'Please enter a valid credit card verification number.' + ], + 'validate-card-year': [ + /** + * Validate credit card number based on mod 10 + * @param date - month + * @return {boolean} + */ + function (date) { + return monthValidator(date).isValid; + }, + 'Incorrect credit card expiration year.' + ] + + }, function (i, rule) { + rule.unshift(i); + $.validator.addMethod.apply($.validator, rule); + }); +})); \ No newline at end of file diff --git a/app/code/Magento/Payment/view/frontend/web/js/view/payment/cc-form.js b/app/code/Magento/Payment/view/frontend/web/js/view/payment/cc-form.js index 8e6e53f0ae7e5061322e0a525bc733c057d938e2..5c1abc1e3c75b1721a889badee6e364009bd448f 100644 --- a/app/code/Magento/Payment/view/frontend/web/js/view/payment/cc-form.js +++ b/app/code/Magento/Payment/view/frontend/web/js/view/payment/cc-form.js @@ -7,21 +7,24 @@ define( [ 'underscore', - 'uiComponent', + 'Magento_Checkout/js/view/payment/default', + 'Magento_Payment/js/model/credit-card-validation/credit-card-data', + 'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator', 'mage/translate' ], - function (_, component, $t) { - return component.extend({ + function (_, Component, creditCardData, cardNumberValidator, $t) { + return Component.extend({ defaults: { - template: 'Magento_Payment/payment/cc-form', creditCardType: '', creditCardExpYear: '', creditCardExpMonth: '', creditCardNumber: '', creditCardSsStartMonth: '', creditCardSsStartYear: '', - creditCardVerificationNumber: '' + creditCardVerificationNumber: '', + selectedCardType: null }, + initObservable: function () { this._super() .observe([ @@ -31,15 +34,62 @@ define( 'creditCardNumber', 'creditCardVerificationNumber', 'creditCardSsStartMonth', - 'creditCardSsStartYear' + 'creditCardSsStartYear', + 'selectedCardType' ]); return this; }, + + initialize: function() { + var self = this; + this._super(); + + //Set credit card number to credit card data object + this.creditCardNumber.subscribe(function(value) { + var result; + self.selectedCardType(null); + + if (value == '' || value == null) { + return false; + } + result = cardNumberValidator(value); + + if (!result.isPotentiallyValid && !result.isValid) { + return false; + } + if (result.card !== null) { + self.selectedCardType(result.card.type); + creditCardData.creditCard = result.card; + } + + if (result.isValid) { + creditCardData.creditCardNumber = value; + self.creditCardType(result.card.type); + } + }); + + //Set expiration year to credit card data object + this.creditCardExpYear.subscribe(function(value) { + creditCardData.expirationYear = value; + }); + + //Set expiration month to credit card data object + this.creditCardExpMonth.subscribe(function(value) { + creditCardData.expirationYear = value; + }); + + //Set cvv code to credit card data object + this.creditCardVerificationNumber.subscribe(function(value) { + creditCardData.cvvCode = value; + }); + }, + getCode: function() { return 'cc'; }, getData: function() { return { + 'method': this.item.method, 'cc_type': this.creditCardType(), 'cc_exp_year': this.creditCardExpYear(), 'cc_exp_month': this.creditCardExpMonth(), diff --git a/app/code/Magento/Payment/view/frontend/web/js/view/review/actions/iframe.js b/app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js similarity index 90% rename from app/code/Magento/Payment/view/frontend/web/js/view/review/actions/iframe.js rename to app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js index 5349dab7b4d93202a4dec1f9924de97d0c564645..83a229af3bfbea8019ea0897b206b91f768377ee 100644 --- a/app/code/Magento/Payment/view/frontend/web/js/view/review/actions/iframe.js +++ b/app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js @@ -6,12 +6,12 @@ /*global define*/ define( [ - 'uiComponent' + 'Magento_Payment/js/view/payment/cc-form' ], function (Component) { return Component.extend({ defaults: { - template: 'Magento_Payment/review/actions/iframe' + template: 'Magento_Payment/payment/iframe' }, getSource: function () { return window.checkoutConfig.payment.iframe.source[this.getCode()]; @@ -34,9 +34,6 @@ define( getCardFieldsMap: function() { return window.checkoutConfig.payment.iframe.cardFieldsMap[this.getCode()]; }, - getCode: function() { - return this.index; - }, originalPlaceOrder: function(parent) { return parent.placeOrder.bind(parent); }, diff --git a/app/code/Magento/Payment/view/frontend/web/js/view/payment/method-renderer/free-method.js b/app/code/Magento/Payment/view/frontend/web/js/view/payment/method-renderer/free-method.js new file mode 100644 index 0000000000000000000000000000000000000000..72c249027684b153892f992c3ce14cdd47aa84ad --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/view/payment/method-renderer/free-method.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'Magento_Checkout/js/view/payment/default', + 'Magento_Checkout/js/model/quote' + ], + function (Component, quote) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Magento_Payment/payment/free' + }, + + /** Returns is method available */ + isAvailable: function() { + return quote.totals().grand_total <= 0; + } + }); + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/view/payment/payments.js b/app/code/Magento/Payment/view/frontend/web/js/view/payment/payments.js new file mode 100644 index 0000000000000000000000000000000000000000..cff4f3810842e9ce77510d4b95da261e9475392b --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/view/payment/payments.js @@ -0,0 +1,26 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/payment/renderer-list' + ], + function ( + Component, + rendererList + ) { + 'use strict'; + rendererList.push( + { + type: 'free', + component: 'Magento_Payment/js/view/payment/method-renderer/free-method' + } + ); + /** Add view logic here if needed */ + return Component.extend({}); + } +); \ No newline at end of file diff --git a/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html b/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html index 96fd1446d2cf33028c3f63f07d6400b1ef82a342..49d1d57f958bdd938284aaeaf11abf1ca926fb3d 100644 --- a/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html +++ b/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html @@ -4,20 +4,36 @@ * See COPYING.txt for license details. */ --> + <fieldset data-bind="attr: {class: 'fieldset payment items ccard ' + getCode(), id: 'payment_form_' + getCode()}"> <!-- ko if: (isShowLegend())--> - <legend class="legend"><span><!-- ko text: $t('Credit Card Information')--><!-- /ko --></span></legend><br /> + <legend class="legend"> + <span><!-- ko text: $t('Credit Card Information')--><!-- /ko --></span> + </legend><br /> <!-- /ko --> <div class="field type required"> <label data-bind="attr: {for: getCode() + '_cc_type'}" class="label"> <span><!-- ko text: $t('Credit Card Type')--><!-- /ko --></span> </label> <div class="control"> - <select name="payment[cc_type]" class="select" - data-bind="attr: {id: getCode() + '_cc_type', 'data-container': getCode() + '-cc-type', 'data-validate': JSON.stringify({required:true, 'validate-cc-type-select':'#' + getCode() + '_cc_number'})}, - mageInit: {creditCardType:{creditCardTypeContainer:'#' + getCode() + '_cc_type_ss_div'}}, - enable: isActive($parents), options: getCcAvailableTypesValues(), optionsValue: 'value', optionsText: 'type', optionsCaption: $t('--Please Select--'), value: creditCardType"> - </select> + <ul class="credit-card-types"> + <!-- ko foreach: {data: getCcAvailableTypesValues(), as: 'item'} --> + <li class="item" data-bind="css: {_active: $parent.selectedCardType() == item.value} "> + <!-- if picture --> + <img data-bind="attr: { + 'src': 'Magento_Payment::images/cc/'+ item.value + '.png', + 'alt': item.type + }"> + <!-- if NOpicture --> + <span><!-- ko text: item.type --><!-- /ko --></span> + </li> + <!--/ko--> + </ul> + <input type="hidden" + name="payment[cc_number]" + class="input-text" + value="" + data-bind="attr: {id: getCode() + '_cc_type'}, value: creditCardType"> </div> </div> <div class="field number required"> @@ -25,9 +41,15 @@ <span><!-- ko text: $t('Credit Card Number')--><!-- /ko --></span> </label> <div class="control"> - <input type="number" name="payment[cc_number]" class="input-text" value="" - data-bind="attr: {id: getCode() + '_cc_number', title: $t('Credit Card Number'), 'data-container': getCode() + '-cc-number', 'data-validate': JSON.stringify({'required-number':true, 'validate-cc-number':'#' + getCode() + '_cc_type', 'validate-cc-type':'#' + getCode() + '_cc_type'})}, - enable: isActive($parents), value: creditCardNumber"/> + <input type="text" name="payment[cc_number]" class="input-text" value="" + data-bind="attr: { + id: getCode() + '_cc_number', + title: $t('Credit Card Number'), + 'data-container': getCode() + '-cc-number', + 'data-validate': JSON.stringify({'required-number':true, 'validate-card-number':'#' + getCode() + '_cc_type', 'validate-cc-type':'#' + getCode() + '_cc_type'})}, + enable: isActive($parents), + value: creditCardNumber, + valueUpdate: 'keyup' "/> </div> </div> <div class="field date required" data-bind="attr: {id: getCode() + '_cc_type_exp_div'}"> @@ -38,17 +60,29 @@ <div class="fields group group-2"> <div class="field no-label month"> <div class="control"> - <select name="payment[cc_exp_month]" class="select month" - data-bind="attr: {id: getCode() + '_expiration', 'data-container': getCode() + '-cc-month', 'data-validate': JSON.stringify({required:true, 'validate-cc-exp':'#' + getCode() + '_expiration_yr'})}, - enable: isActive($parents), options: getCcMonthsValues(), optionsValue: 'value', optionsText: 'month', optionsCaption: $t('Month'), value: creditCardExpMonth"> + <select name="payment[cc_exp_month]" + class="select select-month" + data-bind="attr: {id: getCode() + '_expiration', 'data-container': getCode() + '-cc-month', 'data-validate': JSON.stringify({required:true, 'validate-cc-exp':'#' + getCode() + '_expiration_yr'})}, + enable: isActive($parents), + options: getCcMonthsValues(), + optionsValue: 'value', + optionsText: 'month', + optionsCaption: $t('Month'), + value: creditCardExpMonth"> </select> </div> </div> <div class="field no-label year"> <div class="control"> - <select name="payment[cc_exp_year]" class="select year" - data-bind="attr: {id: getCode() + '_expiration_yr', 'data-container': getCode() + '-cc-year', 'data-validate': JSON.stringify({required:true})}, - enable: isActive($parents), options: getCcYearsValues(), optionsValue: 'value', optionsText: 'year', optionsCaption: $t('Year'), value: creditCardExpYear"> + <select name="payment[cc_exp_year]" + class="select select-year" + data-bind="attr: {id: getCode() + '_expiration_yr', 'data-container': getCode() + '-cc-year', 'data-validate': JSON.stringify({required:true})}, + enable: isActive($parents), + options: getCcYearsValues(), + optionsValue: 'value', + optionsText: 'year', + optionsCaption: $t('Year'), + value: creditCardExpYear"> </select> </div> </div> @@ -60,11 +94,16 @@ <label data-bind="attr: {for: getCode() + '_cc_cid'}" class="label"> <span><!-- ko text: $t('Card Verification Number')--><!-- /ko --></span> </label> - <div class="control"> - <input type="number" class="input-text cvv" name="payment[cc_cid]" value="" - data-bind="attr: {id: getCode() + '_cc_cid', title: $t('Card Verification Number'), 'data-container': getCode() + '-cc-cvv', 'data-validate': JSON.stringify({'required-number':true, 'validate-cc-cvn':'#' + getCode() + '_cc_type'})}, enable: isActive($parents), value: creditCardVerificationNumber"/> - <div class="note"> - <a href="#" class="action cvv" data-bind="attr: {title: $t('What is this?')}, mageInit:{'tooltip': {'content': getCvvImageHtml()}}"><span><!-- ko text: $t('What is this?')--><!-- /ko --></span></a> + <div class="control _with-tooltip"> + <input type="text" class="input-text cvv" name="payment[cc_cid]" value="" + data-bind="attr: {id: getCode() + '_cc_cid', title: $t('Card Verification Number'), 'data-container': getCode() + '-cc-cvv', 'data-validate': JSON.stringify({'required-number':true, 'validate-card-cvv':'#' + getCode() + '_cc_type'})}, + enable: isActive($parents), + value: creditCardVerificationNumber"/> + <div class="field-tooltip toggle"> + <span class="field-tooltip-action action-cvv" data-bind="attr: {title: $t('What is this?')}"> + <span><!-- ko text: $t('What is this?')--><!-- /ko --></span> + </span> + <div class="field-tooltip-content" data-bind="html: getCvvImageHtml()"></div> </div> </div> </div> @@ -72,33 +111,55 @@ <!-- ko if: (hasSsCardType())--> <div class="field switch solo required" data-bind="attr: {id: getCode() + '_cc_type_ss_div'}"> <div class="nested"> - <div class="field switch solo required"> - <label data-bind="attr: {for: getCode() + '_cc_issue'}" class="label"><span><!-- ko text: $t('Switch/Solo/Maestro Only')--><!-- /ko --></span></label> + <div class="field switch-solo required"> + <label data-bind="attr: {for: getCode() + '_cc_issue'}" class="label"> + <span><!-- ko text: $t('Switch/Solo/Maestro Only')--><!-- /ko --></span> + </label> </div> <div class="field number required"> - <label data-bind="attr: {for: getCode() + '_cc_issue'}" class="label"><span><!-- ko text: $t('Issue Number')--><!-- /ko --></span></label> + <label data-bind="attr: {for: getCode() + '_cc_issue'}" class="label"> + <span><!-- ko text: $t('Issue Number')--><!-- /ko --></span> + </label> <div class="control"> - <input type="text" name="payment[cc_ss_issue]" value="" class="input-text cvv" data-bind="attr: {id: getCode() + '_cc_issue', title: $t('Issue Number'), 'data-container': getCode() + '-cc-issue', 'data-validate': JSON.stringify({'validate-cc-ukss':true})}, enable: isActive($parents)"/> + <input type="text" name="payment[cc_ss_issue]" + value="" + class="input-text cvv" + data-bind="attr: {id: getCode() + '_cc_issue', title: $t('Issue Number'), 'data-container': getCode() + '-cc-issue', 'data-validate': JSON.stringify({'validate-cc-ukss':true})}, enable: isActive($parents)"/> </div> </div> <div class="field date required"> - <label data-bind="attr: {for: getCode() + '_start_month'}" class="label"><span><!-- ko text: $t('Start Date')--><!-- /ko --></span></label> + <label data-bind="attr: {for: getCode() + '_start_month'}" class="label"> + <span><!-- ko text: $t('Start Date')--><!-- /ko --></span> + </label> <div class="control"> <div class="fields group group-2"> - <div class="field no-label"> + <div class="field no-label month"> <div class="control"> - <select name="payment[cc_ss_start_month]" class="select month" + <select name="payment[cc_ss_start_month]" + class="select select-month" data-bind="attr: {id: getCode() + '_start_month', 'data-container': getCode() + '-cc-start-month', 'data-validate': JSON.stringify({'validate-cc-ukss':true})}, - enable: isActive($parents), options: getCcMonthsValues(), optionsValue: 'value', optionsText: 'month', optionsCaption: $t('Month'), value: creditCardSsStartMonth"> + enable: isActive($parents), + options: getCcMonthsValues(), + optionsValue: 'value', + optionsText: 'month', + optionsCaption: $t('Month'), + value: creditCardSsStartMonth"> </select> </div> </div> - <div class="field no-label"> + <div class="field no-label year"> <div class="control"> - <select name="payment[cc_ss_start_year]" class="select year" - data-bind="attr: {id: getCode() + '_start_year', 'data-container': getCode() + '-cc-start-year', 'data-validate': JSON.stringify({'validate-cc-ukss':true})}, - enable: isActive($parents), options: getSsStartYearsValues(), optionsValue: 'value', optionsText: 'year', optionsCaption: $t('Year'), value: creditCardSsStartYear"> + <select name="payment[cc_ss_start_year]" + class="select select-year" + data-bind="attr: {id: getCode() + '_start_year', 'data-container': getCode() + '-cc-start-year', + 'data-validate': JSON.stringify({'validate-cc-ukss':true})}, + enable: isActive($parents), + options: getSsStartYearsValues(), + optionsValue: 'value', + optionsText: 'year', + optionsCaption: $t('Year'), + value: creditCardSsStartYear"> </select> </div> </div> diff --git a/app/code/Magento/Payment/view/frontend/web/template/payment/free.html b/app/code/Magento/Payment/view/frontend/web/template/payment/free.html new file mode 100644 index 0000000000000000000000000000000000000000..fb33eafd3cfbb59e8fffe9983692fe3d2fad1050 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/template/payment/free.html @@ -0,0 +1,36 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}, visible: isAvailable()"> + <div class="payment-method-title field choice"> + <input type="radio" + name="payment[method]" + class="radio" + data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/> + <label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label> + </div> + <div class="payment-method-content"> + <div class="payment-method-billing-address"> + <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <div class="checkout-agreements-block"> + <!-- ko foreach: $parent.getRegion('before-place-order') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> + </div> + <div class="actions-toolbar"> + <div class="primary"> + <button class="action primary checkout" + type="submit" + data-bind="click: placeOrder, attr: {title: $t('Place Order')}"> + <span data-bind="text: $t('Place Order')"></span> + </button> + </div> + </div> + </div> +</div> diff --git a/app/code/Magento/Payment/view/frontend/web/template/review/actions/iframe.html b/app/code/Magento/Payment/view/frontend/web/template/payment/iframe.html similarity index 91% rename from app/code/Magento/Payment/view/frontend/web/template/review/actions/iframe.html rename to app/code/Magento/Payment/view/frontend/web/template/payment/iframe.html index df5212f51e03f9a2b54332ca117c38d7abb0d5ba..2fec488a491cb1787d622de53a3c4764c404c4c4 100644 --- a/app/code/Magento/Payment/view/frontend/web/template/review/actions/iframe.html +++ b/app/code/Magento/Payment/view/frontend/web/template/payment/iframe.html @@ -21,6 +21,11 @@ <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> </form> +<div class="checkout-agreements-block"> + <!-- ko foreach: $parent.getRegion('before-place-order') --> + <!-- ko template: getTemplate() --><!-- /ko --> + <!--/ko--> +</div> <div class="actions-toolbar" id="review-buttons-container"> <div class="primary"> <button data-role="review-save" type="submit" diff --git a/app/code/Magento/Payment/view/frontend/web/transparent.js b/app/code/Magento/Payment/view/frontend/web/transparent.js index 6394cf38fee739a4667b1845efc4e11f4582b913..2060ca7c8ea5e5a344329c0e48ad935859f77f8a 100644 --- a/app/code/Magento/Payment/view/frontend/web/transparent.js +++ b/app/code/Magento/Payment/view/frontend/web/transparent.js @@ -6,12 +6,14 @@ define([ "jquery", "mage/template", - "jquery/ui" + "jquery/ui", + "Magento_Payment/js/model/credit-card-validation/validator" ], function($, mageTemplate){ - "use strict"; + 'use strict'; $.widget('mage.transparent', { options: { + context: null, placeOrderSelector: '[data-role="review-save"]', paymentFormSelector: '#co-payment-form', updateSelectorPrefix: '#checkout-', @@ -34,9 +36,24 @@ define([ _create: function() { this.hiddenFormTmpl = mageTemplate(this.options.hiddenFormTmpl); - $(this.options.placeOrderSelector) - .off('click') - .on('click', $.proxy(this._placeOrderHandler, this)); + + if (this.options.context) { + this.options.context.setPlaceOrderHandler($.proxy(this._orderSave, this)); + this.options.context.setValidateHandler($.proxy(this._validateHandler, this)); + } else { + $(this.options.placeOrderSelector) + .off('click') + .on('click', $.proxy(this._placeOrderHandler, this)); + } + }, + + /** + * handler for credit card validation + * @return {Boolean} + * @private + */ + _validateHandler: function() { + return (this.element.validation && this.element.validation('isValid')); }, /** @@ -45,7 +62,7 @@ define([ * @private */ _placeOrderHandler: function() { - if (this.element.validation && this.element.validation('isValid')) { + if (this._validateHandler()) { this._orderSave(); } return false; @@ -65,7 +82,7 @@ define([ '[data-container="' + this.options.gateway + '-cc-type"]' ).val(); - $.ajax({ + return $.ajax({ url: this.options.orderSaveUrl, type: 'post', context: this, @@ -110,7 +127,6 @@ define([ inputs: data } }); - $(tmpl).appendTo($(iframeSelector)).submit(); }, diff --git a/app/code/Magento/Persistent/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Persistent/view/frontend/layout/checkout_onepage_original.xml similarity index 97% rename from app/code/Magento/Persistent/view/frontend/layout/checkout_onepage_index.xml rename to app/code/Magento/Persistent/view/frontend/layout/checkout_onepage_original.xml index 80989653fc335a36a6ebf2298af1ebab84a33a53..6d8cd9506b3907770cbb9e49e44996503a4337bd 100644 --- a/app/code/Magento/Persistent/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/Persistent/view/frontend/layout/checkout_onepage_original.xml @@ -5,6 +5,7 @@ * See COPYING.txt for license details. */ --> +<!-- TODO remove this file as soon as enhanced checkout is implemented --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="checkout.root"> diff --git a/app/code/Magento/Quote/Api/AddressDetailsManagementInterface.php b/app/code/Magento/Quote/Api/AddressDetailsManagementInterface.php deleted file mode 100644 index a721e539ddf505abedd92f68433c26e917833a75..0000000000000000000000000000000000000000 --- a/app/code/Magento/Quote/Api/AddressDetailsManagementInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Api; - -interface AddressDetailsManagementInterface -{ - /** - * Save billing and shipping addresses - * - * @param int $cartId - * @param \Magento\Quote\Api\Data\AddressInterface $billingAddress - * @param \Magento\Quote\Api\Data\AddressInterface $shippingAddress - * @param \Magento\Quote\Api\Data\AddressAdditionalDataInterface|null $additionalData - * @param string|null $checkoutMethod - * @return \Magento\Quote\Api\Data\AddressDetailsInterface - */ - public function saveAddresses( - $cartId, - \Magento\Quote\Api\Data\AddressInterface $billingAddress, - \Magento\Quote\Api\Data\AddressInterface $shippingAddress = null, - \Magento\Quote\Api\Data\AddressAdditionalDataInterface $additionalData = null, - $checkoutMethod = null - ); -} diff --git a/app/code/Magento/Quote/Api/Data/AddressDetailsInterface.php b/app/code/Magento/Quote/Api/Data/AddressDetailsInterface.php deleted file mode 100644 index 843d5faa1e38723531baed4c6f1ad6c564f6b674..0000000000000000000000000000000000000000 --- a/app/code/Magento/Quote/Api/Data/AddressDetailsInterface.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Api\Data; - -interface AddressDetailsInterface extends \Magento\Framework\Api\ExtensibleDataInterface -{ - /**#@+ - * Constants defined for keys of array, makes typos less likely - */ - const SHIPPING_METHODS = 'shipping_methods'; - - const PAYMENT_METHODS = 'payment_methods'; - - const FORMATTED_BILLING_ADDRESS = 'formatted_billing_address'; - - const FORMATTED_SHIPPING_ADDRESS = 'formatted_shipping_address'; - - const TOTALS = 'totals'; - - /**#@-*/ - - /** - * @return \Magento\Quote\Api\Data\ShippingMethodInterface[] - */ - public function getShippingMethods(); - - /** - * @return \Magento\Quote\Api\Data\PaymentMethodInterface[] - */ - public function getPaymentMethods(); - - /** - * @param \Magento\Quote\Api\Data\ShippingMethodInterface[] $shippingMethods - * @return $this - */ - public function setShippingMethods($shippingMethods); - - /** - * @param \Magento\Quote\Api\Data\PaymentMethodInterface[] $paymentMethods - * @return $this - */ - public function setPaymentMethods($paymentMethods); - - /** - * @return string|null - */ - public function getFormattedShippingAddress(); - - /** - * @return string - */ - public function getFormattedBillingAddress(); - - /** - * @param string $formattedBillingAddress - * @return $this - */ - public function setFormattedBillingAddress($formattedBillingAddress); - - /** - * @param string $formattedShippingAddress - * @return $this - */ - public function setFormattedShippingAddress($formattedShippingAddress); - - - /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Quote\Api\Data\AddressDetailsExtensionInterface|null - */ - public function getExtensionAttributes(); - - /** - * Set an extension attributes object. - * - * @param \Magento\Quote\Api\Data\AddressDetailsExtensionInterface $extensionAttributes - * @return $this - */ - public function setExtensionAttributes( - \Magento\Quote\Api\Data\AddressDetailsExtensionInterface $extensionAttributes - ); - - /** - * @return \Magento\Quote\Api\Data\TotalsInterface - */ - public function getTotals(); - - /** - * @param \Magento\Quote\Api\Data\TotalsInterface $totals - * @return $this - */ - public function setTotals($totals); -} diff --git a/app/code/Magento/Quote/Api/Data/TotalSegmentInterface.php b/app/code/Magento/Quote/Api/Data/TotalSegmentInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..6ab64d64cf93fe303ff96b15eccceeef0a898045 --- /dev/null +++ b/app/code/Magento/Quote/Api/Data/TotalSegmentInterface.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Api\Data; + +/** + * Interface TotalsInterface + * @api + */ +interface TotalSegmentInterface extends \Magento\Framework\Api\ExtensibleDataInterface +{ + /**#@+ + * Constants defined for keys of array, makes typos less likely + */ + const CODE = 'code'; + const TITLE = 'title'; + const VALUE = 'value'; + const AREA = 'area'; + /**#@-*/ + + /** + * Total code + * + * @return string + */ + public function getCode(); + + /** + * Set total code + * + * @param string $code + * @return $this + */ + public function setCode($code); + + /** + * Get total title + * + * @return string|null + */ + public function getTitle(); + + /** + * Set total title + * + * @param string|null $title + * @return $this + */ + public function setTitle($title = null); + + /** + * Get total value + * + * @return float + */ + public function getValue(); + + /** + * Set total value + * + * @param float $value + * @return $this + */ + public function setValue($value); + + /** + * Get display area code. + * + * @return string|null + */ + public function getArea(); + + /** + * Set display area code + * + * @param string|null $area + * @return $this + */ + public function setArea($area = null); + + /** + * Retrieve existing extension attributes object or create a new one. + * + * @return \Magento\Quote\Api\Data\TotalSegmentExtensionInterface|null + */ + public function getExtensionAttributes(); + + /** + * Set an extension attributes object. + * + * @param \Magento\Quote\Api\Data\TotalSegmentExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\Quote\Api\Data\TotalSegmentExtensionInterface $extensionAttributes + ); +} diff --git a/app/code/Magento/Quote/Api/Data/TotalsInterface.php b/app/code/Magento/Quote/Api/Data/TotalsInterface.php index 5e8d5349ba1c13ee7c06603ba275131f570649fb..d11e5260c459ac3c706f5f347c91f236384785d9 100644 --- a/app/code/Magento/Quote/Api/Data/TotalsInterface.php +++ b/app/code/Magento/Quote/Api/Data/TotalsInterface.php @@ -42,6 +42,8 @@ interface TotalsInterface extends \Magento\Framework\Api\ExtensibleDataInterface const KEY_BASE_TAX_AMOUNT = 'base_tax_amount'; + const KEY_WEEE_TAX_APPLIED_AMOUNT = 'weee_tax_applied_amount'; + const KEY_SHIPPING_TAX_AMOUNT = 'shipping_tax_amount'; const KEY_BASE_SHIPPING_TAX_AMOUNT = 'base_shipping_tax_amount'; @@ -58,8 +60,14 @@ interface TotalsInterface extends \Magento\Framework\Api\ExtensibleDataInterface const KEY_QUOTE_CURRENCY_CODE = 'quote_currency_code'; + const KEY_COUPON_CODE = 'coupon_code'; + const KEY_ITEMS = 'items'; + const KEY_TOTAL_SEGMENTS = 'total_segments'; + + const KEY_ITEMS_QTY = 'items_qty'; + /**#@-*/ /** @@ -272,6 +280,21 @@ interface TotalsInterface extends \Magento\Framework\Api\ExtensibleDataInterface */ public function setBaseTaxAmount($baseTaxAmount); + /** + * Returns the total weee tax applied amount in quote currency. + * + * @return float Item weee tax applied amount in quote currency. + */ + public function getWeeeTaxAppliedAmount(); + + /** + * Sets the total weee tax applied amount in quote currency. + * + * @param float $weeeTaxAppliedAmount + * @return $this + */ + public function setWeeeTaxAppliedAmount($weeeTaxAppliedAmount); + /** * Get shipping tax amount in quote currency * @@ -392,6 +415,36 @@ interface TotalsInterface extends \Magento\Framework\Api\ExtensibleDataInterface */ public function setQuoteCurrencyCode($quoteCurrencyCode); + /** + * Get applied coupon code + * + * @return string|null + */ + public function getCouponCode(); + + /** + * Set applied coupon code + * + * @param string $couponCode + * @return $this + */ + public function setCouponCode($couponCode); + + /** + * Get items qty + * + * @return int||null + */ + public function getItemsQty(); + + /** + * Set items qty + * + * @param int $itemsQty + * @return $this + */ + public function setItemsQty($itemsQty = null); + /** * Get totals by items * @@ -407,6 +460,21 @@ interface TotalsInterface extends \Magento\Framework\Api\ExtensibleDataInterface */ public function setItems(array $items = null); + /** + * Get dynamically calculated totals + * + * @return \Magento\Quote\Api\Data\TotalSegmentInterface[] + */ + public function getTotalSegments(); + + /** + * Set dynamically calculated totals + * + * @param \Magento\Quote\Api\Data\TotalSegmentInterface[] $totals + * @return $this + */ + public function setTotalSegments($totals = []); + /** * Retrieve existing extension attributes object or create a new one. * diff --git a/app/code/Magento/Quote/Api/GuestAddressDetailsManagementInterface.php b/app/code/Magento/Quote/Api/GuestAddressDetailsManagementInterface.php deleted file mode 100644 index a4eea1464145c613a5c06acdfb164bd9de819527..0000000000000000000000000000000000000000 --- a/app/code/Magento/Quote/Api/GuestAddressDetailsManagementInterface.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Api; - -interface GuestAddressDetailsManagementInterface -{ - /** - * Save billing and shipping addresses for guest. - * - * @param string $cartId - * @param \Magento\Quote\Api\Data\AddressInterface $billingAddress - * @param \Magento\Quote\Api\Data\AddressInterface|null $shippingAddress - * @param \Magento\Quote\Api\Data\AddressAdditionalDataInterface|null $additionalData - * @return \Magento\Quote\Api\Data\AddressDetailsInterface - */ - public function saveAddresses( - $cartId, - \Magento\Quote\Api\Data\AddressInterface $billingAddress, - \Magento\Quote\Api\Data\AddressInterface $shippingAddress = null, - \Magento\Quote\Api\Data\AddressAdditionalDataInterface $additionalData = null - ); -} diff --git a/app/code/Magento/Quote/Api/GuestShippingMethodManagementInterface.php b/app/code/Magento/Quote/Api/GuestShippingMethodManagementInterface.php index 10bd639cf93c5e30ddb57fde13595a67f2a5f945..29c4a07ca8d46c9d85d9f1a901c9303a86eaec3e 100644 --- a/app/code/Magento/Quote/Api/GuestShippingMethodManagementInterface.php +++ b/app/code/Magento/Quote/Api/GuestShippingMethodManagementInterface.php @@ -45,4 +45,13 @@ interface GuestShippingMethodManagementInterface * @throws \Magento\Framework\Exception\StateException The shipping address is not set. */ public function getList($cartId); + + /** + * Estimate shipping + * + * @param string $cartId The shopping cart ID. + * @param \Magento\Quote\Api\Data\EstimateAddressInterface $address The estimate address + * @return \Magento\Quote\Api\Data\ShippingMethodInterface[] An array of shipping methods. + */ + public function estimateByAddress($cartId, \Magento\Quote\Api\Data\EstimateAddressInterface $address); } diff --git a/app/code/Magento/Quote/Model/AddressDetails.php b/app/code/Magento/Quote/Model/AddressDetails.php deleted file mode 100644 index ba3e3bf697708ee8c0d9fc6c0b5c161c6adb3ab3..0000000000000000000000000000000000000000 --- a/app/code/Magento/Quote/Model/AddressDetails.php +++ /dev/null @@ -1,117 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Model; - -/** - * @codeCoverageIgnoreStart - */ -class AddressDetails extends \Magento\Framework\Model\AbstractExtensibleModel implements - \Magento\Quote\Api\Data\AddressDetailsInterface -{ - //@codeCoverageIgnoreStart - /** - * @{inheritdoc} - */ - public function getShippingMethods() - { - return $this->getData(self::SHIPPING_METHODS); - } - - /** - * @{inheritdoc} - */ - public function setShippingMethods($shippingMethods) - { - return $this->setData(self::SHIPPING_METHODS, $shippingMethods); - } - - /** - * @{inheritdoc} - */ - public function getPaymentMethods() - { - return $this->getData(self::PAYMENT_METHODS); - } - - /** - * @{inheritdoc} - */ - public function setPaymentMethods($paymentMethods) - { - return $this->setData(self::PAYMENT_METHODS, $paymentMethods); - } - - /** - * @{inheritdoc} - */ - public function getFormattedShippingAddress() - { - return $this->getData(self::FORMATTED_SHIPPING_ADDRESS); - } - - /** - * @{inheritdoc} - */ - public function getFormattedBillingAddress() - { - return $this->getData(self::FORMATTED_BILLING_ADDRESS); - } - - /** - * @{inheritdoc} - */ - public function setFormattedBillingAddress($formattedBillingAddress) - { - return $this->setData(self::FORMATTED_BILLING_ADDRESS, $formattedBillingAddress); - } - - /** - * @{inheritdoc} - */ - public function setFormattedShippingAddress($formattedShippingAddress) - { - return $this->setData(self::FORMATTED_SHIPPING_ADDRESS, $formattedShippingAddress); - } - - /** - * @{inheritdoc} - */ - public function getTotals() - { - return $this->getData(self::TOTALS); - } - - /** - * @{inheritdoc} - */ - public function setTotals($totals) - { - return $this->setData(self::TOTALS, $totals); - } - //@codeCoverageIgnoreEnd - - /** - * {@inheritdoc} - * - * @return \Magento\Quote\Api\Data\AddressDetailsExtensionInterface|null - */ - public function getExtensionAttributes() - { - return $this->_getExtensionAttributes(); - } - - /** - * {@inheritdoc} - * - * @param \Magento\Quote\Api\Data\AddressDetailsExtensionInterface $extensionAttributes - * @return $this - */ - public function setExtensionAttributes( - \Magento\Quote\Api\Data\AddressDetailsExtensionInterface $extensionAttributes - ) { - return $this->_setExtensionAttributes($extensionAttributes); - } -} diff --git a/app/code/Magento/Quote/Model/AddressDetailsManagement.php b/app/code/Magento/Quote/Model/AddressDetailsManagement.php deleted file mode 100644 index 84c6492510a6d02f6b668612047585920dc1bb75..0000000000000000000000000000000000000000 --- a/app/code/Magento/Quote/Model/AddressDetailsManagement.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Model; - -use Magento\Quote\Api\CartTotalRepositoryInterface; -use Magento\Quote\Model\AddressAdditionalDataProcessor; - -class AddressDetailsManagement implements \Magento\Quote\Api\AddressDetailsManagementInterface -{ - /** - * @var \Magento\Quote\Api\BillingAddressManagementInterface - */ - protected $billingAddressManagement; - - /** - * @var \Magento\Quote\Api\ShippingAddressManagementInterface - */ - protected $shippingAddressManagement; - - /** - * @var \Magento\Quote\Api\PaymentMethodManagementInterface - */ - protected $paymentMethodManagement; - - /** - * @var \Magento\Quote\Api\ShippingMethodManagementInterface - */ - protected $shippingMethodManagement; - - /** - * @var AddressDetailsFactory - */ - protected $addressDetailsFactory; - - /** - * @var AddressAdditionalDataProcessor - */ - protected $dataProcessor; - - /** - * @var QuoteRepository - */ - protected $quoteRepository; - - /** - * @var CartTotalRepositoryInterface - */ - protected $cartTotalsRepository; - - /** - * @param \Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement - * @param \Magento\Quote\Api\ShippingAddressManagementInterface $shippingAddressManagement - * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement - * @param \Magento\Quote\Api\ShippingMethodManagementInterface $shippingMethodManagement - * @param AddressDetailsFactory $addressDetailsFactory - * @param AddressAdditionalDataProcessor $dataProcessor - * @param QuoteRepository $quoteRepository - * @param CartTotalRepositoryInterface $cartTotalsRepository - */ - public function __construct( - \Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement, - \Magento\Quote\Api\ShippingAddressManagementInterface $shippingAddressManagement, - \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement, - \Magento\Quote\Api\ShippingMethodManagementInterface $shippingMethodManagement, - \Magento\Quote\Model\AddressDetailsFactory $addressDetailsFactory, - AddressAdditionalDataProcessor $dataProcessor, - QuoteRepository $quoteRepository, - CartTotalRepositoryInterface $cartTotalsRepository - ) { - $this->billingAddressManagement = $billingAddressManagement; - $this->shippingAddressManagement = $shippingAddressManagement; - $this->paymentMethodManagement = $paymentMethodManagement; - $this->shippingMethodManagement = $shippingMethodManagement; - $this->addressDetailsFactory = $addressDetailsFactory; - $this->dataProcessor = $dataProcessor; - $this->quoteRepository = $quoteRepository; - $this->cartTotalsRepository = $cartTotalsRepository; - } - - /** - * @{inheritdoc} - */ - public function saveAddresses( - $cartId, - \Magento\Quote\Api\Data\AddressInterface $billingAddress, - \Magento\Quote\Api\Data\AddressInterface $shippingAddress = null, - \Magento\Quote\Api\Data\AddressAdditionalDataInterface $additionalData = null, - $checkoutMethod = null - ) { - $this->billingAddressManagement->assign($cartId, $billingAddress); - - /** @var \Magento\Quote\Api\Data\AddressDetailsInterface $addressDetails */ - $addressDetails = $this->addressDetailsFactory->create(); - if ($shippingAddress) { - $this->shippingAddressManagement->assign($cartId, $shippingAddress); - $addressDetails->setFormattedShippingAddress( - $this->shippingAddressManagement->get($cartId)->format('html') - ); - $addressDetails->setShippingMethods($this->shippingMethodManagement->getList($cartId)); - } - $addressDetails->setPaymentMethods($this->paymentMethodManagement->getList($cartId)); - if ($additionalData !== null) { - $this->dataProcessor->process($additionalData); - } - if ($checkoutMethod != null) { - $this->quoteRepository->save( - $this->quoteRepository->getActive($cartId) - ->setCheckoutMethod($checkoutMethod) - ); - } - - $addressDetails->setFormattedBillingAddress( - $this->billingAddressManagement->get($cartId)->format('html') - ); - - $addressDetails->setTotals($this->cartTotalsRepository->get($cartId)); - return $addressDetails; - } -} diff --git a/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php b/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php index 78bdf6da18569990d10fe5ac97330780b6bd14ed..88906928f9a72034da279a9d51c51e7f6944d1a3 100644 --- a/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php +++ b/app/code/Magento/Quote/Model/Cart/CartTotalRepository.php @@ -11,6 +11,7 @@ use Magento\Quote\Api\CartTotalRepositoryInterface; use Magento\Catalog\Helper\Product\ConfigurationPool; use Magento\Framework\Api\DataObjectHelper; use Magento\Quote\Model\Cart\Totals\ItemConverter; +use Magento\Quote\Api\CouponManagementInterface; /** * Cart totals data object. @@ -39,24 +40,40 @@ class CartTotalRepository implements CartTotalRepositoryInterface /** * @var ConfigurationPool */ - private $converter; + private $itemConverter; + + /** + * @var CouponManagementInterface + */ + protected $couponService; + + /** + * @var TotalsConverter + */ + protected $totalsConverter; /** * @param Api\Data\TotalsInterfaceFactory $totalsFactory * @param QuoteRepository $quoteRepository * @param DataObjectHelper $dataObjectHelper + * @param CouponManagementInterface $couponService + * @param TotalsConverter $totalsConverter * @param ItemConverter $converter */ public function __construct( Api\Data\TotalsInterfaceFactory $totalsFactory, QuoteRepository $quoteRepository, DataObjectHelper $dataObjectHelper, + CouponManagementInterface $couponService, + TotalsConverter $totalsConverter, ItemConverter $converter ) { $this->totalsFactory = $totalsFactory; $this->quoteRepository = $quoteRepository; $this->dataObjectHelper = $dataObjectHelper; - $this->converter = $converter; + $this->couponService = $couponService; + $this->totalsConverter = $totalsConverter; + $this->itemConverter = $converter; } /** @@ -82,11 +99,19 @@ class CartTotalRepository implements CartTotalRepositoryInterface $totals = $this->totalsFactory->create(); $this->dataObjectHelper->populateWithArray($totals, $totalsData, '\Magento\Quote\Api\Data\TotalsInterface'); $items = []; + $weeeTaxAppliedAmount = 0; foreach ($quote->getAllVisibleItems() as $index => $item) { - $items[$index] = $this->converter->modelToDataObject($item); + $items[$index] = $this->itemConverter->modelToDataObject($item); + $weeeTaxAppliedAmount += $item->getWeeeTaxAppliedAmount(); } + $totals->setCouponCode($this->couponService->get($cartId)); + $calculatedTotals = $this->totalsConverter->process($quote->getTotals()); + $amount = $totals->getGrandTotal() - $totals->getTaxAmount(); + $amount = $amount > 0 ? $amount : 0; + $totals->setGrandTotal($amount); + $totals->setTotalSegments($calculatedTotals); $totals->setItems($items); - + $totals->setWeeeTaxAppliedAmount($weeeTaxAppliedAmount); return $totals; } } diff --git a/app/code/Magento/Quote/Model/Cart/TotalSegment.php b/app/code/Magento/Quote/Model/Cart/TotalSegment.php new file mode 100644 index 0000000000000000000000000000000000000000..203c8996f5fb2e55b92580cb86a41f93c0dba7e5 --- /dev/null +++ b/app/code/Magento/Quote/Model/Cart/TotalSegment.php @@ -0,0 +1,98 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Model\Cart; + +use Magento\Quote\Api\Data\TotalSegmentInterface; +use Magento\Framework\Model\AbstractExtensibleModel; + +/** + * Extensible Cart Totals + * + * @codeCoverageIgnore + */ +class TotalSegment extends AbstractExtensibleModel implements TotalSegmentInterface +{ + /** + * {@inheritdoc} + */ + public function getCode() + { + return $this->getData(self::CODE); + } + + /** + * {@inheritdoc} + */ + public function setCode($code) + { + return $this->setData(self::CODE, $code); + } + + /** + * {@inheritdoc} + */ + public function getValue() + { + return $this->getData(self::VALUE); + } + + /** + * {@inheritdoc} + */ + public function setValue($value) + { + return $this->setData(self::VALUE, $value); + } + + /** + * {@inheritdoc} + */ + public function getTitle() + { + return $this->getData(self::TITLE); + } + + /** + * {@inheritdoc} + */ + public function setTitle($title = null) + { + return $this->setData(self::TITLE, $title); + } + + /** + * {@inheritdoc} + */ + public function getArea() + { + return $this->getData(self::AREA); + } + + /** + * {@inheritdoc} + */ + public function setArea($area = null) + { + return $this->setData(self::AREA, $area); + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes( + \Magento\Quote\Api\Data\TotalSegmentExtensionInterface $extensionAttributes + ) { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Quote/Model/Cart/Totals.php b/app/code/Magento/Quote/Model/Cart/Totals.php index 4612824f9cebb05dc6c4dedbb00bd8827e4019a3..742f27d4df5497d6adbafdf6e1dd7fd6ddb791c0 100644 --- a/app/code/Magento/Quote/Model/Cart/Totals.php +++ b/app/code/Magento/Quote/Model/Cart/Totals.php @@ -310,6 +310,27 @@ class Totals extends AbstractExtensibleModel implements TotalsInterface return $this->setData(self::KEY_BASE_TAX_AMOUNT, $baseTaxAmount); } + /** + * Returns the total weee tax applied amount in quote currency. + * + * @return float Item weee tax applied amount in quote currency. + */ + public function getWeeeTaxAppliedAmount() + { + return $this->getData(self::KEY_WEEE_TAX_APPLIED_AMOUNT); + } + + /** + * Sets the total weee tax applied amount in quote currency. + * + * @param float $weeeTaxAppliedAmount + * @return $this + */ + public function setWeeeTaxAppliedAmount($weeeTaxAppliedAmount) + { + return $this->setData(self::KEY_WEEE_TAX_APPLIED_AMOUNT, $weeeTaxAppliedAmount); + } + /** * Get shipping tax amount in quote currency * @@ -478,6 +499,43 @@ class Totals extends AbstractExtensibleModel implements TotalsInterface return $this->setData(self::KEY_QUOTE_CURRENCY_CODE, $quoteCurrencyCode); } + /** + * {@inheritdoc} + */ + public function getCouponCode() + { + return $this->getData(self::KEY_COUPON_CODE); + } + + /** + * {@inheritdoc} + */ + public function setCouponCode($couponCode) + { + return $this->setData(self::KEY_COUPON_CODE, $couponCode); + } + + /** + * Get items qty + * + * @return int||null + */ + public function getItemsQty() + { + return $this->getData(self::KEY_ITEMS_QTY); + } + + /** + * Set items qty + * + * @param int $itemsQty + * @return $this + */ + public function setItemsQty($itemsQty = null) + { + return $this->setData(self::KEY_ITEMS_QTY, $itemsQty); + } + /** * Get totals by items * @@ -499,6 +557,22 @@ class Totals extends AbstractExtensibleModel implements TotalsInterface return $this->setData(self::KEY_ITEMS, $items); } + /** + * {@inheritdoc} + */ + public function getTotalSegments() + { + return $this->getData(self::KEY_TOTAL_SEGMENTS); + } + + /** + * {@inheritdoc} + */ + public function setTotalSegments($totals = []) + { + return $this->setData(self::KEY_TOTAL_SEGMENTS, $totals); + } + /** * {@inheritdoc} * diff --git a/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php b/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php index f569f8478b09d566bb3e65131436214d772a3b94..2b4792d2e44a2d884e8bf2f99b444abbc6a3ae43 100644 --- a/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php +++ b/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php @@ -86,10 +86,12 @@ class ItemConverter private function getFormattedOptionValue($item) { $optionsData = []; + + /* @var $helper \Magento\Catalog\Helper\Product\Configuration */ + $helper = $this->configurationPool->getByProductType('default'); + $options = $this->configurationPool->getByProductType($item->getProductType())->getOptions($item); foreach ($options as $index => $optionValue) { - /* @var $helper \Magento\Catalog\Helper\Product\Configuration */ - $helper = $this->configurationPool->getByProductType('default'); $params = [ 'max_length' => 55, 'cut_replacer' => ' <a href="#" class="dots tooltip toggle" onclick="return false">...</a>' diff --git a/app/code/Magento/Quote/Model/Cart/TotalsConverter.php b/app/code/Magento/Quote/Model/Cart/TotalsConverter.php new file mode 100644 index 0000000000000000000000000000000000000000..a041844c8ed5023dd4884459a0a95e222d3a882a --- /dev/null +++ b/app/code/Magento/Quote/Model/Cart/TotalsConverter.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Model\Cart; + +use Magento\Quote\Api\Data\TotalSegmentInterface; +use Magento\Quote\Api\Data\TotalSegmentInterfaceFactory; + +/** + * Cart totals data objects converter. + */ +class TotalsConverter +{ + /** + * @var TotalSegmentInterfaceFactory + */ + protected $factory; + + /** + * @param TotalSegmentInterfaceFactory $factory + */ + public function __construct( + TotalSegmentInterfaceFactory $factory + ) { + $this->factory = $factory; + } + + + /** + * @param \Magento\Quote\Model\Quote\Address\Total[] $addressTotals + * @return \Magento\Quote\Api\Data\TotalSegmentInterface[] + */ + public function process($addressTotals) + { + $data = []; + /** @var \Magento\Quote\Model\Quote\Address\Total $addressTotal */ + foreach ($addressTotals as $addressTotal) { + $pureData = [ + TotalSegmentInterface::CODE => $addressTotal->getCode(), + TotalSegmentInterface::TITLE => '', + TotalSegmentInterface::VALUE => $addressTotal->getValue(), + TotalSegmentInterface::AREA => $addressTotal->getArea(), + ]; + if (is_object($addressTotal->getTitle())) { + $pureData[TotalSegmentInterface::TITLE] = $addressTotal->getTitle()->getText(); + } + /** @var \Magento\Quote\Model\Cart\TotalSegment $total */ + $total = $this->factory->create(); + $total->setData($pureData); + $data[] = $total; + } + return $data; + } +} diff --git a/app/code/Magento/Quote/Model/GuestCart/GuestAddressDetailsManagement.php b/app/code/Magento/Quote/Model/GuestCart/GuestAddressDetailsManagement.php deleted file mode 100644 index 2671a1ccb7665ebddf0b526f923090d6440c85f4..0000000000000000000000000000000000000000 --- a/app/code/Magento/Quote/Model/GuestCart/GuestAddressDetailsManagement.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Model\GuestCart; - -use Magento\Quote\Model\QuoteIdMaskFactory; - -class GuestAddressDetailsManagement implements \Magento\Quote\Api\GuestAddressDetailsManagementInterface -{ - /** - * @var \Magento\Quote\Api\AddressDetailsManagementInterface - */ - protected $addressDetailsManagement; - - /** - * @var QuoteIdMaskFactory - */ - protected $quoteIdMaskFactory; - - /** - * @param \Magento\Quote\Api\AddressDetailsManagementInterface $addressDetailsManagement - * @param QuoteIdMaskFactory $quoteIdMaskFactory - */ - public function __construct( - \Magento\Quote\Api\AddressDetailsManagementInterface $addressDetailsManagement, - QuoteIdMaskFactory $quoteIdMaskFactory - ) { - $this->addressDetailsManagement = $addressDetailsManagement; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - } - - /** - * @{inheritdoc} - */ - public function saveAddresses( - $cartId, - \Magento\Quote\Api\Data\AddressInterface $billingAddress, - \Magento\Quote\Api\Data\AddressInterface $shippingAddress = null, - \Magento\Quote\Api\Data\AddressAdditionalDataInterface $additionalData = null - ) { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - return $this->addressDetailsManagement->saveAddresses( - $quoteIdMask->getQuoteId(), - $billingAddress, - $shippingAddress, - $additionalData - ); - } -} diff --git a/app/code/Magento/Quote/Model/GuestCart/GuestShippingMethodManagement.php b/app/code/Magento/Quote/Model/GuestCart/GuestShippingMethodManagement.php index 0687ca395de869030d97dbb780f474bf1ebc1733..6026ff8f8da0406a98dcc1beaf5212c816e81df6 100644 --- a/app/code/Magento/Quote/Model/GuestCart/GuestShippingMethodManagement.php +++ b/app/code/Magento/Quote/Model/GuestCart/GuestShippingMethodManagement.php @@ -69,4 +69,14 @@ class GuestShippingMethodManagement implements GuestShippingMethodManagementInte $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); return $this->shippingMethodManagement->set($quoteIdMask->getQuoteId(), $carrierCode, $methodCode); } + + /** + * {@inheritDoc} + */ + public function estimateByAddress($cartId, \Magento\Quote\Api\Data\EstimateAddressInterface $address) + { + /** @var $quoteIdMask QuoteIdMask */ + $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); + return $this->shippingMethodManagement->estimateByAddress($quoteIdMask->getQuoteId(), $address); + } } diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index 2dd5c4ca3add051bb7c518b939e8a1011e098a10..d55c9a70bb78a1fb496e4522c3639576dc935c62 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -801,33 +801,6 @@ class Quote extends AbstractExtensibleModel implements \Magento\Quote\Api\Data\C parent::beforeSave(); } - /** - * Save related items - * - * @return $this - */ - public function afterSave() - { - parent::afterSave(); - - if (null !== $this->_addresses) { - $this->getAddressesCollection()->save(); - } - - if (null !== $this->_items) { - $this->getItemsCollection()->save(); - } - - if (null !== $this->_payments) { - $this->getPaymentsCollection()->save(); - } - - if (null !== $this->_currentPayment) { - $this->getPayment()->save(); - } - return $this; - } - /** * Loading quote data by customer * @@ -2496,6 +2469,46 @@ class Quote extends AbstractExtensibleModel implements \Magento\Quote\Api\Data\C return parent::_afterLoad(); } + /** + * Checks if it was set + * + * @return bool + */ + public function addressCollectionWasSet() + { + return null !== $this->_addresses; + } + + /** + * Checks if it was set + * + * @return bool + */ + public function itemsCollectionWasSet() + { + return null !== $this->_items; + } + + /** + * Checks if it was set + * + * @return bool + */ + public function paymentsCollectionWasSet() + { + return null !== $this->_payments; + } + + /** + * Checks if it was set + * + * @return bool + */ + public function currentPaymentWasSet() + { + return null !== $this->_currentPayment; + } + /** * Return checkout method code * diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 2d091f08d1db37e3320f316540eaabce7d3895f9..1c525a5a80af525844fae490d2e4a6de55d9da47 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -423,23 +423,6 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements && $defaultBillingAddress == $defaultShippingAddress; } - /** - * Save child collections - * - * @return $this - */ - public function afterSave() - { - parent::afterSave(); - if (null !== $this->_items) { - $this->getItemsCollection()->save(); - } - if (null !== $this->_rates) { - $this->getShippingRatesCollection()->save(); - } - return $this; - } - /** * Declare address quote model object * @@ -538,7 +521,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements /** * Retrieve address items collection * - * @return \Magento\Eav\Model\Entity\Collection\AbstractCollection + * @return \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection */ public function getItemsCollection() { @@ -779,7 +762,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements /** * Retrieve collection of quote shipping rates * - * @return \Magento\Eav\Model\Entity\Collection\AbstractCollection + * @return \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection */ public function getShippingRatesCollection() { @@ -1114,6 +1097,26 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements $this->setId(null); } + /** + * Checks if it was set + * + * @return bool + */ + public function itemsCollectionWasSet() + { + return null !== $this->_items; + } + + /** + * Checks if it was set + * + * @return bool + */ + public function shippingRatesCollectionWasSet() + { + return null !== $this->_rates; + } + /** * Validate minimum amount * @@ -1572,7 +1575,12 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements */ public function getEmail() { - return $this->getData(self::KEY_EMAIL); + $email = $this->getData(self::KEY_EMAIL); + if (!$email) { + $email = $this->getQuote()->getCustomerEmail(); + $this->setEmail($email); + } + return $email; } /** diff --git a/app/code/Magento/Quote/Model/Quote/Address/Relation.php b/app/code/Magento/Quote/Model/Quote/Address/Relation.php new file mode 100644 index 0000000000000000000000000000000000000000..f5e499d4dcd6f90c302aa27cf696ece18b630681 --- /dev/null +++ b/app/code/Magento/Quote/Model/Quote/Address/Relation.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Model\Quote\Address; + +use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface; + +class Relation implements RelationInterface +{ + /** + * Process object relations + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return void + */ + public function processRelation(\Magento\Framework\Model\AbstractModel $object) + { + /** + * @var $object \Magento\Quote\Model\Quote\Address + */ + if ($object->itemsCollectionWasSet()) { + $object->getItemsCollection()->save(); + } + if ($object->shippingRatesCollectionWasSet()) { + $object->getShippingRatesCollection()->save(); + } + } +} diff --git a/app/code/Magento/Quote/Model/Quote/Item.php b/app/code/Magento/Quote/Model/Quote/Item.php index 56ea708036533251670e39c59ed59569732de0b2..51694e5f68864efedb456e3628e2c0d66d2d557e 100644 --- a/app/code/Magento/Quote/Model/Quote/Item.php +++ b/app/code/Magento/Quote/Model/Quote/Item.php @@ -20,7 +20,6 @@ use Magento\Framework\Api\ExtensionAttributesFactory; * @method \Magento\Quote\Model\Quote\Item setCreatedAt(string $value) * @method string getUpdatedAt() * @method \Magento\Quote\Model\Quote\Item setUpdatedAt(string $value) - * @method \Magento\Quote\Model\Quote\Item setProductId(int $value) * @method int getStoreId() * @method \Magento\Quote\Model\Quote\Item setStoreId(int $value) * @method int getParentItemId() diff --git a/app/code/Magento/Quote/Model/Quote/Relation.php b/app/code/Magento/Quote/Model/Quote/Relation.php new file mode 100644 index 0000000000000000000000000000000000000000..5e131ae6b3b015bab21603b1b316a7d00d644337 --- /dev/null +++ b/app/code/Magento/Quote/Model/Quote/Relation.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Model\Quote; + +use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface; + +class Relation implements RelationInterface +{ + /** + * Process object relations + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return void + */ + public function processRelation(\Magento\Framework\Model\AbstractModel $object) + { + /** + * @var $object \Magento\Quote\Model\Quote + */ + if ($object->addressCollectionWasSet()) { + $object->getAddressesCollection()->save(); + } + if ($object->itemsCollectionWasSet()) { + $object->getItemsCollection()->save(); + } + if ($object->paymentsCollectionWasSet()) { + $object->getPaymentsCollection()->save(); + } + if ($object->currentPaymentWasSet()) { + $object->getPayment()->save(); + } + } +} diff --git a/app/code/Magento/Quote/Model/QuoteAddressValidator.php b/app/code/Magento/Quote/Model/QuoteAddressValidator.php index e92780f4056dba9f10a7158e9abd6cdae5470a4a..13df66e5f9f2513a5b176abb3c90d2b641a8ea88 100644 --- a/app/code/Magento/Quote/Model/QuoteAddressValidator.php +++ b/app/code/Magento/Quote/Model/QuoteAddressValidator.php @@ -13,7 +13,7 @@ class QuoteAddressValidator * * @var \Magento\Customer\Api\AddressRepositoryInterface */ - protected $addressReporitory; + protected $addressRepository; /** * Customer repository. @@ -39,7 +39,7 @@ class QuoteAddressValidator \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, \Magento\Customer\Model\Session $customerSession ) { - $this->addressReporitory = $addressRepository; + $this->addressRepository = $addressRepository; $this->customerRepository = $customerRepository; $this->customerSession = $customerSession; } @@ -67,7 +67,7 @@ class QuoteAddressValidator // validate address id if ($addressData->getId()) { try { - $address = $this->addressReporitory->getById($addressData->getId()); + $address = $this->addressRepository->getById($addressData->getId()); } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { throw new \Magento\Framework\Exception\NoSuchEntityException( __('Invalid address id %1', $addressData->getId()) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index f341b5894b9fb0a5a5da68f92c6a5b04e79fe2ca..3a75073c3960f5741e0e296ca212755b0021e4a5 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -297,11 +297,6 @@ class QuoteManagement implements \Magento\Quote\Api\CartManagementInterface */ public function placeOrder($cartId, $agreements = null, PaymentInterface $paymentMethod = null) { - if (!$this->agreementsValidator->isValid($agreements)) { - throw new \Magento\Framework\Exception\CouldNotSaveException( - __('Please agree to all the terms and conditions before placing the order.') - ); - } $quote = $this->quoteRepository->getActive($cartId); if ($paymentMethod) { $paymentMethod->setChecks([ @@ -333,6 +328,7 @@ class QuoteManagement implements \Magento\Quote\Api\CartManagementInterface $this->checkoutSession->setLastSuccessQuoteId($quote->getId()); $this->checkoutSession->setLastOrderId($order->getId()); $this->checkoutSession->setLastRealOrderId($order->getIncrementId()); + $this->checkoutSession->setLastOrderStatus($order->getStatus()); $this->eventManager->dispatch('checkout_submit_all_after', ['order' => $order, 'quote' => $quote]); return $order->getId(); diff --git a/app/code/Magento/Quote/Model/Resource/Quote.php b/app/code/Magento/Quote/Model/Resource/Quote.php index c9ac55ba5414bb7a9368eb495b62bbdf952bad44..c942d9bd2f86a51a404b560f2be507413324d0e4 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote.php +++ b/app/code/Magento/Quote/Model/Resource/Quote.php @@ -8,7 +8,10 @@ namespace Magento\Quote\Model\Resource; -use Magento\Framework\Model\Resource\Db\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; +use Magento\SalesSequence\Model\Manager; /** * Quote resource model @@ -22,15 +25,19 @@ class Quote extends AbstractDb /** * @param \Magento\Framework\Model\Resource\Db\Context $context + * @param Snapshot $entitySnapshot, + * @param RelationComposite $entityRelationComposite, * @param \Magento\SalesSequence\Model\Manager $sequenceManager * @param null $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, - \Magento\SalesSequence\Model\Manager $sequenceManager, + Snapshot $entitySnapshot, + RelationComposite $entityRelationComposite, + Manager $sequenceManager, $resourcePrefix = null ) { - parent::__construct($context, $resourcePrefix); + parent::__construct($context, $entitySnapshot, $entityRelationComposite, $resourcePrefix); $this->sequenceManager = $sequenceManager; } diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address.php b/app/code/Magento/Quote/Model/Resource/Quote/Address.php index 350193fc2e13f7e5e260a063ddd1e06539f8ebb8..56d71a651e18a430a6201716464b7dd6700a1b18 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Address.php @@ -5,7 +5,7 @@ */ namespace Magento\Quote\Model\Resource\Quote; -use Magento\Framework\Model\Resource\Db\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb; /** * Quote address resource model diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php index 960d256ca93ab766ea243de3216b370a401ff6fc..521daa91741d3806d4a96575cd0d696ea7cebae1 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php @@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote\Address; * * @author Magento Core Team <core@magentocommerce.com> */ -class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection { /** * Event prefix diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php index 44365e28efd5339f851a5d9bf05d6dc06efd3a56..d156ba6804657d9bc20c62a117210bc5b7994dc0 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php @@ -5,7 +5,7 @@ */ namespace Magento\Quote\Model\Resource\Quote\Address; -use Magento\Framework\Model\Resource\Db\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb; /** * Quote address item resource model diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php index 3ef5acacbbfae979a6f83a33a1b14d08d6e3eb67..03b381a572470fac7e1ff727ae76e71f129e9bce 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php @@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote\Address\Item; * * @author Magento Core Team <core@magentocommerce.com> */ -class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection { /** * Resource initialization diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php index 20177eb97cd48d36657ee22e8099d966caeaa250..221f1b42c5a1fe927e32fae8a3dac80e61b74ac7 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php @@ -5,7 +5,7 @@ */ namespace Magento\Quote\Model\Resource\Quote\Address; -use Magento\Framework\Model\Resource\Db\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb; /** * Quote address shipping rate resource model diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php index f21945483c6873facccac4eb9efeebe611ba723c..94d13b94377aaec1409cb8aa97e191bcb78b1fdc 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php @@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote\Address\Rate; * * @author Magento Core Team <core@magentocommerce.com> */ -class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection { /** * Whether to load fixed items only @@ -24,8 +24,9 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Shipping\Model\CarrierFactoryInterface $carrierFactory - * @param \Zend_Db_Adapter_Abstract $connection + * @param \Zend_Db_Adapter_Abstract|null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource */ public function __construct( @@ -33,11 +34,20 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Shipping\Model\CarrierFactoryInterface $carrierFactory, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null ) { - parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource); + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $entitySnapshot, + $connection, + $resource + ); $this->_carrierFactory = $carrierFactory; } diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Collection.php index 426caa5d17fceb6b413de08d980edaeac59a611c..20e325fbf3678273365f9f20e185c1343cc0162d 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Collection.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Collection.php @@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote; * * @author Magento Core Team <core@magentocommerce.com> */ -class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection { /** * Resource initialization diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Item.php b/app/code/Magento/Quote/Model/Resource/Quote/Item.php index dbe8c0944870f21be9a933a361f33076e354080d..0f527977b5a8fd1228b469d844d9e34d7bb6381a 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Item.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Item.php @@ -5,7 +5,7 @@ */ namespace Magento\Quote\Model\Resource\Quote; -use Magento\Framework\Model\Resource\Db\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb; /** * Quote resource model @@ -29,7 +29,7 @@ class Item extends AbstractDb */ public function save(\Magento\Framework\Model\AbstractModel $object) { - $hasDataChanges = $object->hasDataChanges(); + $hasDataChanges = $this->isModified($object); $object->setIsOptionsSaved(false); $result = parent::save($object); diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php index 8f90d543450507681fd9e6678ce3390d37525eb1..56bbda864bc2cd501e68588e8582894708287169 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php @@ -8,7 +8,7 @@ namespace Magento\Quote\Model\Resource\Quote\Item; /** * Quote item resource collection */ -class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection { /** * Collection quote instance @@ -44,24 +44,35 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Quote\Model\Resource\Quote\Item\Option\CollectionFactory $itemOptionCollectionFactory + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot + * @param Option\CollectionFactory $itemOptionCollectionFactory * @param \Magento\Catalog\Model\Resource\Product\CollectionFactory $productCollectionFactory * @param \Magento\Quote\Model\Quote\Config $quoteConfig - * @param \Zend_Db_Adapter_Abstract $connection + * @param \Zend_Db_Adapter_Abstract|null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\Data\Collection\EntityFactory $entityFactory, \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Quote\Model\Resource\Quote\Item\Option\CollectionFactory $itemOptionCollectionFactory, \Magento\Catalog\Model\Resource\Product\CollectionFactory $productCollectionFactory, \Magento\Quote\Model\Quote\Config $quoteConfig, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null ) { - parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource); + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $entitySnapshot, + $connection, + $resource + ); $this->_itemOptionCollectionFactory = $itemOptionCollectionFactory; $this->_productCollectionFactory = $productCollectionFactory; $this->_quoteConfig = $quoteConfig; diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Payment.php b/app/code/Magento/Quote/Model/Resource/Quote/Payment.php index 3275211dbf876b0405ef96cd17fe1842fe7fbfe4..8fc4f3446e2b129a9019cc4ce8def5475e1cb587 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Payment.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Payment.php @@ -5,7 +5,7 @@ */ namespace Magento\Quote\Model\Resource\Quote; -use Magento\Framework\Model\Resource\Db\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb; /** * Quote payment resource model diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php index b1f14b76e7a53170de91a9f6ebe5e6ca5119291a..18b09bf83430939b3e4a3d508c9a602bea12bae7 100644 --- a/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php +++ b/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php @@ -8,14 +8,15 @@ namespace Magento\Quote\Model\Resource\Quote\Payment; /** * Quote payments collection */ -class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection { /** * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Zend_Db_Adapter_Abstract $connection + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot + * @param \Zend_Db_Adapter_Abstract|null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource */ public function __construct( @@ -23,10 +24,19 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null ) { - parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource); + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $entitySnapshot, + $connection, + $resource + ); } /** diff --git a/app/code/Magento/Quote/Model/ShippingMethodManagement.php b/app/code/Magento/Quote/Model/ShippingMethodManagement.php index f8a39533b4233cf77b9365821857ca0e973ada0c..f54ab223a9d55f23a7610bbd204064ac86c0ac97 100644 --- a/app/code/Magento/Quote/Model/ShippingMethodManagement.php +++ b/app/code/Magento/Quote/Model/ShippingMethodManagement.php @@ -46,7 +46,6 @@ class ShippingMethodManagement implements ShippingMethodManagementInterface * @param QuoteRepository $quoteRepository Quote repository. * @param \Magento\Quote\Model\Cart\ShippingMethodConverter $converter Shipping method converter. * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository Customer Address repository - * */ public function __construct( QuoteRepository $quoteRepository, @@ -80,6 +79,9 @@ class ShippingMethodManagement implements ShippingMethodManagementInterface $shippingAddress->collectShippingRates(); /** @var \Magento\Quote\Model\Quote\Address\Rate $shippingRate */ $shippingRate = $shippingAddress->getShippingRateByCode($shippingMethod); + if (!$shippingRate) { + return null; + } return $this->converter->modelToDataObject($shippingRate, $quote->getQuoteCurrencyCode()); } @@ -140,10 +142,6 @@ class ShippingMethodManagement implements ShippingMethodManagementInterface if (!$shippingAddress->getCountryId()) { throw new StateException(__('Shipping address is not set')); } - $billingAddress = $quote->getBillingAddress(); - if (!$billingAddress->getCountryId()) { - throw new StateException(__('Billing address is not set')); - } $shippingAddress->setShippingMethod($carrierCode . '_' . $methodCode); if (!$shippingAddress->getShippingRateByCode($shippingAddress->getShippingMethod())) { throw new NoSuchEntityException( @@ -222,7 +220,7 @@ class ShippingMethodManagement implements ShippingMethodManagementInterface $shippingAddress->setRegionId($regionId); $shippingAddress->setRegion($region); $shippingAddress->setCollectShippingRates(true); - $shippingAddress->collectShippingRates(); + $shippingAddress->collectTotals(); $shippingRates = $shippingAddress->getGroupedAllShippingRates(); foreach ($shippingRates as $carrierRates) { foreach ($carrierRates as $rate) { diff --git a/app/code/Magento/Quote/Test/Unit/Model/AddressDetailsManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/AddressDetailsManagementTest.php deleted file mode 100644 index ab1e0e6c18be2874a5fbc5f5af17ffd48452e028..0000000000000000000000000000000000000000 --- a/app/code/Magento/Quote/Test/Unit/Model/AddressDetailsManagementTest.php +++ /dev/null @@ -1,151 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Test\Unit\Model; - -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; - -class AddressDetailsManagementTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var \Magento\Quote\Model\AddressDetailsManagement - */ - protected $model; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $billingAddressManagement; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $shippingAddressManagement; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $paymentMethodManagement; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $shippingMethodManagement; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $addressDetailsFactory; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $dataProcessor; - - /** @var \Magento\Quote\Model\QuoteRepository|\PHPUnit_Framework_MockObject_MockObject */ - protected $quoteRepository; - - /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager - */ - protected $objectManager; - - protected function setUp() - { - $this->objectManager = new ObjectManager($this); - $this->billingAddressManagement = $this->getMock('Magento\Quote\Api\BillingAddressManagementInterface'); - $this->shippingAddressManagement = $this->getMock('Magento\Quote\Api\ShippingAddressManagementInterface'); - $this->paymentMethodManagement = $this->getMock('Magento\Quote\Api\PaymentMethodManagementInterface'); - $this->shippingMethodManagement = $this->getMock('Magento\Quote\Api\ShippingMethodManagementInterface'); - $this->addressDetailsFactory = $this->getMock( - 'Magento\Quote\Model\AddressDetailsFactory', - ['create'], - [], - '', - false - ); - $this->dataProcessor = $this->getMock('Magento\Quote\Model\AddressAdditionalDataProcessor', [], [], '', false); - $this->quoteRepository = $this->getMock('Magento\Quote\Model\QuoteRepository', [], [], '', false); - - $this->model = $this->objectManager->getObject( - 'Magento\Quote\Model\AddressDetailsManagement', - [ - 'billingAddressManagement' => $this->billingAddressManagement, - 'shippingAddressManagement' => $this->shippingAddressManagement, - 'paymentMethodManagement' => $this->paymentMethodManagement, - 'shippingMethodManagement' => $this->shippingMethodManagement, - 'addressDetailsFactory' => $this->addressDetailsFactory, - 'dataProcessor' => $this->dataProcessor, - 'quoteRepository' => $this->quoteRepository, - ] - ); - } - - public function testSaveAddresses() - { - $cartId = 100; - $additionalData = $this->getMock('\Magento\Quote\Api\Data\AddressAdditionalDataInterface'); - $billingAddressMock = $this->getMock('\Magento\Quote\Model\Quote\Address', [], [], '', false); - $shippingAddressMock = $this->getMock('\Magento\Quote\Model\Quote\Address', [], [], '', false); - - $this->billingAddressManagement->expects($this->once()) - ->method('assign') - ->with($cartId, $billingAddressMock) - ->willReturn(1); - - $billingAddressMock->expects($this->once())->method('format')->with('html'); - $this->billingAddressManagement->expects($this->once()) - ->method('get') - ->with($cartId) - ->willReturn($billingAddressMock); - - $this->shippingAddressManagement->expects($this->once()) - ->method('assign') - ->with($cartId, $shippingAddressMock) - ->willReturn(1); - - $shippingAddressMock->expects($this->once())->method('format')->with('html'); - $this->shippingAddressManagement->expects($this->once()) - ->method('get') - ->with($cartId) - ->willReturn($shippingAddressMock); - - $shippingMethodMock = $this->getMock('\Magento\Quote\Api\Data\ShippingMethodInterface'); - $this->shippingMethodManagement->expects($this->once()) - ->method('getList') - ->with($cartId) - ->willReturn([$shippingMethodMock]); - $paymentMethodMock = $this->getMock('\Magento\Quote\Api\Data\PaymentMethodInterface'); - $this->paymentMethodManagement->expects($this->once()) - ->method('getList') - ->with($cartId) - ->willReturn([$paymentMethodMock]); - - $addressDetailsMock = $this->getMock('\Magento\Quote\Model\AddressDetails', [], [], '', false); - $this->addressDetailsFactory->expects($this->once())->method('create')->willReturn($addressDetailsMock); - - $addressDetailsMock->expects($this->once()) - ->method('setShippingMethods') - ->with([$shippingMethodMock]) - ->willReturnSelf(); - $addressDetailsMock->expects($this->once()) - ->method('setPaymentMethods') - ->with([$paymentMethodMock]) - ->willReturnSelf(); - $this->dataProcessor->expects($this->once())->method('process')->with($additionalData); - - $quote = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false); - $quote->expects($this->once()) - ->method('setCheckoutMethod') - ->willReturnSelf(); - - $this->quoteRepository - ->expects($this->once()) - ->method('getActive') - ->willReturn($quote); - - $this->model->saveAddresses($cartId, $billingAddressMock, $shippingAddressMock, $additionalData, 'register'); - } -} diff --git a/app/code/Magento/Quote/Test/Unit/Model/Cart/Totals/ItemConverterTest.php b/app/code/Magento/Quote/Test/Unit/Model/Cart/Totals/ItemConverterTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b9770ab17fc4d02eb7d75838f4104acf4f41735b --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Cart/Totals/ItemConverterTest.php @@ -0,0 +1,91 @@ +<?php +/** + * + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Test\Unit\Model\Cart\Totals; + +class ItemConverterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $configPoolMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $eventManagerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $totalsFactoryMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $dataObjectHelperMock; + + /** + * @var \Magento\Quote\Model\Cart\Totals\ItemConverter + */ + private $model; + + public function setUp() + { + $this->configPoolMock = $this->getMock('Magento\Catalog\Helper\Product\ConfigurationPool', [], [], '', false); + $this->eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface'); + $this->dataObjectHelperMock = $this->getMock('Magento\Framework\Api\DataObjectHelper', [], [], '', false); + $this->totalsFactoryMock = $this->getMock( + 'Magento\Quote\Api\Data\TotalsItemInterfaceFactory', + ['create'], + [], + '', + false + ); + + $this->model = new \Magento\Quote\Model\Cart\Totals\ItemConverter( + $this->configPoolMock, + $this->eventManagerMock, + $this->totalsFactoryMock, + $this->dataObjectHelperMock + ); + } + + public function testModelToDataObject() + { + $productType = 'simple'; + + $itemMock = $this->getMock('Magento\Quote\Model\Quote\Item', [], [], '', false); + $itemMock->expects($this->once())->method('toArray')->will($this->returnValue(['options' => []])); + $itemMock->expects($this->any())->method('getProductType')->will($this->returnValue($productType)); + + $simpleConfigMock = $this->getMock('Magento\Catalog\Helper\Product\Configuration', [], [], '', false); + $defaultConfigMock = $this->getMock('Magento\Catalog\Helper\Product\Configuration', [], [], '', false); + + $this->configPoolMock->expects($this->any())->method('getByProductType') + ->will($this->returnValueMap([['simple', $simpleConfigMock], ['default', $defaultConfigMock]])); + + $options = ['1' => ['label' => 'option1'], '2' => ['label' => 'option2']]; + $simpleConfigMock->expects($this->once())->method('getOptions')->with($itemMock) + ->will($this->returnValue($options)); + + $option = ['data' => 'optionsData', 'label' => '']; + $defaultConfigMock->expects($this->any())->method('getFormattedOptionValue')->will($this->returnValue($option)); + + $this->eventManagerMock->expects($this->once())->method('dispatch') + ->with('items_additional_data', ['item' => $itemMock]); + + $this->totalsFactoryMock->expects($this->once())->method('create'); + + $expectedData = [ + 'options' => '{"1":{"data":"optionsData","label":"option1"},"2":{"data":"optionsData","label":"option2"}}' + ]; + $this->dataObjectHelperMock->expects($this->once())->method('populateWithArray') + ->with(null, $expectedData, '\Magento\Quote\Api\Data\TotalsItemInterface'); + + $this->model->modelToDataObject($itemMock); + } +} diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/RelationTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/RelationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b8fa10e5ed63043809e17c2ee10bb39926e9bc08 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/RelationTest.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Test\Unit\Model\Quote\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class RelationTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\Model\AbstractModel | \PHPUnit_Framework_MockObject_MockObject + */ + private $modelMock; + + /** + * @var \Magento\Quote\Model\Quote\Address\Relation + */ + private $relation; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->modelMock = $this->getMock( + 'Magento\Framework\Model\AbstractModel', + [ + 'getItemsCollection', + 'getShippingRatesCollection', + 'itemsCollectionWasSet', + 'shippingRatesCollectionWasSet' + ], + [], + '', + false + ); + $this->relation = $objectManager->getObject('Magento\Quote\Model\Quote\Address\Relation', []); + } + + public function testProcessRelation() + { + $itemsCollection = $this->getMock( + 'Magento\Framework\Model\Resource\Db\Collection\AbstractCollection', + [], + [], + '', + false + ); + $shippingRatesCollection = $this->getMock( + 'Magento\Framework\Model\Resource\Db\Collection\AbstractCollection', + [], + [], + '', + false + ); + $this->modelMock->expects($this->once())->method('itemsCollectionWasSet')->willReturn(true); + $this->modelMock->expects($this->once())->method('getItemsCollection')->willReturn($itemsCollection); + $this->modelMock->expects($this->once())->method('shippingRatesCollectionWasSet')->willReturn(true); + $this->modelMock->expects($this->once()) + ->method('getShippingRatesCollection') + ->willReturn($shippingRatesCollection); + $itemsCollection->expects($this->once())->method('save'); + $shippingRatesCollection->expects($this->once())->method('save'); + $this->relation->processRelation($this->modelMock); + } +} diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php index 2fd80d4588170a5594df523ff5586f5b6ef086d8..996d1d54955f38aee5c92e51030e5258497ef3a9 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php @@ -22,7 +22,7 @@ class AbstractItemTest extends \PHPUnit_Framework_TestCase public function testGetTotalDiscountAmount($expectedDiscountAmount, $children, $calculated, $myDiscountAmount) { $abstractItemMock = $this->getMockForAbstractClass( - '\Magento\Quote\Model\Quote\Item\AbstractItem', + 'Magento\Quote\Model\Quote\Item\AbstractItem', [], '', false, @@ -51,7 +51,7 @@ class AbstractItemTest extends \PHPUnit_Framework_TestCase { $childOneDiscountAmount = 1000; $childOneItemMock = $this->getMockForAbstractClass( - '\Magento\Quote\Model\Quote\Item\AbstractItem', + 'Magento\Quote\Model\Quote\Item\AbstractItem', [], '', false, @@ -65,7 +65,7 @@ class AbstractItemTest extends \PHPUnit_Framework_TestCase $childTwoDiscountAmount = 50; $childTwoItemMock = $this->getMockForAbstractClass( - '\Magento\Quote\Model\Quote\Item\AbstractItem', + 'Magento\Quote\Model\Quote\Item\AbstractItem', [], '', false, diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/RelationTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/RelationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3b0723b9273e046a59f667ad3b3b5526d4182bcd --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/RelationTest.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Test\Unit\Model\Quote; + +use Magento\Quote\Model\Quote\Relation; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class RelationTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Relation + */ + private $model; + + /** + * @var \Magento\Quote\Model\Quote|\PHPUnit_Framework_MockObject_MockObject + */ + protected $quoteMock; + + /** + * Mock class dependencies + */ + protected function setUp() + { + $this->quoteMock = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false); + + $objectManager = new ObjectManager($this); + $this->model = $objectManager->getObject( + 'Magento\Quote\Model\Quote\Relation' + ); + } + + /** + * Test for processRelation + */ + public function testProcessRelation() + { + $addressCollectionMock = $this->getMock( + 'Magento\Eav\Model\Entity\Collection\AbstractCollection', + [], + [], + '', + false + ); + $this->quoteMock->expects($this->once())->method('addressCollectionWasSet')->willReturn(true); + $this->quoteMock->expects($this->once())->method('getAddressesCollection')->willReturn($addressCollectionMock); + $addressCollectionMock->expects($this->once())->method('save'); + + + $itemsCollectionMock = $this->getMock( + 'Magento\Eav\Model\Entity\Collection\AbstractCollection', + [], + [], + '', + false + ); + $this->quoteMock->expects($this->once())->method('itemsCollectionWasSet')->willReturn(true); + $this->quoteMock->expects($this->once())->method('getItemsCollection')->willReturn($itemsCollectionMock); + $itemsCollectionMock->expects($this->once())->method('save'); + + $paymentCollectionMock = $this->getMock( + 'Magento\Eav\Model\Entity\Collection\AbstractCollection', + [], + [], + '', + false + ); + $this->quoteMock->expects($this->once())->method('paymentsCollectionWasSet')->willReturn(true); + $this->quoteMock->expects($this->once())->method('getPaymentsCollection')->willReturn($paymentCollectionMock); + $paymentCollectionMock->expects($this->once())->method('save'); + + $paymentMock = $this->getMock('Magento\Quote\Model\Quote\Payment', [], [], '', false); + $this->quoteMock->expects($this->once())->method('currentPaymentWasSet')->willReturn(true); + $this->quoteMock->expects($this->once())->method('getPayment')->willReturn($paymentMock); + $paymentMock->expects($this->once())->method('save'); + + $this->model->processRelation($this->quoteMock); + } +} diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php index 56885a81d78648500927d8b77992e9cddea8a2ee..b6a44c587386f6c5fa0e885261ac30c06a7c83c6 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php @@ -211,7 +211,7 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase $this->dataObjectHelperMock = $this->getMock('\Magento\Framework\Api\DataObjectHelper', [], [], '', false); $this->checkoutSessionMock = $this->getMock( 'Magento\Checkout\Model\Session', - ['setLastQuoteId', 'setLastSuccessQuoteId', 'setLastOrderId', 'setLastRealOrderId'], + ['setLastQuoteId', 'setLastSuccessQuoteId', 'setLastOrderId', 'setLastRealOrderId', 'setLastOrderStatus'], [], '', false @@ -652,6 +652,7 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase $cartId = 100; $orderId = 332; $orderIncrementId = 100003332; + $orderStatus = 'status1'; $email = 'email@mail.com'; $this->quoteRepositoryMock->expects($this->once()) @@ -710,59 +711,26 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase $service->expects($this->once())->method('submit')->willReturn($orderMock); $this->quoteMock->expects($this->atLeastOnce())->method('getId')->willReturn($cartId); + $orderMock->expects($this->atLeastOnce())->method('getId')->willReturn($orderId); $orderMock->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($orderIncrementId); + $orderMock->expects($this->atLeastOnce())->method('getStatus')->willReturn($orderStatus); $this->checkoutSessionMock->expects($this->once())->method('setLastQuoteId')->with($cartId); $this->checkoutSessionMock->expects($this->once())->method('setLastSuccessQuoteId')->with($cartId); $this->checkoutSessionMock->expects($this->once())->method('setLastOrderId')->with($orderId); $this->checkoutSessionMock->expects($this->once())->method('setLastRealOrderId')->with($orderIncrementId); - $this->agreementsValidatorMock->expects($this->once())->method('isValid')->willReturn(true); - + $this->checkoutSessionMock->expects($this->once())->method('setLastOrderStatus')->with($orderStatus); + $this->assertEquals($orderId, $service->placeOrder($cartId)); } - /** - * @expectedException \Magento\Framework\Exception\CouldNotSaveException - */ - public function testPlaceOrderIfAgreementsIsNotValid() - { - $this->agreementsValidatorMock->expects($this->once())->method('isValid')->willReturn(false); - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Quote\Model\QuoteManagement $service */ - $service = $this->getMock( - '\Magento\Quote\Model\QuoteManagement', - ['submit'], - [ - 'eventManager' => $this->eventManager, - 'quoteValidator' => $this->quoteValidator, - 'orderFactory' => $this->orderFactory, - 'orderManagement' => $this->orderManagement, - 'customerManagement' => $this->customerManagement, - 'quoteAddressToOrder' => $this->quoteAddressToOrder, - 'quoteAddressToOrderAddress' => $this->quoteAddressToOrderAddress, - 'quoteItemToOrderItem' => $this->quoteItemToOrderItem, - 'quotePaymentToOrderPayment' => $this->quotePaymentToOrderPayment, - 'userContext' => $this->userContextMock, - 'quoteRepository' => $this->quoteRepositoryMock, - 'customerRepository' => $this->customerRepositoryMock, - 'customerModelFactory' => $this->customerFactoryMock, - 'dataObjectHelper' => $this->dataObjectHelperMock, - 'storeManager' => $this->storeManagerMock, - 'checkoutSession' => $this->checkoutSessionMock, - 'customerSession' => $this->customerSessionMock, - 'accountManagement' => $this->accountManagementMock, - 'agreementsValidator' => $this->agreementsValidatorMock, - ] - ); - $service->placeOrder(45); - } - public function testPlaceOrder() { $cartId = 323; $orderId = 332; $orderIncrementId = 100003332; + $orderStatus = 'status1'; /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Quote\Model\QuoteManagement $service */ $service = $this->getMock( @@ -822,14 +790,16 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase $service->expects($this->once())->method('submit')->willReturn($orderMock); $this->quoteMock->expects($this->atLeastOnce())->method('getId')->willReturn($cartId); + $orderMock->expects($this->atLeastOnce())->method('getId')->willReturn($orderId); $orderMock->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($orderIncrementId); + $orderMock->expects($this->atLeastOnce())->method('getStatus')->willReturn($orderStatus); $this->checkoutSessionMock->expects($this->once())->method('setLastQuoteId')->with($cartId); $this->checkoutSessionMock->expects($this->once())->method('setLastSuccessQuoteId')->with($cartId); $this->checkoutSessionMock->expects($this->once())->method('setLastOrderId')->with($orderId); $this->checkoutSessionMock->expects($this->once())->method('setLastRealOrderId')->with($orderIncrementId); - $this->agreementsValidatorMock->expects($this->once())->method('isValid')->willReturn(true); + $this->checkoutSessionMock->expects($this->once())->method('setLastOrderStatus')->with($orderStatus); $paymentMethod = $this->getMock('Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false); $paymentMethod->expects($this->once())->method('setChecks'); diff --git a/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/Item/CollectionTest.php b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/Item/CollectionTest.php new file mode 100644 index 0000000000000000000000000000000000000000..04b1ab4442d2ebf9ac3f3d089cecc34504e90555 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/Item/CollectionTest.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Test\Unit\Model\Resource\Quote\Item; + +use Magento\Quote\Model\Resource\Quote\Item\Collection; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +/** + * Class CollectionTest + */ +class CollectionTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Collection + */ + private $collection; + + /** + * @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject + */ + protected $connectionMock; + + /** + * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eventManagerMock; + + /** + * @var \Zend_Db_Select|\PHPUnit_Framework_MockObject_MockObject + */ + protected $selectMock; + + /** + * @var \Magento\Framework\Model\Resource\Db\AbstractDb|\PHPUnit_Framework_MockObject_MockObject + */ + protected $resourceMock; + + /** + * @var \Magento\Framework\Data\Collection\Db\FetchStrategyInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fetchStrategyMock; + + /** + * @var \Magento\Framework\Data\Collection\EntityFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entityFactoryMock; + + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entitySnapshotMock; + + /** + * Mock class dependencies + */ + protected function setUp() + { + $this->entityFactoryMock = $this->getMock('Magento\Framework\Data\Collection\EntityFactory', [], [], '', false); + $this->fetchStrategyMock = $this->getMockForAbstractClass( + 'Magento\Framework\Data\Collection\Db\FetchStrategyInterface' + ); + $this->eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface', [], [], '', false); + + $this->selectMock = $this->getMock('Zend_Db_Select', [], [], '', false); + $this->connectionMock = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false); + $this->connectionMock->expects($this->atLeastOnce()) + ->method('select') + ->will($this->returnValue($this->selectMock)); + + $this->resourceMock = $this->getMock('Magento\Framework\Model\Resource\Db\AbstractDb', [], [], '', false); + $this->resourceMock->expects($this->any())->method('getReadConnection')->will( + $this->returnValue($this->connectionMock) + ); + + $objectManager = new ObjectManager($this); + $this->collection = $objectManager->getObject( + 'Magento\Quote\Model\Resource\Quote\Item\Collection', + [ + 'entityFactory' => $this->entityFactoryMock, + 'fetchStrategy' => $this->fetchStrategyMock, + 'eventManager' => $this->eventManagerMock, + 'resource' => $this->resourceMock + ] + ); + } + + public function testInstanceOf() + { + $this->assertInstanceOf('Magento\Framework\Model\Resource\Db\VersionControl\Collection', $this->collection); + } +} diff --git a/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/ItemTest.php b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/ItemTest.php new file mode 100644 index 0000000000000000000000000000000000000000..60eb9d9eda57e978a5fd8c95a6f5de3cadfee183 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/ItemTest.php @@ -0,0 +1,179 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Test\Unit\Model\Resource\Quote; + +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; +use Magento\Quote\Model\Resource\Quote\Item; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Class ItemTest + * + * @SuppressWarnings(PHPMD.TooManyFields) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ItemTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var Item + */ + protected $model; + + /** + * @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject + */ + protected $resourceMock; + + /** + * @var \Magento\Quote\Model\Quote\Item|\PHPUnit_Framework_MockObject_MockObject + */ + protected $quoteItemMock; + + /** + * @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject + */ + protected $adapterMock; + + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entitySnapshotMock; + + /** + * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject + */ + protected $relationCompositeMock; + + /** + * @var \Magento\Framework\Model\Resource\Db\ObjectRelationProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + protected $objectRelationProcessorMock; + + /** + * Mock class dependencies + */ + public function setUp() + { + $this->resourceMock = $this->getMock('Magento\Framework\App\Resource', [], [], '', false); + $this->quoteItemMock = $this->getMock('Magento\Quote\Model\Quote\Item', [], [], '', false); + $this->adapterMock = $this->getMock( + 'Magento\Framework\DB\Adapter\Pdo\Mysql', + [ + 'describeTable', + 'insert', + 'lastInsertId', + 'beginTransaction', + 'rollback', + 'commit', + 'quoteInto', + 'update' + ], + [], + '', + false + ); + $this->entitySnapshotMock = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', + [], + [], + '', + false + ); + $this->relationCompositeMock = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite', + [], + [], + '', + false + ); + $this->objectRelationProcessorMock = $this->getMock( + 'Magento\Framework\Model\Resource\Db\ObjectRelationProcessor', + [], + [], + '', + false + ); + $contextMock = $this->getMock('\Magento\Framework\Model\Resource\Db\Context', [], [], '', false); + $contextMock->expects($this->once())->method('getResources')->willReturn($this->resourceMock); + $contextMock->expects($this->once()) + ->method('getObjectRelationProcessor') + ->willReturn($this->objectRelationProcessorMock); + + $objectManager = new ObjectManagerHelper($this); + $this->model = $objectManager->getObject( + 'Magento\Quote\Model\Resource\Quote\Item', + [ + 'context' => $contextMock, + 'entitySnapshot' => $this->entitySnapshotMock, + 'entityRelationComposite' => $this->relationCompositeMock + ] + ); + } + + public function testInstanceOf() + { + $this->assertInstanceOf('Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb', $this->model); + } + + public function testSaveNotModifiedItem() + { + $this->entitySnapshotMock->expects($this->exactly(2)) + ->method('isModified') + ->with($this->quoteItemMock) + ->willReturn(false); + + $this->quoteItemMock->expects($this->never()) + ->method('isOptionsSaved'); + $this->quoteItemMock->expects($this->never()) + ->method('saveItemOptions'); + + $this->resourceMock->expects($this->any()) + ->method('getConnection') + ->willReturn($this->adapterMock); + + $this->assertEquals($this->model, $this->model->save($this->quoteItemMock)); + } + + public function testSaveSavedBeforeItem() + { + $this->entitySnapshotMock->expects($this->exactly(2)) + ->method('isModified') + ->with($this->quoteItemMock) + ->willReturn(true); + + $this->quoteItemMock->expects($this->once()) + ->method('isOptionsSaved') + ->willReturn(true); + $this->quoteItemMock->expects($this->never()) + ->method('saveItemOptions'); + + $this->resourceMock->expects($this->any()) + ->method('getConnection') + ->willReturn($this->adapterMock); + + $this->assertEquals($this->model, $this->model->save($this->quoteItemMock)); + } + + public function testSaveModifiedItem() + { + $this->entitySnapshotMock->expects($this->exactly(2)) + ->method('isModified') + ->with($this->quoteItemMock) + ->willReturn(true); + + $this->quoteItemMock->expects($this->once()) + ->method('isOptionsSaved') + ->willReturn(false); + $this->quoteItemMock->expects($this->once()) + ->method('saveItemOptions'); + + $this->resourceMock->expects($this->any()) + ->method('getConnection') + ->willReturn($this->adapterMock); + + $this->assertEquals($this->model, $this->model->save($this->quoteItemMock)); + } +} diff --git a/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/QuoteAddressTest.php b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/QuoteAddressTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a7713ff991ba28f6d17e7d13547abc6a8640ea83 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/QuoteAddressTest.php @@ -0,0 +1,132 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Quote\Test\Unit\Model\Resource\Quote; + +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; + +/** + * Class QuoteAddressTest + */ +class QuoteAddressTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Quote\Model\Resource\Quote\Address + */ + protected $addressResource; + + /** + * @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject + */ + protected $appResourceMock; + + /** + * @var \Magento\Quote\Model\Quote\Address|\PHPUnit_Framework_MockObject_MockObject + */ + protected $addressMock; + + /** + * @var \Magento\Quote\Model\Quote|\PHPUnit_Framework_MockObject_MockObject + */ + protected $quoteMock; + + /** + * @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject + */ + protected $adapterMock; + + /** + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entitySnapshotMock; + + /** + * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject + */ + protected $relationCompositeMock; + + /** + * Init + */ + public function setUp() + { + $this->addressMock = $this->getMock( + 'Magento\Quote\Model\Quote\Address', + ['__wakeup', 'getOrderId', 'hasDataChanges', 'beforeSave', 'afterSave', 'validateBeforeSave', 'getOrder'], + [], + '', + false + ); + $this->quoteMock = $this->getMock( + 'Magento\Quote\Model\Quote', + ['__wakeup', 'getId'], + [], + '', + false + ); + $this->appResourceMock = $this->getMock( + 'Magento\Framework\App\Resource', + [], + [], + '', + false + ); + $this->adapterMock = $this->getMock( + 'Magento\Framework\DB\Adapter\Pdo\Mysql', + [], + [], + '', + false + ); + $this->entitySnapshotMock = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', + [], + [], + '', + false + ); + $this->relationCompositeMock = $this->getMock( + 'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite', + [], + [], + '', + false + ); + $this->appResourceMock->expects($this->any()) + ->method('getConnection') + ->will($this->returnValue($this->adapterMock)); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->adapterMock->expects($this->any()) + ->method('describeTable') + ->will($this->returnValue([])); + $this->adapterMock->expects($this->any()) + ->method('insert'); + $this->adapterMock->expects($this->any()) + ->method('lastInsertId'); + $this->addressResource = $objectManager->getObject( + 'Magento\Quote\Model\Resource\Quote\Address', + [ + 'resource' => $this->appResourceMock, + 'entitySnapshot' => $this->entitySnapshotMock, + 'entityRelationComposite' => $this->relationCompositeMock + ] + ); + } + + public function testSave() + { + $this->entitySnapshotMock->expects($this->once()) + ->method('isModified') + ->with($this->addressMock) + ->willReturn(true); + $this->entitySnapshotMock->expects($this->once()) + ->method('registerSnapshot') + ->with($this->addressMock); + $this->relationCompositeMock->expects($this->once()) + ->method('processRelations') + ->with($this->addressMock); + $this->addressResource->save($this->addressMock); + } +} diff --git a/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressManagementTest.php index 4c5bffe80077615734f94e7df2f3cee0f0c61f4d..2fea9a5b9a15c1c67d7bcf85e49814f90162f5f6 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressManagementTest.php @@ -32,6 +32,11 @@ class ShippingAddressManagementTest extends \PHPUnit_Framework_TestCase */ protected $validatorMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $scopeConfigMock; + /** * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ @@ -41,6 +46,7 @@ class ShippingAddressManagementTest extends \PHPUnit_Framework_TestCase { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->quoteRepositoryMock = $this->getMock('\Magento\Quote\Model\QuoteRepository', [], [], '', false); + $this->scopeConfigMock = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface'); $this->quoteAddressMock = $this->getMock( '\Magento\Quote\Model\Quote\Address', @@ -66,7 +72,8 @@ class ShippingAddressManagementTest extends \PHPUnit_Framework_TestCase [ 'quoteRepository' => $this->quoteRepositoryMock, 'addressValidator' => $this->validatorMock, - 'logger' => $this->getMock('\Psr\Log\LoggerInterface') + 'logger' => $this->getMock('\Psr\Log\LoggerInterface'), + 'scopeConfig' => $this->scopeConfigMock ] ); } @@ -167,6 +174,28 @@ class ShippingAddressManagementTest extends \PHPUnit_Framework_TestCase $this->service->assign('cart867', $this->quoteAddressMock); } + /** + * @expectedException \Magento\Framework\Exception\InputException + */ + public function testSetAddressWithViolationOfMinimumAmount() + { + $storeId = 12; + $this->quoteAddressMock->expects($this->once())->method('collectTotals')->willReturnSelf(); + $this->quoteAddressMock->expects($this->once())->method('save'); + + $quoteMock = $this->getMock('\Magento\Quote\Model\Quote', [], [], '', false); + $this->quoteRepositoryMock->expects($this->once())->method('getActive')->with('cart123') + ->will($this->returnValue($quoteMock)); + $quoteMock->expects($this->once())->method('isVirtual')->will($this->returnValue(false)); + $quoteMock->expects($this->once())->method('getShippingAddress')->willReturn($this->quoteAddressMock); + $quoteMock->expects($this->any())->method('getStoreId')->will($this->returnValue($storeId)); + + $this->scopeConfigMock->expects($this->once())->method('getValue') + ->with('sales/minimum_order/error_message', \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId); + + $this->service->assign('cart123', $this->quoteAddressMock); + } + public function testGetAddress() { $quoteMock = $this->getMock('\Magento\Quote\Model\Quote', [], [], '', false); diff --git a/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php index ef5992e11f7af3c0dbedf4f7b8d263a12cf1804e..fd760977a6c89f57308b2142d4acd827af06bfa4 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php @@ -316,39 +316,6 @@ class ShippingMethodManagementTest extends \PHPUnit_Framework_TestCase $this->model->set($cartId, $carrierCode, $methodCode); } - /** - * @expectedException \Magento\Framework\Exception\StateException - * @expectedExceptionMessage Billing address is not set - */ - public function testSetMethodWithoutBillingAddress() - { - $cartId = 12; - $carrierCode = 34; - $methodCode = 56; - $countryId = 1; - - $this->quoteRepositoryMock->expects($this->once()) - ->method('getActive')->with($cartId)->will($this->returnValue($this->quoteMock)); - $this->quoteMock->expects($this->once())->method('getItemsCount')->will($this->returnValue(1)); - $this->quoteMock->expects($this->once())->method('isVirtual')->will($this->returnValue(false)); - $this->quoteMock->expects($this->once()) - ->method('getShippingAddress')->will($this->returnValue($this->shippingAddressMock)); - $this->shippingAddressMock->expects($this->once()) - ->method('getCountryId')->will($this->returnValue($countryId)); - $billingAddressMock = $this->getMock( - '\Magento\Quote\Model\Quote\Address', - ['getCountryId', '__wakeup'], - [], - '', - false - ); - $this->quoteMock->expects($this->once()) - ->method('getBillingAddress')->will($this->returnValue($billingAddressMock)); - $billingAddressMock->expects($this->once())->method('getCountryId')->will($this->returnValue(null)); - - $this->model->set($cartId, $carrierCode, $methodCode); - } - /** * @expectedException \Magento\Framework\Exception\NoSuchEntityException * @expectedExceptionMessage Carrier with such method not found: 34, 56 @@ -365,16 +332,6 @@ class ShippingMethodManagementTest extends \PHPUnit_Framework_TestCase $this->quoteMock->expects($this->once())->method('isVirtual')->will($this->returnValue(false)); $this->quoteMock->expects($this->once()) ->method('getShippingAddress')->will($this->returnValue($this->shippingAddressMock)); - $billingAddressMock = $this->getMock( - '\Magento\Quote\Model\Quote\Address', - ['getCountryId', '__wakeup'], - [], - '', - false - ); - $this->quoteMock->expects($this->once()) - ->method('getBillingAddress')->will($this->returnValue($billingAddressMock)); - $billingAddressMock->expects($this->once())->method('getCountryId')->will($this->returnValue(23)); $this->shippingAddressMock->expects($this->once()) ->method('getCountryId')->will($this->returnValue($countryId)); $this->shippingAddressMock->expects($this->once()) @@ -405,19 +362,6 @@ class ShippingMethodManagementTest extends \PHPUnit_Framework_TestCase ->method('getShippingAddress')->will($this->returnValue($this->shippingAddressMock)); $this->shippingAddressMock->expects($this->once()) ->method('getCountryId')->will($this->returnValue($countryId)); - $billingAddressMock = $this->getMock( - '\Magento\Quote\Model\Quote\Address', - [ - 'getCountryId', - '__wakeup' - ], - [], - '', - false - ); - $this->quoteMock->expects($this->once()) - ->method('getBillingAddress')->will($this->returnValue($billingAddressMock)); - $billingAddressMock->expects($this->once())->method('getCountryId')->will($this->returnValue(23)); $this->shippingAddressMock->expects($this->once()) ->method('setShippingMethod')->with($carrierCode . '_' . $methodCode); $this->shippingAddressMock->expects($this->once()) @@ -464,19 +408,6 @@ class ShippingMethodManagementTest extends \PHPUnit_Framework_TestCase $this->quoteMock->expects($this->once())->method('isVirtual')->will($this->returnValue(false)); $this->quoteMock->expects($this->once()) ->method('getShippingAddress')->will($this->returnValue($this->shippingAddressMock)); - $billingAddressMock = $this->getMock( - '\Magento\Quote\Model\Quote\Address', - [ - 'getCountryId', - '__wakeup' - ], - [], - '', - false - ); - $this->quoteMock->expects($this->once()) - ->method('getBillingAddress')->will($this->returnValue($billingAddressMock)); - $billingAddressMock->expects($this->once())->method('getCountryId')->will($this->returnValue(23)); $this->shippingAddressMock->expects($this->once()) ->method('getCountryId')->will($this->returnValue($countryId)); $this->shippingAddressMock->expects($this->once()) diff --git a/app/code/Magento/Quote/etc/di.xml b/app/code/Magento/Quote/etc/di.xml index 66cae592e21018589902a907529cbcc87007c8e4..8766552b2bca3a3ee0743e672a0335d4c5c858d2 100644 --- a/app/code/Magento/Quote/etc/di.xml +++ b/app/code/Magento/Quote/etc/di.xml @@ -24,6 +24,7 @@ <preference for="Magento\Quote\Api\CartTotalRepositoryInterface" type="\Magento\Quote\Model\Cart\CartTotalRepository" /> <preference for="Magento\Quote\Api\CartTotalManagementInterface" type="\Magento\Quote\Model\Cart\CartTotalManagement" /> <preference for="Magento\Quote\Api\Data\TotalsInterface" type="\Magento\Quote\Model\Cart\Totals" /> + <preference for="Magento\Quote\Api\Data\TotalSegmentInterface" type="\Magento\Quote\Model\Cart\TotalSegment" /> <preference for="Magento\Quote\Api\Data\TotalsItemInterface" type="\Magento\Quote\Model\Cart\Totals\Item" /> <preference for="Magento\Quote\Api\Data\CurrencyInterface" type="\Magento\Quote\Model\Cart\Currency" /> <preference for="Magento\Quote\Api\GuestCartManagementInterface" type="Magento\Quote\Model\GuestCart\GuestCartManagement" /> @@ -35,7 +36,6 @@ <preference for="Magento\Quote\Api\GuestShippingAddressManagementInterface" type="Magento\Quote\Model\GuestCart\GuestShippingAddressManagement" /> <preference for="Magento\Quote\Api\GuestShippingMethodManagementInterface" type="Magento\Quote\Model\GuestCart\GuestShippingMethodManagement" /> <preference for="Magento\Quote\Api\GuestBillingAddressManagementInterface" type="Magento\Quote\Model\GuestCart\GuestBillingAddressManagement" /> - <preference for="Magento\Quote\Api\GuestAddressDetailsManagementInterface" type="Magento\Quote\Model\GuestCart\GuestAddressDetailsManagement" /> <preference for="Magento\Quote\Api\GuestCartTotalManagementInterface" type="\Magento\Quote\Model\GuestCart\GuestCartTotalManagement" /> <preference for="Magento\Quote\Api\Data\EstimateAddressInterface" type="Magento\Quote\Model\EstimateAddress" /> <type name="Magento\Webapi\Controller\Rest\ParamsOverrider"> @@ -55,8 +55,30 @@ <argument name="addressConfig" xsi:type="object">Magento\Customer\Model\Address\Config\Proxy</argument> </arguments> </type> - <preference for="Magento\Quote\Api\AddressDetailsManagementInterface" type="Magento\Quote\Model\AddressDetailsManagement" /> - <preference for="Magento\Quote\Api\Data\AddressDetailsInterface" type="Magento\Quote\Model\AddressDetails" /> + <virtualType name="QuoteAddressRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> + <arguments> + <argument name="relationProcessors" xsi:type="array"> + <item name="default" xsi:type="object">Magento\Quote\Model\Quote\Address\Relation</item> + </argument> + </arguments> + </virtualType> + <type name="Magento\Quote\Model\Resource\Quote\Address"> + <arguments> + <argument name="entityRelationComposite" xsi:type="object">QuoteAddressRelationsComposite</argument> + </arguments> + </type> + <virtualType name="QuoteRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> + <arguments> + <argument name="relationProcessors" xsi:type="array"> + <item name="default" xsi:type="object">Magento\Quote\Model\Quote\Relation</item> + </argument> + </arguments> + </virtualType> + <type name="Magento\Quote\Model\Resource\Quote"> + <arguments> + <argument name="entityRelationComposite" xsi:type="object">QuoteRelationsComposite</argument> + </arguments> + </type> <preference for="Magento\Quote\Api\Data\AddressAdditionalDataInterface" type="Magento\Quote\Model\AddressAdditionalData" /> <preference for="Magento\Quote\Api\Data\TotalsAdditionalDataInterface" type="Magento\Quote\Model\Cart\TotalsAdditionalData" /> <preference for="\Magento\Quote\Model\Quote\Address\CustomAttributeListInterface" type="\Magento\Quote\Model\Quote\Address\CustomAttributeList" /> diff --git a/app/code/Magento/Quote/etc/webapi.xml b/app/code/Magento/Quote/etc/webapi.xml index 9b6ca15468d654d70622b0dba27d47a02f5f806d..8e5e097a995cd6aa38aa77f568f2c0ba97f1d9cd 100644 --- a/app/code/Magento/Quote/etc/webapi.xml +++ b/app/code/Magento/Quote/etc/webapi.xml @@ -145,6 +145,24 @@ <parameter name="cartId" force="true">%cart_id%</parameter> </data> </route> + <route url="/V1/carts/mine/estimate-shipping-methods" method="POST"> + <service class="Magento\Quote\Api\ShippingMethodManagementInterface" method="estimateByAddress"/> + <resources> + <resource ref="self" /> + </resources> + <data> + <parameter name="cartId" force="true">%cart_id%</parameter> + </data> + </route> + <route url="/V1/carts/mine/estimate-shipping-methods-by-address-id" method="POST"> + <service class="Magento\Quote\Api\ShippingMethodManagementInterface" method="estimateByAddressId"/> + <resources> + <resource ref="self" /> + </resources> + <data> + <parameter name="cartId" force="true">%cart_id%</parameter> + </data> + </route> <!-- Managing Guest Cart Shipment Method --> <route url="/V1/guest-carts/:cartId/selected-shipping-method" method="PUT"> @@ -165,6 +183,12 @@ <resource ref="anonymous" /> </resources> </route> + <route url="/V1/guest-carts/:cartId/estimate-shipping-methods" method="POST"> + <service class="Magento\Quote\Api\GuestShippingMethodManagementInterface" method="estimateByAddress"/> + <resources> + <resource ref="anonymous" /> + </resources> + </route> <!-- Managing Cart Items --> <route url="/V1/carts/:cartId/items" method="GET"> @@ -352,12 +376,6 @@ <resource ref="anonymous" /> </resources> </route> - <route url="/V1/guest-carts/:cartId/addresses" method="POST"> - <service class="Magento\Quote\Api\GuestAddressDetailsManagementInterface" method="saveAddresses"/> - <resources> - <resource ref="anonymous" /> - </resources> - </route> <!-- Managing My Cart Billing address --> <route url="/V1/carts/mine/billing-address" method="GET"> @@ -495,15 +513,6 @@ <parameter name="cartId" force="true">%cart_id%</parameter> </data> </route> - <route url="/V1/carts/mine/addresses" method="POST"> - <service class="Magento\Quote\Api\AddressDetailsManagementInterface" method="saveAddresses"/> - <resources> - <resource ref="self" /> - </resources> - <data> - <parameter name="cartId" force="true">%cart_id%</parameter> - </data> - </route> <!-- Managing Cart Order --> <route url="/V1/carts/:cartId/order" method="PUT"> diff --git a/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php b/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php index 30b6fccb13435e396ce06d6383768b301f0f399c..8b325bb2a0ad1b0a5695bf54864496effbed60ba 100644 --- a/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php +++ b/app/code/Magento/Reports/Block/Adminhtml/Sales/Grid/Column/Renderer/Date.php @@ -37,31 +37,20 @@ class Date extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Date { $format = $this->getColumn()->getFormat(); if (!$format) { - if (self::$_format === null) { - try { - $formats = (new DataBundle())->get( - $this->_localeResolver->getLocale() - )['calendar']['gregorian']['availableFormats']; - - switch ($this->getColumn()->getPeriodType()) { - case 'month': - self::$_format = $formats['yM']; - break; - - case 'year': - self::$_format = $formats['y']; - break; - - default: - self::$_format = $this->_localeDate->getDateFormat( - \IntlDateFormatter::MEDIUM - ); - break; - } - } catch (\Exception $e) { - } + $dataBundle = new DataBundle(); + $resourceBundle = $dataBundle->get($this->_localeResolver->getLocale()); + $formats = $resourceBundle['calendar']['gregorian']['availableFormats']; + switch ($this->getColumn()->getPeriodType()) { + case 'month': + $format = $formats['yM']; + break; + case 'year': + $format = $formats['y']; + break; + default: + $format = $this->_localeDate->getDateFormat(\IntlDateFormatter::MEDIUM); + break; } - $format = self::$_format; } return $format; } @@ -74,51 +63,22 @@ class Date extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Date */ public function render(\Magento\Framework\Object $row) { - //@todo: check this logic manually if ($data = $row->getData($this->getColumn()->getIndex())) { switch ($this->getColumn()->getPeriodType()) { case 'month': - $dateFormat = 'yyyy-MM'; + $data = $data . '-01'; break; case 'year': - $dateFormat = 'yyyy'; - break; - default: - $dateFormat = \Magento\Framework\Stdlib\DateTime::DATE_INTERNAL_FORMAT; + $data = $data . '-01-01'; break; } - $format = $this->_getFormat(); - try { - $data = $this->getColumn()->getGmtoffset() - ? \IntlDateFormatter::formatObject( - $this->_localeDate->date(new \DateTime($data)), - $format - ) - : \IntlDateFormatter::formatObject( - $this->_localeDate->date( - new \DateTime($data), - null, - false - ), - $format - ); - } catch (\Exception $e) { - $data = $this->getColumn()->getTimezone() - ? \IntlDateFormatter::formatObject( - $this->_localeDate->date(new \DateTime($data)), - $format - ) - : \IntlDateFormatter::formatObject( - $this->_localeDate->date( - new \DateTime($data), - null, - false - ), - $format - ); + if ($this->getColumn()->getGmtoffset() || $this->getColumn()->getTimezone()) { + $date = $this->_localeDate->date(new \DateTime($data)); + } else { + $date = $this->_localeDate->date(new \DateTime($data), null, false); } - return $data; + return \IntlDateFormatter::formatObject($date, $format); } return $this->getColumn()->getDefault(); } diff --git a/app/code/Magento/Reports/Model/Resource/Customer/Collection.php b/app/code/Magento/Reports/Model/Resource/Customer/Collection.php index c602eb91ae9b4284b289204770089483d4879ffe..637f593308083813a3e0f89cac78e612279d76a1 100644 --- a/app/code/Magento/Reports/Model/Resource/Customer/Collection.php +++ b/app/code/Magento/Reports/Model/Resource/Customer/Collection.php @@ -81,6 +81,7 @@ class Collection extends \Magento\Customer\Model\Resource\Customer\Collection * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory * @param \Magento\Eav\Model\Resource\Helper $resourceHelper * @param \Magento\Framework\Validator\UniversalFactory $universalFactory + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Framework\Object\Copy\Config $fieldsetConfig * @param \Magento\Quote\Model\QuoteRepository $quoteRepository * @param \Magento\Quote\Model\Resource\Quote\Item\CollectionFactory $quoteItemFactory @@ -100,6 +101,7 @@ class Collection extends \Magento\Customer\Model\Resource\Customer\Collection \Magento\Eav\Model\EntityFactory $eavEntityFactory, \Magento\Eav\Model\Resource\Helper $resourceHelper, \Magento\Framework\Validator\UniversalFactory $universalFactory, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\Object\Copy\Config $fieldsetConfig, \Magento\Quote\Model\QuoteRepository $quoteRepository, \Magento\Quote\Model\Resource\Quote\Item\CollectionFactory $quoteItemFactory, @@ -117,6 +119,7 @@ class Collection extends \Magento\Customer\Model\Resource\Customer\Collection $eavEntityFactory, $resourceHelper, $universalFactory, + $entitySnapshot, $fieldsetConfig, $connection, $modelName diff --git a/app/code/Magento/Reports/Model/Resource/Order/Collection.php b/app/code/Magento/Reports/Model/Resource/Order/Collection.php index 07c2e2aa8c4a76d1d262f38904d52b00ea622f99..97294fb8ddd9371e270a9dde67709910fbe56696 100644 --- a/app/code/Magento/Reports/Model/Resource/Order/Collection.php +++ b/app/code/Magento/Reports/Model/Resource/Order/Collection.php @@ -72,7 +72,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Collection * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Framework\DB\Helper $coreResourceHelper * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -89,7 +89,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Collection \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\DB\Helper $coreResourceHelper, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Store\Model\StoreManagerInterface $storeManager, diff --git a/app/code/Magento/Reports/Model/Resource/Quote/Collection.php b/app/code/Magento/Reports/Model/Resource/Quote/Collection.php index c83ab61da03371c03db533b27a46a4ad88c82205..ccad3cf8f4e8c37eabe56bc75897674dc820dd2c 100644 --- a/app/code/Magento/Reports/Model/Resource/Quote/Collection.php +++ b/app/code/Magento/Reports/Model/Resource/Quote/Collection.php @@ -17,6 +17,7 @@ class Collection extends \Magento\Quote\Model\Resource\Quote\Collection * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Customer\Model\Resource\Customer $customerResource * @param \Zend_Db_Adapter_Abstract $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource @@ -26,11 +27,20 @@ class Collection extends \Magento\Quote\Model\Resource\Quote\Collection \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Customer\Model\Resource\Customer $customerResource, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null ) { - parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource); + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $entitySnapshot, + $connection, + $resource + ); $this->customerResource = $customerResource; } diff --git a/app/code/Magento/Reports/Test/Unit/Block/Adminhtml/Sales/Grid/Column/Renderer/DateTest.php b/app/code/Magento/Reports/Test/Unit/Block/Adminhtml/Sales/Grid/Column/Renderer/DateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6252d53d0382924f42e5af294791de18e333c88a --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Block/Adminhtml/Sales/Grid/Column/Renderer/DateTest.php @@ -0,0 +1,145 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Block\Adminhtml\Sales\Grid\Column\Renderer; + +use Magento\Reports\Block\Adminhtml\Sales\Grid\Column\Renderer\Date; + +class DateTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Reports\Block\Adminhtml\Sales\Grid\Column\Renderer\Date + */ + protected $date; + + /** + * @var \Magento\Backend\Block\Context|\PHPUnit_Framework_MockObject_MockObject + */ + protected $contextMock; + + /** + * @var \Magento\Framework\Locale\ResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $resolverMock; + + /** + * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $localeDate; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + $this->localeDate = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\TimezoneInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->localeDate + ->expects($this->once()) + ->method('date') + ->will($this->returnArgument(0)); + + $this->contextMock = $this->getMockBuilder('Magento\Backend\Block\Context') + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock + ->expects($this->once()) + ->method('getLocaleDate') + ->will($this->returnValue($this->localeDate)); + + $this->resolverMock = $this->getMockBuilder('Magento\Framework\Locale\ResolverInterface') + ->getMock(); + + $this->date = new Date( + $this->contextMock, + $this->resolverMock + ); + } + + /** + * @param string $data + * @param string $index + * @param string $locale + * @param string $period + * @param string $result + * @dataProvider datesDataProvider + * @return void + */ + public function testRender($data, $index, $locale, $period, $result) + { + $this->resolverMock->expects($this->any())->method('getLocale')->will($this->returnValue($locale)); + $this->localeDate->expects($this->any())->method('getDateFormat')->willReturnCallback( + function ($value) use ($locale) { + return (new \IntlDateFormatter( + $locale, + $value, + \IntlDateFormatter::NONE + ))->getPattern(); + } + ); + + $objectMock = $this->getMockBuilder('Magento\Framework\Object') + ->setMethods(['getData']) + ->getMock(); + $objectMock->expects($this->once())->method('getData')->will($this->returnValue($data)); + + $columnMock = $this->getMockBuilder('Magento\Backend\Block\Widget\Grid\Column') + ->disableOriginalConstructor() + ->setMethods(['getIndex', 'getPeriodType']) + ->getMock(); + $columnMock->expects($this->once())->method('getIndex')->will($this->returnValue($index)); + $columnMock->expects($this->atLeastOnce())->method('getPeriodType')->will($this->returnValue($period)); + + $this->date->setColumn($columnMock); + + $this->assertEquals($result, $this->date->render($objectMock)); + } + + /** + * @return array + */ + public function datesDataProvider() + { + return [ + [ + 'data' => '2000', + 'index' => 'period', + 'locale' => 'en_US', + 'period' => 'year', + 'result' => '2000' + ], + [ + 'data' => '2030', + 'index' => 'period', + 'locale' => 'en_US', + 'period' => 'year', + 'result' => '2030' + ], + [ + 'data' => '2000-01', + 'index' => 'period', + 'locale' => 'en_US', + 'period' => 'month', + 'result' => '1/2000' + ], + [ + 'data' => '2030-12', + 'index' => 'period', + 'locale' => 'en_US', + 'period' => 'month', + 'result' => '12/2030' + ], + [ + 'data' => '2014-06-25', + 'index' => 'period', + 'locale' => 'en_US', + 'period' => 'day', + 'result' => 'Jun 25, 2014' + ] + ]; + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/AbstractControllerTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/AbstractControllerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a15c7a139132cb978a52ca934612c946427bb8aa --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/AbstractControllerTest.php @@ -0,0 +1,133 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report; + +/** + * @SuppressWarnings(PHPMD.NumberOfChildren) + */ +abstract class AbstractControllerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject + */ + protected $contextMock; + + /** + * @var \Magento\Framework\App\Response\Http\FileFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fileFactoryMock; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $requestMock; + + /** + * @var \Magento\Framework\App\ViewInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $viewMock; + + /** + * @var \Magento\Framework\View\LayoutInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $layoutMock; + + /** + * @var \Magento\Framework\View\Element\BlockInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $breadcrumbsBlockMock; + + /** + * @var \Magento\Framework\View\Element\BlockInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $menuBlockMock; + + /** + * @var \Magento\Framework\View\Element\BlockInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $switcherBlockMock; + + /** + * @var \Magento\Backend\Model\Menu|\PHPUnit_Framework_MockObject_MockObject + */ + protected $menuModelMock; + + /** + * @var \Magento\Framework\View\Element\AbstractBlock|\PHPUnit_Framework_MockObject_MockObject + */ + protected $abstractBlockMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + $this->requestMock = $this->getMockForAbstractClassBuilder( + 'Magento\Framework\App\RequestInterface', + ['isDispatched', 'initForward', 'setDispatched', 'isForwarded'] + ); + $this->breadcrumbsBlockMock = $this->getMockForAbstractClassBuilder( + 'Magento\Framework\View\Element\BlockInterface', + ['addLink'] + ); + $this->menuBlockMock = $this->getMockForAbstractClassBuilder( + 'Magento\Framework\View\Element\BlockInterface', + ['setActive', 'getMenuModel'] + ); + $this->viewMock = $this->getMockForAbstractClassBuilder( + 'Magento\Framework\App\ViewInterface' + ); + + $this->layoutMock = $this->getMockBuilder('Magento\Framework\View\LayoutInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->switcherBlockMock = $this->getMockBuilder('Magento\Framework\View\Element\BlockInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder('Magento\Backend\App\Action\Context') + ->disableOriginalConstructor() + ->getMock(); + $this->fileFactoryMock = $this->getMockBuilder('Magento\Framework\App\Response\Http\FileFactory') + ->disableOriginalConstructor() + ->getMock(); + $this->menuModelMock = $this->getMockBuilder('Magento\Backend\Model\Menu') + ->disableOriginalConstructor() + ->getMock(); + $this->abstractBlockMock = $this->getMockBuilder('Magento\Framework\View\Element\AbstractBlock') + ->setMethods(['getCsvFile', 'getExcelFile', 'setSaveParametersInSession', 'getCsv', 'getExcel']) + ->disableOriginalConstructor() + ->getMock(); + + $this->menuModelMock->expects($this->any())->method('getParentItems')->willReturn([]); + $this->menuBlockMock->expects($this->any())->method('getMenuModel')->willReturn($this->menuModelMock); + $this->viewMock->expects($this->any())->method('getLayout')->willReturn($this->layoutMock); + $this->contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock); + $this->contextMock->expects($this->any())->method('getView')->willReturn($this->viewMock); + + $this->layoutMock->expects($this->any())->method('getBlock')->will( + $this->returnValueMap( + [ + ['breadcrumbs', $this->breadcrumbsBlockMock], + ['menu', $this->menuBlockMock], + ['store_switcher', $this->switcherBlockMock] + ] + ) + ); + $this->layoutMock->expects($this->any())->method('getChildBlock')->willReturn($this->abstractBlockMock); + } + + /** + * Custom mock for abstract class + * @param string $className + * @param array $mockedMethods + * @return \PHPUnit_Framework_MockObject_MockObject + */ + protected function getMockForAbstractClassBuilder($className, $mockedMethods = []) + { + return $this->getMockForAbstractClass($className, [], '', false, false, true, $mockedMethods); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/AccountsTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/AccountsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c6267c7192f74a912a2ba6be23c7b5e3108fe473 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/AccountsTest.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\Accounts; +use Magento\Framework\Object; +use Magento\Framework\Phrase; + +class AccountsTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\Accounts + */ + protected $accounts; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->accounts = new Accounts( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $titleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->disableOriginalConstructor() + ->getMock(); + $titleMock + ->expects($this->once()) + ->method('prepend') + ->with(new Phrase('New Accounts Report')); + + $this->viewMock + ->expects($this->any()) + ->method('getPage') + ->willReturn( + new Object( + ['config' => new Object( + ['title' => $titleMock] + )] + ) + ); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->with('Magento_Reports::report_customers_accounts'); + $this->breadcrumbsBlockMock + ->expects($this->at(0)) + ->method('addLink') + ->with(new Phrase('Reports'), new Phrase('Reports')); + $this->breadcrumbsBlockMock + ->expects($this->at(1)) + ->method('addLink') + ->with(new Phrase('Customers'), new Phrase('Customers')); + $this->breadcrumbsBlockMock + ->expects($this->at(2)) + ->method('addLink') + ->with(new Phrase('New Accounts'), new Phrase('New Accounts')); + $this->accounts->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportAccountsCsvTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportAccountsCsvTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c5e9ccccf6d933966c1802fe34a2c0fdf2c6c885 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportAccountsCsvTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\ExportAccountsCsv; + +class ExportAccountsCsvTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\ExportAccountsCsv + */ + protected $exportAccountsCsv; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->exportAccountsCsv = new ExportAccountsCsv( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->abstractBlockMock + ->expects($this->once()) + ->method('getCsvFile') + ->willReturn(['export']); + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export'); + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('new_accounts.csv', ['export'], \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + $this->exportAccountsCsv->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportAccountsExcelTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportAccountsExcelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..98134d20ccd9edc52fa27958a60c437657c1756c --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportAccountsExcelTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\ExportAccountsExcel; + +class ExportAccountsExcelTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\ExportAccountsExcel + */ + protected $exportAccountsExcel; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->exportAccountsExcel = new ExportAccountsExcel( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->abstractBlockMock + ->expects($this->once()) + ->method('getExcelFile') + ->willReturn(['export']); + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export'); + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('new_accounts.xml', ['export'], \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + $this->exportAccountsExcel->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportOrdersCsvTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportOrdersCsvTest.php new file mode 100644 index 0000000000000000000000000000000000000000..573720a1859cd759ca99ba03f9ec0b93252904f4 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportOrdersCsvTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\ExportOrdersCsv; + +class ExportOrdersCsvTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\ExportOrdersCsv + */ + protected $exportOrdersCsv; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->exportOrdersCsv = new ExportOrdersCsv( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->abstractBlockMock + ->expects($this->once()) + ->method('getCsvFile') + ->willReturn(['export']); + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export'); + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('customers_orders.csv', ['export'], \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + $this->exportOrdersCsv->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportOrdersExcelTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportOrdersExcelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b8273becb2d66d0a3636e6514a37f77c599e87d9 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportOrdersExcelTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\ExportOrdersExcel; + +class ExportOrdersExcelTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\ExportOrdersExcel + */ + protected $exportOrdersExcel; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->exportOrdersExcel = new ExportOrdersExcel( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->abstractBlockMock + ->expects($this->once()) + ->method('getExcelFile') + ->willReturn(['export']); + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export'); + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('customers_orders.xml', ['export'], \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + $this->exportOrdersExcel->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportTotalsCsvTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportTotalsCsvTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b4a7a0c68e2d2872f7e04a4a655eb614c5d72893 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportTotalsCsvTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\ExportTotalsCsv; + +class ExportTotalsCsvTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\ExportTotalsCsv + */ + protected $exportTotalsCsv; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->exportTotalsCsv = new ExportTotalsCsv( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->abstractBlockMock + ->expects($this->once()) + ->method('getCsvFile') + ->willReturn(['export']); + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export'); + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('customer_totals.csv', ['export'], \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + $this->exportTotalsCsv->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportTotalsExcelTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportTotalsExcelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..33177c27a183fbd6aa03e6e8f208190dc43a433d --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/ExportTotalsExcelTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\ExportTotalsExcel; + +class ExportTotalsExcelTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\ExportTotalsExcel + */ + protected $exportTotalsExcel; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->exportTotalsExcel = new ExportTotalsExcel( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->abstractBlockMock + ->expects($this->once()) + ->method('getExcelFile') + ->willReturn(['export']); + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export'); + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('customer_totals.xml', ['export'], \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + $this->exportTotalsExcel->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/OrdersTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/OrdersTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9e58897f7458dc46882a9e5b1aa5288e71f60748 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/OrdersTest.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\Orders; +use Magento\Framework\Object; +use Magento\Framework\Phrase; + +class OrdersTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\Orders + */ + protected $orders; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->orders = new Orders( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $titleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->disableOriginalConstructor() + ->getMock(); + $titleMock + ->expects($this->once()) + ->method('prepend') + ->with(new Phrase('Order Count Report')); + + $this->viewMock + ->expects($this->any()) + ->method('getPage') + ->willReturn( + new Object( + ['config' => new Object( + ['title' => $titleMock] + )] + ) + ); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->with('Magento_Reports::report_customers_orders'); + $this->breadcrumbsBlockMock + ->expects($this->at(0)) + ->method('addLink') + ->with(new Phrase('Reports'), new Phrase('Reports')); + $this->breadcrumbsBlockMock + ->expects($this->at(1)) + ->method('addLink') + ->with(new Phrase('Customers'), new Phrase('Customers')); + $this->breadcrumbsBlockMock + ->expects($this->at(2)) + ->method('addLink') + ->with(new Phrase('Customers by Number of Orders'), new Phrase('Customers by Number of Orders')); + $this->orders->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/TotalsTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/TotalsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bf63f966292f16cd203897e72f8abb7b672593f6 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Customer/TotalsTest.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Customer; + +use Magento\Reports\Controller\Adminhtml\Report\Customer\Totals; +use Magento\Framework\Object; +use Magento\Framework\Phrase; + +class TotalsTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Customer\Totals + */ + protected $totals; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->totals = new Totals( + $this->contextMock, + $this->fileFactoryMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $titleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->disableOriginalConstructor() + ->getMock(); + $titleMock + ->expects($this->once()) + ->method('prepend') + ->with(new Phrase('Order Total Report')); + + $this->viewMock + ->expects($this->any()) + ->method('getPage') + ->willReturn( + new Object( + ['config' => new Object( + ['title' => $titleMock] + )] + ) + ); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->with('Magento_Reports::report_customers_totals'); + $this->breadcrumbsBlockMock + ->expects($this->at(0)) + ->method('addLink') + ->with(new Phrase('Reports'), new Phrase('Reports')); + $this->breadcrumbsBlockMock + ->expects($this->at(1)) + ->method('addLink') + ->with(new Phrase('Customers'), new Phrase('Customers')); + $this->breadcrumbsBlockMock + ->expects($this->at(2)) + ->method('addLink') + ->with(new Phrase('Customers by Orders Total'), new Phrase('Customers by Orders Total')); + $this->totals->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/DownloadsTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/DownloadsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e7e1ada266c5a9545c4b965a12c8604c0d446257 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/DownloadsTest.php @@ -0,0 +1,90 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\Downloads; +use Magento\Framework\Object; +use Magento\Framework\Phrase; + +class DownloadsTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\Downloads + */ + protected $downloads; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->downloads = new Downloads( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $titleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->disableOriginalConstructor() + ->getMock(); + + $titleMock + ->expects($this->once()) + ->method('prepend') + ->with(new Phrase('Downloads Report')); + + $this->viewMock + ->expects($this->once()) + ->method('getPage') + ->willReturn( + new Object( + ['config' => new Object( + ['title' => $titleMock] + )] + ) + ); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->with('Magento_Downloadable::report_products_downloads'); + + $this->breadcrumbsBlockMock + ->expects($this->exactly(3)) + ->method('addLink') + ->withConsecutive( + [new Phrase('Reports'), new Phrase('Reports')], + [new Phrase('Products'), new Phrase('Products')], + [new Phrase('Downloads'), new Phrase('Downloads')] + ); + + $this->layoutMock + ->expects($this->once()) + ->method('createBlock') + ->with('Magento\Reports\Block\Adminhtml\Product\Downloads') + ->willReturn($this->abstractBlockMock); + + $this->downloads->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportDownloadsCsvTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportDownloadsCsvTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6d693599b8f92dd48c21f8be673ff7a5efc16001 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportDownloadsCsvTest.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportDownloadsCsv; + +class ExportDownloadsCsvTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportDownloadsCsv + */ + protected $exportDownloadsCsv; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->exportDownloadsCsv = new ExportDownloadsCsv( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('setSaveParametersInSession') + ->willReturnSelf(); + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getCsv') + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('createBlock') + ->with('Magento\Reports\Block\Adminhtml\Product\Downloads\Grid') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('products_downloads.csv', $content); + + $this->exportDownloadsCsv->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportDownloadsExcelTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportDownloadsExcelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9b10f29b369590a8e2d154bb59abb2007fe34aa7 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportDownloadsExcelTest.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportDownloadsExcel; + +class ExportDownloadsExcelTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportDownloadsExcel + */ + protected $exportDownloadsExcel; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->exportDownloadsExcel = new ExportDownloadsExcel( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + $fileName = 'products_downloads.xml'; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('setSaveParametersInSession') + ->willReturnSelf(); + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getExcel') + ->with($fileName) + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('createBlock') + ->with('Magento\Reports\Block\Adminhtml\Product\Downloads\Grid') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with($fileName, $content); + + $this->exportDownloadsExcel->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportLowstockCsvTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportLowstockCsvTest.php new file mode 100644 index 0000000000000000000000000000000000000000..010a123afc7e3e61d5ac8c541f0292bd94dd7cdf --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportLowstockCsvTest.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportLowstockCsv; + +class ExportLowstockCsvTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportLowstockCsv + */ + protected $exportLowstockCsv; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->exportLowstockCsv = new ExportLowstockCsv( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getCsvFile') + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.block.report.product.lowstock.grid', 'grid.export') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('products_lowstock.csv', $content, \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + + $this->exportLowstockCsv->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportLowstockExcelTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportLowstockExcelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..257b08e7bcbf44e47b5a855985482908b593af1d --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportLowstockExcelTest.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportLowstockExcel; + +class ExportLowstockExcelTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportLowstockExcel + */ + protected $exportLowstockExcel; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->exportLowstockExcel = new ExportLowstockExcel( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getExcelFile') + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.block.report.product.lowstock.grid', 'grid.export') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('products_lowstock.xml', $content, \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + + $this->exportLowstockExcel->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportSoldCsvTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportSoldCsvTest.php new file mode 100644 index 0000000000000000000000000000000000000000..54d5303ad317e706fa733fe13c7208a8d09d6a7d --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportSoldCsvTest.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportSoldCsv; + +class ExportSoldCsvTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportSoldCsv + */ + protected $exportSoldCsv; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->exportSoldCsv = new ExportSoldCsv( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getCsvFile') + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('products_ordered.csv', $content, \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + + $this->exportSoldCsv->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportSoldExcelTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportSoldExcelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..cec703d778b347b536444ac4dafa1fa1937feb4f --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportSoldExcelTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportSoldExcel; + +class ExportSoldExcelTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportSoldExcel + */ + protected $exportSoldExcel; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->exportSoldExcel = new ExportSoldExcel( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + $fileName = 'products_ordered.xml'; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getExcelFile') + ->with($fileName) + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('getChildBlock') + ->with('adminhtml.report.grid', 'grid.export') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with($fileName, $content, \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + + $this->exportSoldExcel->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportViewedCsvTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportViewedCsvTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d1e4cafbf627af407b1470049d4b81a76c510009 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportViewedCsvTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportViewedCsv; + +class ExportViewedCsvTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportViewedCsv + */ + protected $exportViewedCsv; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $objectManagerMock; + + /** + * @var \Magento\Backend\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + */ + protected $helperMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->helperMock = $this->getMockBuilder('Magento\Backend\Helper\Data') + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManagerInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerMock + ->expects($this->any()) + ->method('get') + ->willReturn($this->helperMock); + + $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); + + $this->exportViewedCsv = new ExportViewedCsv( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + $fileName = 'products_mostviewed.csv'; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getCsvFile') + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('createBlock') + ->with('Magento\Reports\Block\Adminhtml\Product\Viewed\Grid') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with($fileName, $content, \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + + $this->exportViewedCsv->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportViewedExcelTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportViewedExcelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..93c68d3ff695049a73d6f7df11a93d2c6ce2092f --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ExportViewedExcelTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\ExportViewedExcel; + +class ExportViewedExcelTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\ExportViewedExcel + */ + protected $exportViewedExcel; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $objectManagerMock; + + /** + * @var \Magento\Backend\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + */ + protected $helperMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->helperMock = $this->getMockBuilder('Magento\Backend\Helper\Data') + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManagerInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerMock + ->expects($this->any()) + ->method('get') + ->willReturn($this->helperMock); + + $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); + + $this->exportViewedExcel = new ExportViewedExcel( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $content = ['export']; + $fileName = 'products_mostviewed.xml'; + + $this->abstractBlockMock + ->expects($this->once()) + ->method('getExcelFile') + ->with($fileName) + ->willReturn($content); + + $this->layoutMock + ->expects($this->once()) + ->method('createBlock') + ->with('Magento\Reports\Block\Adminhtml\Product\Viewed\Grid') + ->willReturn($this->abstractBlockMock); + + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with($fileName, $content, \Magento\Framework\App\Filesystem\DirectoryList::VAR_DIR); + + $this->exportViewedExcel->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/LowstockTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/LowstockTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6120128d828fb902d8a10c9cc5956dd14d67e33d --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/LowstockTest.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\Lowstock; +use Magento\Framework\Object; +use Magento\Framework\Phrase; + +class LowstockTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\Lowstock + */ + protected $lowstock; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->lowstock = new Lowstock( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $titleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->disableOriginalConstructor() + ->getMock(); + + $titleMock + ->expects($this->once()) + ->method('prepend') + ->with(new Phrase('Low Stock Report')); + + $this->viewMock + ->expects($this->once()) + ->method('getPage') + ->willReturn( + new Object( + ['config' => new Object( + ['title' => $titleMock] + )] + ) + ); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->with('Magento_Reports::report_products_lowstock'); + + $this->breadcrumbsBlockMock + ->expects($this->exactly(3)) + ->method('addLink') + ->withConsecutive( + [new Phrase('Reports'), new Phrase('Reports')], + [new Phrase('Products'), new Phrase('Products')], + [new Phrase('Low Stock'), new Phrase('Low Stock')] + ); + + $this->lowstock->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/SoldTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/SoldTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0b1b27e748e88f47ade203433a846b7360566c4b --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/SoldTest.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\Sold; +use Magento\Framework\Object; +use Magento\Framework\Phrase; + +class SoldTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\Sold + */ + protected $sold; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $this->sold = new Sold( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $titleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->disableOriginalConstructor() + ->getMock(); + + $titleMock + ->expects($this->once()) + ->method('prepend') + ->with(new Phrase('Ordered Products Report')); + + $this->viewMock + ->expects($this->once()) + ->method('getPage') + ->willReturn( + new Object( + ['config' => new Object( + ['title' => $titleMock] + )] + ) + ); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->with('Magento_Reports::report_products_sold'); + + $this->breadcrumbsBlockMock + ->expects($this->exactly(3)) + ->method('addLink') + ->withConsecutive( + [new Phrase('Reports'), new Phrase('Reports')], + [new Phrase('Products'), new Phrase('Products')], + [new Phrase('Products Ordered'), new Phrase('Products Ordered')] + ); + + $this->sold->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ViewedTest.php b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ViewedTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0d87c428b3933a214d1d16fb68058e37007a5728 --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Controller/Adminhtml/Report/Product/ViewedTest.php @@ -0,0 +1,223 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Reports\Test\Unit\Controller\Adminhtml\Report\Product; + +use Magento\Reports\Controller\Adminhtml\Report\Product\Viewed; +use Magento\Framework\Object; +use Magento\Framework\Phrase; + +class ViewedTest extends \Magento\Reports\Test\Unit\Controller\Adminhtml\Report\AbstractControllerTest +{ + /** + * @var \Magento\Reports\Controller\Adminhtml\Report\Product\Viewed + */ + protected $viewed; + + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date|\PHPUnit_Framework_MockObject_MockObject + */ + protected $dateMock; + + /** + * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $objectManagerMock; + + /** + * @var \Magento\Backend\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + */ + protected $helperMock; + + /** + * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $messageManagerMock; + + /** + * {@inheritDoc} + */ + protected function setUp() + { + parent::setUp(); + + $this->dateMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime\Filter\Date') + ->disableOriginalConstructor() + ->getMock(); + + $flagMock = $this->getMockBuilder('Magento\Reports\Model\Flag') + ->disableOriginalConstructor() + ->getMock(); + $flagMock + ->expects($this->any()) + ->method('setReportFlagCode') + ->willReturnSelf(); + $flagMock + ->expects($this->any()) + ->method('loadSelf') + ->willReturnSelf(); + + $this->helperMock = $this->getMockBuilder('Magento\Backend\Helper\Data') + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManagerInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerMock + ->expects($this->any()) + ->method('create') + ->with('Magento\Reports\Model\Flag') + ->willReturn($flagMock); + + $this->messageManagerMock = $this->getMockBuilder('Magento\Framework\Message\ManagerInterface') + ->disableOriginalConstructor() + ->getMock(); + + $flagMock = $this->getMockBuilder('Magento\Framework\App\ActionFlag') + ->disableOriginalConstructor() + ->getMock(); + + $responseMock = $this->getMockBuilder('Magento\Framework\App\ResponseInterface') + ->disableOriginalConstructor() + ->setMethods(['setRedirect', 'sendResponse']) + ->getMock(); + + $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); + $this->contextMock->expects($this->any())->method('getHelper')->willReturn($this->helperMock); + $this->contextMock->expects($this->any())->method('getMessageManager')->willReturn($this->messageManagerMock); + $this->contextMock->expects($this->any())->method('getActionFlag')->willReturn($flagMock); + $this->contextMock->expects($this->any())->method('getResponse')->willReturn($responseMock); + + $this->viewed = new Viewed( + $this->contextMock, + $this->fileFactoryMock, + $this->dateMock + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->objectManagerMock + ->expects($this->any()) + ->method('get') + ->willReturn($this->helperMock); + + $titleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->disableOriginalConstructor() + ->getMock(); + + $titleMock + ->expects($this->once()) + ->method('prepend') + ->with(new Phrase('Product Views Report')); + + $this->viewMock + ->expects($this->once()) + ->method('getPage') + ->willReturn( + new Object( + ['config' => new Object( + ['title' => $titleMock] + )] + ) + ); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->with('Magento_Reports::report_products_viewed'); + + $this->breadcrumbsBlockMock + ->expects($this->exactly(3)) + ->method('addLink') + ->withConsecutive( + [new Phrase('Reports'), new Phrase('Reports')], + [new Phrase('Products'), new Phrase('Products')], + [new Phrase('Products Most Viewed Report'), new Phrase('Products Most Viewed Report')] + ); + + $this->viewMock + ->expects($this->once()) + ->method('renderLayout'); + + $this->viewed->execute(); + } + + /** + * @return void + */ + public function testExecuteWithException() + { + $errorText = new Phrase( + 'An error occurred while showing the product views report. ' . + 'Please review the log and try again.' + ); + + $logMock = $this->getMockBuilder('Psr\Log\LoggerInterface') + ->disableOriginalConstructor() + ->getMock(); + + $sessionMock = $this->getMockBuilder('Magento\Backend\Model\Session') + ->setMethods(['setIsUrlNotice']) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock + ->expects($this->any()) + ->method('get') + ->will( + $this->returnValueMap( + [ + ['Psr\Log\LoggerInterface', $logMock], + ['Magento\Backend\Model\Auth\Session', $sessionMock] + ] + ) + ); + + $this->messageManagerMock + ->expects($this->once()) + ->method('addError') + ->with($errorText); + + $logMock + ->expects($this->once()) + ->method('critical'); + $sessionMock + ->expects($this->once()) + ->method('setIsUrlNotice'); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->willThrowException(new \Exception()); + + $this->viewed->execute(); + } + + /** + * @return void + */ + public function testExecuteWithLocalizedException() + { + $errorText = new Phrase('Error'); + + $this->messageManagerMock + ->expects($this->once()) + ->method('addError') + ->with($errorText); + + $this->menuBlockMock + ->expects($this->once()) + ->method('setActive') + ->willThrowException(new \Magento\Framework\Exception\LocalizedException($errorText)); + + $this->viewed->execute(); + } +} diff --git a/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php b/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php index 22a6bb1be49c2719d81af2339c7feef95295a195..b2414a6b388de779cec6e34ce0a06527085f9996 100644 --- a/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php +++ b/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php @@ -102,7 +102,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase ->getMock(); $this->managerMock = $this->getMockBuilder('Magento\Framework\Event\ManagerInterface') ->getMock(); - $this->entitySnapshotMock = $this->getMockBuilder('Magento\Sales\Model\Resource\EntitySnapshot') + $this->entitySnapshotMock = $this->getMockBuilder('Magento\Framework\Model\Resource\Db\VersionControl\Snapshot') ->disableOriginalConstructor() ->getMock(); $this->helperMock = $this->getMockBuilder('Magento\Framework\DB\Helper') diff --git a/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php b/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php index a8bea7e05133cba46c465b46f3d6e9f170559d3c..3f24f1a6d7e7be362ab20453647af0c9dd6c7952 100644 --- a/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php +++ b/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php @@ -42,6 +42,11 @@ class CollectionTest extends \PHPUnit_Framework_TestCase */ protected $entityFactoryMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot + */ + protected $entitySnapshotMock; + protected function setUp() { $this->selectMock = $this->getMockBuilder('Magento\Framework\DB\Select') @@ -81,6 +86,10 @@ class CollectionTest extends \PHPUnit_Framework_TestCase $this->entityFactoryMock = $this->getMockBuilder('Magento\Framework\Data\Collection\EntityFactory') ->disableOriginalConstructor() ->getMock(); + $this->entitySnapshotMock = $this->getMockBuilder('Magento\Framework\Model\Resource\Db\VersionControl\Snapshot') + ->disableOriginalConstructor() + ->setMethods(['registerSnapshot']) + ->getMock(); $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $helper->getObject( @@ -89,7 +98,8 @@ class CollectionTest extends \PHPUnit_Framework_TestCase 'customerResource' => $this->customerResourceMock, 'resource' => $this->resourceMock, 'fetchStrategy' => $this->fetchStrategyMock, - 'entityFactory' => $this->entityFactoryMock + 'entityFactory' => $this->entityFactoryMock, + 'entitySnapshot' => $this->entitySnapshotMock ] ); } @@ -154,7 +164,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase ->withAnyParameters() ->willReturn($customerId); - $itemMock = $this->getMockBuilder('Magento\Framework\Object') + $itemMock = $this->getMockBuilder('Magento\Framework\Model\AbstractModel') ->disableOriginalConstructor() ->getMock(); $itemMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Model/AbstractModel.php b/app/code/Magento/Sales/Model/AbstractModel.php index 9f409bcbd76bb2dfacf96116b06584e6c70d12b3..e018d84d95c2d6b3674ea63b5961d925b08d91e2 100644 --- a/app/code/Magento/Sales/Model/AbstractModel.php +++ b/app/code/Magento/Sales/Model/AbstractModel.php @@ -45,16 +45,6 @@ abstract class AbstractModel extends AbstractExtensibleModel ); } - /** - * Returns _eventPrefix - * - * @return string - */ - public function getEventPrefix() - { - return $this->_eventPrefix; - } - /** * Returns _eventObject * diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index d0c564c01bf619a5babab63eefe194733eb8242c..56d1c892985da5d8423381fa5d9080be6de2564c 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -373,6 +373,28 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt return false; } + /** + * Returns assigned invoice + * + * @return Invoice|null + */ + public function getInvoice() + { + return $this->getData('invoice'); + } + + /** + * Sets invoice + * + * @param Invoice $invoice + * @return $this + */ + public function setInvoice(Invoice $invoice) + { + $this->setData('invoice', $invoice); + return $this; + } + /** * Check creditmemo cancel action availability * diff --git a/app/code/Magento/Sales/Model/Order/Payment.php b/app/code/Magento/Sales/Model/Order/Payment.php index 6ecf8a298cd1a663af73808e5c79eb6b664d458a..269f9e0187798ed74eb919d31c88b6aada5a6bd5 100644 --- a/app/code/Magento/Sales/Model/Order/Payment.php +++ b/app/code/Magento/Sales/Model/Order/Payment.php @@ -186,6 +186,40 @@ class Payment extends Info implements OrderPaymentInterface return $this->_order; } + /** + * Sets transaction id for current payment + * + * @param string $transactionId + * @return $this + */ + public function setTransactionId($transactionId) + { + $this->setData('transaction_id', $transactionId); + return $this; + } + + /** + * Sets transaction close flag + * + * @param bool $isClosed + * @return $this + */ + public function setIsTransactionClosed($isClosed) + { + $this->setData('is_transaction_closed', (bool)$isClosed); + return $this; + } + + /** + * Returns transaction parent + * + * @return string + */ + public function getParentTransactionId() + { + return $this->getData('parent_transaction_id'); + } + /** * Check order payment capture action availability * @@ -655,6 +689,30 @@ class Payment extends Info implements OrderPaymentInterface return $this->_void(false, $amount); } + /** + * Sets creditmemo for current payment + * + * @param Creditmemo $creditmemo + * @return $this + */ + public function setCreditmemo(Creditmemo $creditmemo) + { + $this->setData('creditmemo', $creditmemo); + return $this; + } + + /** + * Returns Creditmemo assigned for this payment + * + * @return Creditmemo|null + */ + public function getCreditmemo() + { + return $this->getData('creditmemo') instanceof Creditmemo + ? $this->getData('creditmemo') + : null; + } + /** * Refund payment online or offline, depending on whether there is invoice set in the creditmemo instance * Updates transactions hierarchy, if required diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 5d7a2efedd93f35bca87d852441edc3c1ac5e07a..40d528fbeb8d5fec707f059b6cb5e7a77c0c6bcc 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -614,8 +614,12 @@ class Transaction extends AbstractModel implements TransactionInterface { $this->_verifyThisTransactionExists(); if (null === $this->_paymentObject && $shouldLoad) { + /** @var \Magento\Sales\Model\Order\Payment $payment */ $payment = $this->_paymentFactory->create()->load($this->getPaymentId()); if ($payment->getId()) { + if (!$payment->getOrder()) { + $payment->setOrder($this->getOrder()); + } $this->setOrderPaymentObject($payment); } } diff --git a/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php b/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php index b0e4edf8dd32d65c367b71a823f16dca05c47219..d32dc6ee981c70f1d498d27d15ac04fb7f507d87 100644 --- a/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php +++ b/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php @@ -9,41 +9,13 @@ namespace Magento\Sales\Model\Resource\Collection; * Flat sales abstract collection * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -abstract class AbstractCollection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +abstract class AbstractCollection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection { /** * @var \Zend_Db_Select */ protected $_countSelect; - /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot - */ - protected $entitySnapshot; - - /** - * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory - * @param \Psr\Log\LoggerInterface $logger - * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy - * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot - * @param string|null $connection - * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource - * @throws \Zend_Exception - */ - public function __construct( - \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory, - \Psr\Log\LoggerInterface $logger, - \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, - \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, - $connection = null, - \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null - ) { - $this->entitySnapshot = $entitySnapshot; - parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource); - } - /** * Set select count sql * @@ -233,63 +205,4 @@ abstract class AbstractCollection extends \Magento\Framework\Model\Resource\Db\C { return $this; } - - /** - * Returns a collection item that corresponds to the fetched row - * and moves the internal data pointer ahead - * All returned rows marked as non changed to prevent unnecessary persistence operations - * - * @return \Magento\Framework\Object|bool - */ - public function fetchItem() - { - if (null === $this->_fetchStmt) { - $this->_renderOrders()->_renderLimit(); - - $this->_fetchStmt = $this->getConnection()->query($this->getSelect()); - } - $data = $this->_fetchStmt->fetch(); - if (!empty($data) && is_array($data)) { - /**@var \Magento\Sales\Model\AbstractModel $item */ - $item = $this->getNewEmptyItem(); - if ($this->getIdFieldName()) { - $item->setIdFieldName($this->getIdFieldName()); - } - $item->setData($data); - $this->entitySnapshot->registerSnapshot($item); - return $item; - } - return false; - } - - /** - * Load data with filter in place - * All returned rows marked as non changed to prevent unnecessary persistence operations - * - * @param bool $printQuery - * @param bool $logQuery - * @return $this - */ - public function loadWithFilter($printQuery = false, $logQuery = false) - { - $this->_beforeLoad(); - $this->_renderFilters()->_renderOrders()->_renderLimit(); - $this->printLogQuery($printQuery, $logQuery); - $data = $this->getData(); - $this->resetData(); - if (is_array($data)) { - foreach ($data as $row) { - $item = $this->getNewEmptyItem(); - if ($this->getIdFieldName()) { - $item->setIdFieldName($this->getIdFieldName()); - } - $item->setData($row); - $this->entitySnapshot->registerSnapshot($item); - $this->addItem($item); - } - } - $this->_setIsLoaded(); - $this->_afterLoad(); - return $this; - } } diff --git a/app/code/Magento/Sales/Model/Resource/EntityAbstract.php b/app/code/Magento/Sales/Model/Resource/EntityAbstract.php index 44989d28a214cc6f2531e7313591ac3d9bf27d68..b095ebf88a3ae1d73b0e28d07b9eceabc06d3d3b 100644 --- a/app/code/Magento/Sales/Model/Resource/EntityAbstract.php +++ b/app/code/Magento/Sales/Model/Resource/EntityAbstract.php @@ -5,9 +5,11 @@ */ namespace Magento\Sales\Model\Resource; -use Magento\Framework\Model\Resource\Db\AbstractDb; -use Magento\Sales\Model\EntityInterface; +use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\SalesSequence\Model\Manager; +use Magento\Sales\Model\EntityInterface; /** * Abstract sales entity provides to its children knowledge about eventPrefix and eventObject @@ -47,46 +49,33 @@ abstract class EntityAbstract extends AbstractDb */ protected $attribute; - /** * @var Manager */ protected $sequenceManager; - /** - * @var EntitySnapshot - */ - protected $entitySnapshot; - - /** - * @var EntityRelationComposite - */ - protected $entityRelationComposite; - /** * @param \Magento\Framework\Model\Resource\Db\Context $context + * @param Snapshot $entitySnapshot + * @param RelationComposite $entityRelationComposite * @param Attribute $attribute * @param Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param EntityRelationComposite $entityRelationComposite * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + RelationComposite $entityRelationComposite, \Magento\Sales\Model\Resource\Attribute $attribute, Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - EntityRelationComposite $entityRelationComposite, $resourcePrefix = null ) { $this->attribute = $attribute; $this->sequenceManager = $sequenceManager; - $this->entitySnapshot = $entitySnapshot; - $this->entityRelationComposite = $entityRelationComposite; if ($resourcePrefix === null) { $resourcePrefix = 'sales'; } - parent::__construct($context, $resourcePrefix); + parent::__construct($context, $entitySnapshot, $entityRelationComposite, $resourcePrefix); } /** @@ -171,83 +160,39 @@ abstract class EntityAbstract extends AbstractDb } /** - * Perform actions after object delete - * - * @param \Magento\Framework\Model\AbstractModel $object - * @return $this + * @inheritdoc */ - protected function _afterDelete(\Magento\Framework\Model\AbstractModel $object) + protected function updateObject(\Magento\Framework\Model\AbstractModel $object) { - parent::_afterDelete($object); - return $this; + $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId()); + $data = $this->_prepareDataForSave($object); + unset($data[$this->getIdFieldName()]); + $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition); } /** - * Perform actions after object load, mark loaded data as data without changes - * - * @param \Magento\Framework\Model\AbstractModel|\Magento\Framework\Object $object - * @return $this - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ - protected function _afterLoad(\Magento\Framework\Model\AbstractModel $object) + protected function saveNewObject(\Magento\Framework\Model\AbstractModel $object) { - $this->entitySnapshot->registerSnapshot($object); - return $this; + $bind = $this->_prepareDataForSave($object); + unset($bind[$this->getIdFieldName()]); + $this->_getWriteAdapter()->insert($this->getMainTable(), $bind); + $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable())); + if ($this->_useIsObjectNew) { + $object->isObjectNew(false); + } } /** - * Save entity + * Perform actions after object delete * * @param \Magento\Framework\Model\AbstractModel $object * @return $this - * @throws \Exception */ - public function save(\Magento\Framework\Model\AbstractModel $object) + protected function _afterDelete(\Magento\Framework\Model\AbstractModel $object) { - if ($object->isDeleted()) { - return $this->delete($object); - } - if (!$this->entitySnapshot->isModified($object)) { - $this->entityRelationComposite->processRelations($object); - return $this; - } - $this->beginTransaction(); - - try { - $object->validateBeforeSave(); - $object->beforeSave(); - if ($object->isSaveAllowed()) { - $this->_serializeFields($object); - $this->_beforeSave($object); - $this->_checkUnique($object); - $this->objectRelationProcessor->validateDataIntegrity($this->getMainTable(), $object->getData()); - if ($object->getId() !== null && (!$this->_useIsObjectNew || !$object->isObjectNew())) { - $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId()); - $data = $this->_prepareDataForSave($object); - unset($data[$this->getIdFieldName()]); - $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition); - } else { - $bind = $this->_prepareDataForSave($object); - unset($bind[$this->getIdFieldName()]); - $this->_getWriteAdapter()->insert($this->getMainTable(), $bind); - $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable())); - if ($this->_useIsObjectNew) { - $object->isObjectNew(false); - } - } - $this->unserializeFields($object); - $this->_afterSave($object); - $this->entitySnapshot->registerSnapshot($object); - $object->afterSave(); - $this->entityRelationComposite->processRelations($object); - } - $this->addCommitCallback([$object, 'afterCommitCallback'])->commit(); - $object->setHasDataChanges(false); - } catch (\Exception $e) { - $this->rollBack(); - $object->setHasDataChanges(true); - throw $e; - } + parent::_afterDelete($object); return $this; } } diff --git a/app/code/Magento/Sales/Model/Resource/EntityMetadata.php b/app/code/Magento/Sales/Model/Resource/EntityMetadata.php deleted file mode 100644 index d39a9a63cb5ab9b25dd11321a01a4dbdbb8560ab..0000000000000000000000000000000000000000 --- a/app/code/Magento/Sales/Model/Resource/EntityMetadata.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Sales\Model\Resource; - -use Magento\Sales\Model\AbstractModel; - -/** - * Class EntityMetadata represents a list of entity fields that are applicable for persistence operations - */ -class EntityMetadata -{ - /** - * @var array - */ - protected $metadataInfo = []; - - /** - * Returns list of entity fields that are applicable for persistence operations - * - * @param AbstractModel $entity - * @return array - * @throws \Magento\Framework\Exception\LocalizedException - */ - public function getFields(AbstractModel $entity) - { - if (!isset($this->metadataInfo[get_class($entity)])) { - $this->metadataInfo[get_class($entity)] = - $entity->getResource()->getReadConnection()->describeTable( - $entity->getResource()->getMainTable() - ); - } - return $this->metadataInfo[get_class($entity)]; - } -} diff --git a/app/code/Magento/Sales/Model/Resource/EntityRelationInterface.php b/app/code/Magento/Sales/Model/Resource/EntityRelationInterface.php deleted file mode 100644 index 72d26e580e8dff1b8940b82ca4433c5cfa27e69f..0000000000000000000000000000000000000000 --- a/app/code/Magento/Sales/Model/Resource/EntityRelationInterface.php +++ /dev/null @@ -1,21 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Sales\Model\Resource; - -/** - * Interface EntityRelationInterface - */ -interface EntityRelationInterface -{ - /** - * Process object relations - * - * @param \Magento\Sales\Model\AbstractModel $object - * @return void - */ - public function processRelation(\Magento\Sales\Model\AbstractModel $object); -} diff --git a/app/code/Magento/Sales/Model/Resource/EntitySnapshot.php b/app/code/Magento/Sales/Model/Resource/EntitySnapshot.php deleted file mode 100644 index 47a008445ebf5f3807944a1115a39d5d72f86c87..0000000000000000000000000000000000000000 --- a/app/code/Magento/Sales/Model/Resource/EntitySnapshot.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Sales\Model\Resource; - -use Magento\Framework\Model\AbstractModel; - -/** - * Class EntitySnapshot register snapshot of entity data, for tracking changes - */ -class EntitySnapshot -{ - /** - * Array of snapshots of entities data - * - * @var array - */ - protected $snapshotData = []; - - /** - * @var EntityMetadata - */ - protected $entityMetadata; - - /** - * Initialization - * - * @param EntityMetadata $entityMetadata - */ - public function __construct( - EntityMetadata $entityMetadata - ) { - $this->entityMetadata = $entityMetadata; - } - - /** - * Register snapshot of entity data, for tracking changes - * - * @param AbstractModel $entity - * @return void - */ - public function registerSnapshot(AbstractModel $entity) - { - $data = array_intersect_key($entity->getData(), $this->entityMetadata->getFields($entity)); - $this->snapshotData[get_class($entity)][$entity->getId()] = $data; - } - - /** - * Check is current entity has changes, by comparing current object state with stored snapshot - * - * @param AbstractModel $entity - * @return bool - */ - public function isModified(AbstractModel $entity) - { - if (!$entity->getId()) { - return true; - } - if (!isset($this->snapshotData[get_class($entity)][$entity->getId()])) { - return true; - } - $data = array_intersect_key($entity->getData(), $this->entityMetadata->getFields($entity)); - if ($data !== $this->snapshotData[get_class($entity)][$entity->getId()]) { - return true; - } - return false; - } -} diff --git a/app/code/Magento/Sales/Model/Resource/Order.php b/app/code/Magento/Sales/Model/Resource/Order.php index 24b205c079d7266f3f010806d039466e25f2b25c..f44ca611da317a9068111add4782c16dec481591 100644 --- a/app/code/Magento/Sales/Model/Resource/Order.php +++ b/app/code/Magento/Sales/Model/Resource/Order.php @@ -11,6 +11,8 @@ use Magento\SalesSequence\Model\Manager; use Magento\Sales\Model\Resource\EntityAbstract as SalesResource; use Magento\Sales\Model\Resource\Order\Handler\State as StateHandler; use Magento\Sales\Model\Spi\OrderResourceInterface; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; /** * Flat sales order resource @@ -53,27 +55,27 @@ class Order extends SalesResource implements OrderResourceInterface * @param \Magento\Framework\Model\Resource\Db\Context $context * @param Attribute $attribute * @param Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param EntityRelationComposite $entityRelationComposite + * @param Snapshot $entitySnapshot + * @param RelationComposite $entityRelationComposite * @param StateHandler $stateHandler * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + RelationComposite $entityRelationComposite, Attribute $attribute, Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - EntityRelationComposite $entityRelationComposite, StateHandler $stateHandler, $resourcePrefix = null ) { $this->stateHandler = $stateHandler; parent::__construct( $context, - $attribute, - $sequenceManager, $entitySnapshot, $entityRelationComposite, + $attribute, + $sequenceManager, $resourcePrefix ); } @@ -138,8 +140,6 @@ class Order extends SalesResource implements OrderResourceInterface */ protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object) { - /** @var \Magento\Sales\Model\Order $object */ - $this->stateHandler->check($object); if (!$object->getId()) { /** @var \Magento\Store\Model\Store $store */ $store = $object->getStore(); @@ -161,4 +161,14 @@ class Order extends SalesResource implements OrderResourceInterface } return parent::_beforeSave($object); } + + /** + * {@inheritdoc} + */ + public function save(\Magento\Framework\Model\AbstractModel $object) + { + /** @var \Magento\Sales\Model\Order $object */ + $this->stateHandler->check($object); + return parent::save($object); + } } diff --git a/app/code/Magento/Sales/Model/Resource/Order/Address.php b/app/code/Magento/Sales/Model/Resource/Order/Address.php index 878bfdf6a8ad9fd6bbf30f71642c3f6fe8bf64d1..760895576385ec3fd42c8598f2f34e9e590bba1a 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Address.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Address.php @@ -7,7 +7,7 @@ namespace Magento\Sales\Model\Resource\Order; use Magento\Sales\Model\Resource\EntityAbstract as SalesResource; use Magento\Sales\Model\Spi\OrderAddressResourceInterface; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; /** * Flat sales order address resource @@ -35,18 +35,18 @@ class Address extends SalesResource implements OrderAddressResourceInterface * @param \Magento\Framework\Model\Resource\Db\Context $context * @param \Magento\Sales\Model\Resource\Attribute $attribute * @param \Magento\SalesSequence\Model\Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite + * @param Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite * @param \Magento\Sales\Model\Order\Address\Validator $validator * @param \Magento\Sales\Model\Resource\GridPool $gridPool * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Sales\Model\Resource\Attribute $attribute, \Magento\SalesSequence\Model\Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite, \Magento\Sales\Model\Order\Address\Validator $validator, \Magento\Sales\Model\Resource\GridPool $gridPool, $resourcePrefix = null @@ -55,10 +55,10 @@ class Address extends SalesResource implements OrderAddressResourceInterface $this->gridPool = $gridPool; parent::__construct( $context, - $attribute, - $sequenceManager, $entitySnapshot, $entityRelationComposite, + $attribute, + $sequenceManager, $resourcePrefix ); } diff --git a/app/code/Magento/Sales/Model/Resource/Order/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Collection.php index 4254242321fa2c11b6bf60fb819bc2c74a6ce615..2e68417ba67ee7523c848d233c6634f4101d51b8 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Collection.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Collection.php @@ -39,7 +39,7 @@ class Collection extends AbstractCollection implements OrderSearchResultInterfac * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Framework\DB\Helper $coreResourceHelper * @param string|null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource @@ -49,7 +49,7 @@ class Collection extends AbstractCollection implements OrderSearchResultInterfac \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\DB\Helper $coreResourceHelper, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php index f0a5c4d693428efed1a537f29db22df1af9758cb..255d4cd4388f1c67652a252c1737b57bd23f6890 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php @@ -9,7 +9,7 @@ use Magento\Framework\App\Resource as AppResource; use Magento\SalesSequence\Model\Manager; use Magento\Sales\Model\Resource\Attribute; use Magento\Sales\Model\Resource\EntityAbstract as SalesResource; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\CreditmemoResourceInterface; /** diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php index 3056759346691ebb39edfbd90f0cbb5adb160382..304677688895668a68a1650f1a24ef9dbec0bfdd 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php @@ -6,7 +6,7 @@ namespace Magento\Sales\Model\Resource\Order\Creditmemo; use Magento\Sales\Model\Resource\EntityAbstract; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\CreditmemoCommentResourceInterface; /** @@ -34,27 +34,27 @@ class Comment extends EntityAbstract implements CreditmemoCommentResourceInterfa * @param \Magento\Framework\Model\Resource\Db\Context $context * @param \Magento\Sales\Model\Resource\Attribute $attribute * @param \Magento\SalesSequence\Model\Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite + * @param Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite * @param \Magento\Sales\Model\Order\Creditmemo\Comment\Validator $validator * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Sales\Model\Resource\Attribute $attribute, \Magento\SalesSequence\Model\Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite, \Magento\Sales\Model\Order\Creditmemo\Comment\Validator $validator, $resourcePrefix = null ) { $this->validator = $validator; parent::__construct( $context, - $attribute, - $sequenceManager, $entitySnapshot, $entityRelationComposite, + $attribute, + $sequenceManager, $resourcePrefix ); } diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php index 85eeb520f00038005fc02d39303e096723775948..c24cfddac98ab0f1e998c390ed099e04a8518234 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php @@ -23,7 +23,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Creditmemo\Grid\Col * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param \Magento\Framework\Registry $registryManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource */ @@ -32,7 +32,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Creditmemo\Grid\Col \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\Registry $registryManager, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php index 674e9552b7ae54cc956fa539c09ed3fef49e1933..6aabb91138517a7696271fc16063a1fea8876789 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php @@ -6,12 +6,12 @@ namespace Magento\Sales\Model\Resource\Order\Creditmemo; -use Magento\Sales\Model\Resource\EntityRelationInterface; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface; /** * Class Relation */ -class Relation implements EntityRelationInterface +class Relation implements RelationInterface { /** * @var Item @@ -38,11 +38,11 @@ class Relation implements EntityRelationInterface /** * Process relations for CreditMemo * - * @param \Magento\Sales\Model\AbstractModel $object + * @param \Magento\Framework\Model\AbstractModel $object * @throws \Exception * @return void */ - public function processRelation(\Magento\Sales\Model\AbstractModel $object) + public function processRelation(\Magento\Framework\Model\AbstractModel $object) { /** @var \Magento\Sales\Model\Order\Creditmemo $object */ if (null !== $object->getItems()) { diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice.php index 6fb7504394cf8f3c813089146dbeb577b19cb448..33a095ce60c66d85b5ff05d8e4c4c8ec4568f7ed 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Invoice.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice.php @@ -9,7 +9,7 @@ use Magento\Framework\App\Resource; use Magento\SalesSequence\Model\Manager; use Magento\Sales\Model\Resource\Attribute; use Magento\Sales\Model\Resource\EntityAbstract as SalesResource; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\InvoiceResourceInterface; /** diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php index f54208f1e5d5d11edc3ea35408223a2423752ea0..ad15a0a99dfd38d804ad68c407a63726512d4d75 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php @@ -6,7 +6,7 @@ namespace Magento\Sales\Model\Resource\Order\Invoice; use Magento\Sales\Model\Resource\EntityAbstract; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\InvoiceCommentResourceInterface; /** @@ -34,27 +34,27 @@ class Comment extends EntityAbstract implements InvoiceCommentResourceInterface * @param \Magento\Framework\Model\Resource\Db\Context $context * @param \Magento\Sales\Model\Resource\Attribute $attribute * @param \Magento\SalesSequence\Model\Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite + * @param Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite * @param \Magento\Sales\Model\Order\Invoice\Comment\Validator $validator * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Sales\Model\Resource\Attribute $attribute, \Magento\SalesSequence\Model\Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite, \Magento\Sales\Model\Order\Invoice\Comment\Validator $validator, $resourcePrefix = null ) { $this->validator = $validator; parent::__construct( $context, - $attribute, - $sequenceManager, $entitySnapshot, $entityRelationComposite, + $attribute, + $sequenceManager, $resourcePrefix ); } diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php index 6f6d71c655ebb10c595db011e3f5777c6e1a1754..2a79e1c08d2575123511f230b5270453baec11da 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php @@ -17,7 +17,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Invoice\Grid\Collec * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Framework\Registry $registryManager * @param null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource @@ -27,7 +27,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Invoice\Grid\Collec \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\Registry $registryManager, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php index 80f10e6adbaad2b6d2a61cdbfd17d9f2223ca2ec..b2da74d1d74333752376e0e0df64f2f99ad75a24 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php @@ -6,14 +6,14 @@ namespace Magento\Sales\Model\Resource\Order\Invoice; -use Magento\Sales\Model\Resource\EntityRelationInterface; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface; use Magento\Sales\Model\Resource\Order\Invoice\Item as InvoiceItemResource; use Magento\Sales\Model\Resource\Order\Invoice\Comment as InvoiceCommentResource; /** * Class Relation */ -class Relation implements EntityRelationInterface +class Relation implements RelationInterface { /** * @var InvoiceItemResource @@ -40,11 +40,11 @@ class Relation implements EntityRelationInterface /** * Process relations for Shipment * - * @param \Magento\Sales\Model\AbstractModel $object + * @param \Magento\Framework\Model\AbstractModel $object * @return void * @throws \Exception */ - public function processRelation(\Magento\Sales\Model\AbstractModel $object) + public function processRelation(\Magento\Framework\Model\AbstractModel $object) { /** @var $object \Magento\Sales\Model\Order\Invoice */ if (null !== $object->getItems()) { diff --git a/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php index 8f73ee346165a646e8e8939bcdae16d6d64256b4..284dd3dc81937a4b7da960ff0a90abb074481e4b 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php @@ -32,7 +32,7 @@ class Collection extends AbstractCollection implements OrderPaymentSearchResultI * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource */ @@ -41,7 +41,7 @@ class Collection extends AbstractCollection implements OrderPaymentSearchResultI \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null ) { diff --git a/app/code/Magento/Sales/Model/Resource/Order/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Relation.php index 749de294fe06d4057c2a990d875821bc5e45840c..f832d285383280a67360c2ea6e28066beac0e6b9 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Relation.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Relation.php @@ -6,9 +6,8 @@ namespace Magento\Sales\Model\Resource\Order; -use Magento\Sales\Model\AbstractModel; use Magento\Sales\Model\Resource\Order\Handler\Address as AddressHandler; -use Magento\Sales\Model\Resource\EntityRelationInterface; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface; use Magento\Sales\Model\Resource\Order\Item as OrderItemResource; use Magento\Sales\Model\Resource\Order\Payment as OrderPaymentResource; use Magento\Sales\Model\Resource\Order\Status\History as OrderStatusHistoryResource; @@ -16,7 +15,7 @@ use Magento\Sales\Model\Resource\Order\Status\History as OrderStatusHistoryResou /** * Class Relation */ -class Relation implements EntityRelationInterface +class Relation implements RelationInterface { /** * @var AddressHandler @@ -59,11 +58,11 @@ class Relation implements EntityRelationInterface /** * Save relations for Order * - * @param AbstractModel $object + * @param \Magento\Framework\Model\AbstractModel $object * @return void * @throws \Exception */ - public function processRelation(AbstractModel $object) + public function processRelation(\Magento\Framework\Model\AbstractModel $object) { /** @var \Magento\Sales\Model\Order $object */ $this->addressHandler->removeEmptyAddresses($object); diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment.php index 8fe7b8afa972e655edfcaed864336d697ef0791f..32293e81802cc33e1a738ce2acd867b88117d82b 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Shipment.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment.php @@ -9,7 +9,7 @@ use Magento\Framework\App\Resource as AppResource; use Magento\SalesSequence\Model\Manager; use Magento\Sales\Model\Resource\Attribute; use Magento\Sales\Model\Resource\EntityAbstract as SalesResource; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Resource\Order\Shipment\Grid as ShipmentGrid; use Magento\Sales\Model\Spi\ShipmentResourceInterface; diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php index 0379873ee76fb01c21ce4b02d95cec43c174406d..f77505a9fe208524ac4ffe094226b3f528ecf1cd 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php @@ -6,7 +6,7 @@ namespace Magento\Sales\Model\Resource\Order\Shipment; use Magento\Sales\Model\Resource\EntityAbstract; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\ShipmentCommentResourceInterface; /** @@ -34,27 +34,27 @@ class Comment extends EntityAbstract implements ShipmentCommentResourceInterface * @param \Magento\Framework\Model\Resource\Db\Context $context * @param \Magento\Sales\Model\Resource\Attribute $attribute * @param \Magento\SalesSequence\Model\Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite + * @param Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite * @param \Magento\Sales\Model\Order\Shipment\Comment\Validator $validator * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Sales\Model\Resource\Attribute $attribute, \Magento\SalesSequence\Model\Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite, \Magento\Sales\Model\Order\Shipment\Comment\Validator $validator, $resourcePrefix = null ) { $this->validator = $validator; parent::__construct( $context, - $attribute, - $sequenceManager, $entitySnapshot, $entityRelationComposite, + $attribute, + $sequenceManager, $resourcePrefix ); } diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php index ae31f67f65deb94365871772b991d45ebcebf9f0..d61ea0fbd7c82fb0455ffe6d5c502be45f0a4afe 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php @@ -22,7 +22,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Shipment\Grid\Colle * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Framework\Registry $registryManager * @param null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource @@ -32,7 +32,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Shipment\Grid\Colle \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\Registry $registryManager, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php index 8d25d48c40e2195d5dcb1c14e82c3b1e050eba28..32efe9ad52732e700ddb73b33e6968e75c7a7f4a 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php @@ -6,7 +6,7 @@ namespace Magento\Sales\Model\Resource\Order\Shipment; -use Magento\Sales\Model\Resource\EntityRelationInterface; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface; use Magento\Sales\Model\Resource\Order\Shipment\Item as ShipmentItemResource; use Magento\Sales\Model\Resource\Order\Shipment\Comment as ShipmentCommentResource; use Magento\Sales\Model\Resource\Order\Shipment\Track as ShipmentTrackResource; @@ -14,7 +14,7 @@ use Magento\Sales\Model\Resource\Order\Shipment\Track as ShipmentTrackResource; /** * Class Relation */ -class Relation implements EntityRelationInterface +class Relation implements RelationInterface { /** * @var ShipmentItemResource @@ -49,11 +49,11 @@ class Relation implements EntityRelationInterface /** * Process relations for Shipment * - * @param \Magento\Sales\Model\AbstractModel $object + * @param \Magento\Framework\Model\AbstractModel $object * @return void * @throws \Exception */ - public function processRelation(\Magento\Sales\Model\AbstractModel $object) + public function processRelation(\Magento\Framework\Model\AbstractModel $object) { /** @var \Magento\Sales\Model\Order\Shipment $object */ if (null !== $object->getItems()) { diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php index 07dfa2beb992ecc46df47024df476e44e5ab70bd..6db8bf2ee10496a2716e0cbd707dc46b5d040911 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php @@ -6,7 +6,7 @@ namespace Magento\Sales\Model\Resource\Order\Shipment; use Magento\Sales\Model\Resource\EntityAbstract as SalesResource; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\ShipmentTrackResourceInterface; /** @@ -34,27 +34,27 @@ class Track extends SalesResource implements ShipmentTrackResourceInterface * @param \Magento\Framework\Model\Resource\Db\Context $context * @param \Magento\Sales\Model\Resource\Attribute $attribute * @param \Magento\SalesSequence\Model\Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite + * @param Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite * @param \Magento\Sales\Model\Order\Shipment\Track\Validator $validator * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Sales\Model\Resource\Attribute $attribute, \Magento\SalesSequence\Model\Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite, \Magento\Sales\Model\Order\Shipment\Track\Validator $validator, $resourcePrefix = null ) { $this->validator = $validator; parent::__construct( $context, - $attribute, - $sequenceManager, $entitySnapshot, $entityRelationComposite, + $attribute, + $sequenceManager, $resourcePrefix ); } diff --git a/app/code/Magento/Sales/Model/Resource/Order/Status.php b/app/code/Magento/Sales/Model/Resource/Order/Status.php index 6ebf0702bb9eb87d96a082a47c702619052edcfc..b28a95f490823a288fb89a33ee0eb5d045e33b51 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Status.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Status.php @@ -10,14 +10,14 @@ use Psr\Log\LoggerInterface as LogWriter; use Magento\Framework\Exception\LocalizedException; use Magento\SalesSequence\Model\Manager; use \Magento\Sales\Model\Resource\EntityAbstract; -use \Magento\Sales\Model\Resource\EntitySnapshot; +use \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; /** * Order status resource model * * @author Magento Core Team <core@magentocommerce.com> */ -class Status extends \Magento\Framework\Model\Resource\Db\AbstractDb +class Status extends \Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb { /** * Status labels table diff --git a/app/code/Magento/Sales/Model/Resource/Order/Status/History.php b/app/code/Magento/Sales/Model/Resource/Order/Status/History.php index 8c13fdef8880954947e7c6c6f26f0d7b98b6cc22..2dbf7cc79946d97159b0dc71f069007f353196c7 100644 --- a/app/code/Magento/Sales/Model/Resource/Order/Status/History.php +++ b/app/code/Magento/Sales/Model/Resource/Order/Status/History.php @@ -7,7 +7,7 @@ namespace Magento\Sales\Model\Resource\Order\Status; use Magento\Sales\Model\Order\Status\History\Validator; use Magento\Sales\Model\Resource\EntityAbstract; -use Magento\Sales\Model\Resource\EntitySnapshot; +use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\OrderStatusHistoryResourceInterface; /** @@ -26,27 +26,27 @@ class History extends EntityAbstract implements OrderStatusHistoryResourceInterf * @param \Magento\Framework\Model\Resource\Db\Context $context * @param \Magento\Sales\Model\Resource\Attribute $attribute * @param \Magento\SalesSequence\Model\Manager $sequenceManager - * @param EntitySnapshot $entitySnapshot - * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite + * @param Snapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite * @param Validator $validator * @param string $resourcePrefix */ public function __construct( \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite, \Magento\Sales\Model\Resource\Attribute $attribute, \Magento\SalesSequence\Model\Manager $sequenceManager, - EntitySnapshot $entitySnapshot, - \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite, Validator $validator, $resourcePrefix = null ) { $this->validator = $validator; parent::__construct( $context, - $attribute, - $sequenceManager, $entitySnapshot, $entityRelationComposite, + $attribute, + $sequenceManager, $resourcePrefix ); } diff --git a/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php index 9bd3c5d4aac539ad12d462d2d4c3100be3328703..f58c41554af1cde9e63f7597945889fd9313aebd 100644 --- a/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php +++ b/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php @@ -20,7 +20,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Payment\Transaction * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy * @param \Magento\Framework\Event\ManagerInterface $eventManager - * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot + * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot * @param \Magento\Framework\Registry $registryManager * @param null $connection * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource @@ -30,7 +30,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Payment\Transaction \Psr\Log\LoggerInterface $logger, \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot, + \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot, \Magento\Framework\Registry $registryManager, $connection = null, \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php index 85d167520a3bbdff1809a69a82a284f79c76be32..fd9d023735b57c1bcdccb2f6d4b1deba2829b12f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php @@ -46,7 +46,7 @@ class AddressTest extends \PHPUnit_Framework_TestCase protected $gridPoolMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; @@ -95,7 +95,7 @@ class AddressTest extends \PHPUnit_Framework_TestCase false ); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php index cb90e1429574daec837ab14470e58f5685eb192f..f5f43992bf9bfbd7ec5ab2cb15b7dd15edeab04b 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php @@ -35,7 +35,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase */ protected $validatorMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; @@ -73,7 +73,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase false ); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php index 307b36d867efaf5e2d92b2b1c2bd54fb00147493..5348b94492ff3539e979d7ba852719aad2c52407 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php @@ -35,7 +35,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase */ protected $validatorMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; @@ -73,7 +73,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase false ); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php index bc6d3793a0621a69cc068d564fb0c267c1bdee8c..d397e2d7b79c109b19f2932c51c5905a48ba8e4f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php @@ -35,7 +35,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase */ protected $validatorMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; @@ -73,7 +73,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase false ); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php index d9c4b184b6c3812fa386c4489fc7e13f4504f55d..6a10d12526840f0147931793c476602254b646f4 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php @@ -35,7 +35,7 @@ class TrackTest extends \PHPUnit_Framework_TestCase */ protected $validatorMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; @@ -73,7 +73,7 @@ class TrackTest extends \PHPUnit_Framework_TestCase false ); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php index 7d0dc3b50ec512812807269d2ef8ae59763f95a1..e3222511a2389b3cd7fe4d56621ca4d346d16c0f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php @@ -48,7 +48,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase */ protected $entityFactoryMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; @@ -59,7 +59,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase $this->selectMock = $this->getMock('Zend_Db_Select', [], [], '', false); $this->historyItemMock = $this->getMock( 'Magento\Sales\Model\Order\Status\History', - ['__wakeup', 'setData'], + ['__wakeup', 'addData'], [], '', false @@ -74,7 +74,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase ['getReadConnection', 'getMainTable', 'getTable', '__wakeup'] ); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', @@ -97,7 +97,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase $data = [['data']]; $this->historyItemMock->expects($this->once()) - ->method('setData') + ->method('addData') ->with($this->equalTo($data[0])) ->will($this->returnValue($this->historyItemMock)); diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php index eced486c174c08fccd775c5540d6f16a6b34c624..0dfcf1e512a5ad94cc26535d148777901b1a42b5 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php @@ -37,7 +37,7 @@ class HistoryTest extends \PHPUnit_Framework_TestCase protected $validatorMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; @@ -65,7 +65,7 @@ class HistoryTest extends \PHPUnit_Framework_TestCase false ); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php index 397e6b0374502cd78ccc7084e3ac7ddc8fd20dfa..647427af5956808ff1eb5505bf46ceadb7d1b23d 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php @@ -5,6 +5,7 @@ */ namespace Magento\Sales\Test\Unit\Model\Resource; +use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite; use \Magento\Sales\Model\Resource\Order; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; @@ -50,12 +51,12 @@ class OrderTest extends \PHPUnit_Framework_TestCase */ protected $adapterMock; /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject */ protected $entitySnapshotMock; /** - * @var \Magento\Sales\Model\Resource\EntityRelationComposite|\PHPUnit_Framework_MockObject_MockObject + * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject */ protected $relationCompositeMock; @@ -97,14 +98,14 @@ class OrderTest extends \PHPUnit_Framework_TestCase ); $this->salesSequenceMock = $this->getMock('Magento\SalesSequence\Model\Sequence', [], [], '', false); $this->entitySnapshotMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntitySnapshot', + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', [], [], '', false ); $this->relationCompositeMock = $this->getMock( - 'Magento\Sales\Model\Resource\EntityRelationComposite', + 'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite', [], [], '', diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml index c0aec4a0857a24fdc363ad679fc38b3a44bc7408..28ea25b9dcf30f4db415e56c8f90753867ff14be 100644 --- a/app/code/Magento/Sales/etc/di.xml +++ b/app/code/Magento/Sales/etc/di.xml @@ -220,7 +220,7 @@ <argument name="resourcePrefix" xsi:type="string">sales</argument> </arguments> </type> - <virtualType name="OrderRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite"> + <virtualType name="OrderRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> <arguments> <argument name="relationProcessors" xsi:type="array"> <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Relation</item> @@ -232,7 +232,7 @@ <argument name="entityRelationComposite" xsi:type="object">OrderRelationsComposite</argument> </arguments> </type> - <virtualType name="InvoiceRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite"> + <virtualType name="InvoiceRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> <arguments> <argument name="relationProcessors" xsi:type="array"> <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Invoice\Relation</item> @@ -244,7 +244,7 @@ <argument name="entityRelationComposite" xsi:type="object">InvoiceRelationsComposite</argument> </arguments> </type> - <virtualType name="ShipmentRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite"> + <virtualType name="ShipmentRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> <arguments> <argument name="relationProcessors" xsi:type="array"> <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Shipment\Relation</item> @@ -256,7 +256,7 @@ <argument name="entityRelationComposite" xsi:type="object">ShipmentRelationsComposite</argument> </arguments> </type> - <virtualType name="CreditmemoRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite"> + <virtualType name="CreditmemoRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite"> <arguments> <argument name="relationProcessors" xsi:type="array"> <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Creditmemo\Relation</item> diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml index 196c1d42977c1482a4793ee9fe3c320e63983286..8a4bc2971760994b04dbf9b18b4ff0a804d89130 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml @@ -14,8 +14,8 @@ store name = $_order->getStore()->getGroup()->getName() ?> <?php $_order = $block->getOrder() ?> <div> -<?php echo __('Customer Name: %1', $_order->getCustomerFirstname() ? $_order->getCustomerName() : $_order->getBillingAddress()->getName()) ?><br /> -<?php echo __('Purchased From: %1', $_order->getStore()->getGroup()->getName()) ?><br /> +<?php echo __('Customer Name: %1', $block->escapeHtml($_order->getCustomerFirstname() ? $_order->getCustomerName() : $_order->getBillingAddress()->getName())) ?><br /> +<?php echo __('Purchased From: %1', $block->escapeHtml($_order->getStore()->getGroup()->getName())) ?><br /> </div> <table cellpadding="0" border="0" width="100%" style="border:1px solid #bebcb7; background:#f8f7f5;"> <thead> diff --git a/app/code/Magento/SalesRule/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/SalesRule/view/frontend/layout/checkout_onepage_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9ba81bfaa8ec98f6f906d86cc704b184ee417ff --- /dev/null +++ b/app/code/Magento/SalesRule/view/frontend/layout/checkout_onepage_index.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="billing-step" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="children" xsi:type="array"> + <item name="payment" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="afterMethods" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="store-credit" xsi:type="array"> + <item name="component" xsi:type="string">Magento_SalesRule/js/view/payment/discount</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + <item name="summary" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="totals" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="discount" xsi:type="array"> + <item name="component" xsi:type="string">Magento_SalesRule/js/view/summary/discount</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string">Discount</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> \ No newline at end of file diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js b/app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js new file mode 100644 index 0000000000000000000000000000000000000000..80a6488fb285a34fcf91dc07693843ce731ed85f --- /dev/null +++ b/app/code/Magento/SalesRule/view/frontend/web/js/action/cancel-coupon.js @@ -0,0 +1,51 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * Customer store credit(balance) application + */ +/*global define,alert*/ +define( + [ + 'ko', + 'jquery', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/resource-url-manager', + 'Magento_Checkout/js/model/payment-service', + 'Magento_Ui/js/model/messageList', + 'mage/storage', + 'Magento_Checkout/js/action/get-totals' + ], + function (ko, $, quote, urlManager, paymentService, messageList, storage, getTotalsAction) { + 'use strict'; + return function (isApplied, isLoading) { + var quoteId = quote.getQuoteId(); + var url = urlManager.getCancelCouponUrl(quoteId); + return storage.delete( + url, + false + ).done( + function (response) { + isLoading(false); + var deferred = $.Deferred(); + + getTotalsAction([], deferred); + $.when(deferred).done(function() { + isApplied(false); + paymentService.setPaymentMethods( + paymentService.getAvailablePaymentMethods() + ); + }); + } + ).error( + function (response) { + isLoading(false); + var error = JSON.parse(response.responseText); + messageList.addErrorMessage(error); + } + ); + }; + } +); diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js b/app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js new file mode 100644 index 0000000000000000000000000000000000000000..a76500e4517208b0a166af5a7162b17ddcad9099 --- /dev/null +++ b/app/code/Magento/SalesRule/view/frontend/web/js/action/set-coupon-code.js @@ -0,0 +1,54 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * Customer store credit(balance) application + */ +/*global define,alert*/ +define( + [ + 'ko', + 'jquery', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/resource-url-manager', + 'Magento_Checkout/js/model/payment-service', + 'Magento_Ui/js/model/messageList', + 'mage/storage', + 'Magento_Checkout/js/action/get-totals' + ], + function (ko, $, quote, urlManager, paymentService, messageList, storage, getTotalsAction) { + 'use strict'; + return function (couponCode, isApplied, isLoading) { + var quoteId = quote.getQuoteId(); + var url = urlManager.getApplyCouponUrl(couponCode, quoteId); + return storage.put( + url, + {}, + false + ).done( + function (response) { + if (response) { + isLoading(false); + isApplied(true); + var deferred = $.Deferred(); + + getTotalsAction([], deferred); + $.when(deferred).done(function() { + paymentService.setPaymentMethods( + paymentService.getAvailablePaymentMethods() + ); + }); + } + } + ).error( + function (response) { + isLoading(false); + var error = JSON.parse(response.responseText); + messageList.addErrorMessage(error); + } + ); + }; + } +); diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js b/app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js new file mode 100644 index 0000000000000000000000000000000000000000..ddbce5003a402df4de8db9b23a181beed36c7a59 --- /dev/null +++ b/app/code/Magento/SalesRule/view/frontend/web/js/view/payment/discount.js @@ -0,0 +1,63 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define( + [ + 'jquery', + 'ko', + 'uiComponent', + 'Magento_Checkout/js/model/quote', + 'Magento_SalesRule/js/action/set-coupon-code', + 'Magento_SalesRule/js/action/cancel-coupon' + ], + function ($, ko, Component, quote, setCouponCodeAction, cancelCouponAction) { + 'use strict'; + var totals = quote.getTotals(); + var couponCode = ko.observable(null); + if (totals()) { + couponCode(totals()['coupon_code']); + } + var isApplied = ko.observable(couponCode() != null); + var isLoading = ko.observable(false); + return Component.extend({ + defaults: { + template: 'Magento_SalesRule/payment/discount' + }, + couponCode: couponCode, + /** + * Applied flag + */ + isApplied: isApplied, + isLoading: isLoading, + /** + * Coupon code application procedure + */ + apply: function() { + if (this.validate()) { + isLoading(true); + setCouponCodeAction(couponCode(), isApplied, isLoading); + } + }, + /** + * Cancel using coupon + */ + cancel: function() { + if (this.validate()) { + isLoading(true); + couponCode(''); + cancelCouponAction(isApplied, isLoading); + } + }, + /** + * Coupon form validation + * + * @returns {boolean} + */ + validate: function() { + var form = '#discount-form'; + return $(form).validation() && $(form).validation('isValid'); + } + }); + } +); diff --git a/app/code/Magento/SalesRule/view/frontend/web/js/view/summary/discount.js b/app/code/Magento/SalesRule/view/frontend/web/js/view/summary/discount.js new file mode 100644 index 0000000000000000000000000000000000000000..8558966cd71e5aa7af00dc70ba339179ce9d4917 --- /dev/null +++ b/app/code/Magento/SalesRule/view/frontend/web/js/view/summary/discount.js @@ -0,0 +1,39 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote', + ], + function (Component, quote) { + "use strict"; + return Component.extend({ + defaults: { + template: 'Magento_SalesRule/summary/discount' + }, + totals: quote.getTotals(), + isDisplayed: function() { + return this.isFullMode() && this.getPureValue() != 0; + }, + getCouponCode: function() { + if (!this.totals()) { + return null; + } + return this.totals()['coupon_code']; + }, + getPureValue: function() { + var price = 0; + if (this.totals() && this.totals().discount_amount) { + price = parseFloat(this.totals().discount_amount); + } + return price; + }, + getValue: function() { + return this.getFormattedPrice(this.getPureValue()); + } + }); + } +); diff --git a/app/code/Magento/SalesRule/view/frontend/web/template/payment/discount.html b/app/code/Magento/SalesRule/view/frontend/web/template/payment/discount.html new file mode 100644 index 0000000000000000000000000000000000000000..92041308eada737fc81f6ab15b7bad6e0e041e8f --- /dev/null +++ b/app/code/Magento/SalesRule/view/frontend/web/template/payment/discount.html @@ -0,0 +1,47 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="payment-option _collapsible opc-payment-additional discount-code" + data-bind="mageInit: {'collapsible':{'openedState': '_active'}}"> + <div class="payment-option-title field choice" data-role="title"> + <span class="action action-toggle" id="block-discount-heading" role="heading" aria-level="2"> + <!-- ko text: $t('Apply promo code')--><!-- /ko --> + </span> + </div> + <div class="payment-option-content" data-role="content"> + <form class="form form-discount" id="discount-form" data-bind="blockLoader: isLoading"> + <div class="payment-option-inner"> + <div class="field"> + <label class="label" for="discount-code"> + <span data-bind="text: $t('Enter promo code')"></span> + </label> + <div class="control"> + <input class="input-text" + type="text" + id="discount-code" + name="discount_code" + data-validate="{'required-entry':true}" + data-bind="value: couponCode, attr:{placeholder: $t('Enter promo code')} " /> + </div> + </div> + </div> + <div class="actions-toolbar"> + <div class="primary"> + <!-- ko ifnot: isApplied() --> + <button class="action action-apply" type="submit" data-bind="'value': $t('Apply'), click: apply"> + <span><!-- ko text: $t('Apply')--><!-- /ko --></span> + </button> + <!-- /ko --> + <!-- ko if: isApplied() --> + <button class="action action-cancel" type="submit" data-bind="'value': $t('Cancel'), click: cancel"> + <span><!-- ko text: $t('Cancel coupon')--><!-- /ko --></span> + </button> + <!-- /ko --> + </div> + </div> + </form> + </div> +</div> diff --git a/app/code/Magento/SalesRule/view/frontend/web/template/summary/discount.html b/app/code/Magento/SalesRule/view/frontend/web/template/summary/discount.html new file mode 100644 index 0000000000000000000000000000000000000000..60ac9c7982a5f6a0a510abd25fb67e4ee11dc13a --- /dev/null +++ b/app/code/Magento/SalesRule/view/frontend/web/template/summary/discount.html @@ -0,0 +1,17 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: isDisplayed() --> +<tr class="totals discount"> + <th class="mark" scope="row"> + <span class="title" data-bind="text: title"></span> + <span class="discount coupon" data-bind="text: getCouponCode()"></span> + </th> + <td class="amount"> + <span class="price" data-bind="text: getValue(), attr: {'data-th': $t(name) }"></span> + </td> +</tr> +<!-- /ko --> diff --git a/app/code/Magento/Shipping/etc/acl.xml b/app/code/Magento/Shipping/etc/acl.xml index 74811607f3d06fbc8d002fa03dc27d47a0be0f59..feacd4d501dc3da36c629f277754c456eb7f6762 100644 --- a/app/code/Magento/Shipping/etc/acl.xml +++ b/app/code/Magento/Shipping/etc/acl.xml @@ -13,6 +13,7 @@ <resource id="Magento_Backend::stores_settings"> <resource id="Magento_Config::config"> <resource id="Magento_Shipping::config_shipping" title="Shipping Settings Section" sortOrder="5" /> + <resource id="Magento_Shipping::shipping_policy" title="Shipping Policy Parameters Section" sortOrder="5" /> <resource id="Magento_Shipping::carriers" title="Shipping Methods Section" sortOrder="5" /> </resource> </resource> diff --git a/app/code/Magento/Shipping/etc/adminhtml/system.xml b/app/code/Magento/Shipping/etc/adminhtml/system.xml index 40e4568907c17aa71bd790790b3ea912932eb260..5b56b96f719b7fbd3270e7b253dab0b1f862205d 100644 --- a/app/code/Magento/Shipping/etc/adminhtml/system.xml +++ b/app/code/Magento/Shipping/etc/adminhtml/system.xml @@ -7,7 +7,7 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../Config/etc/system_file.xsd"> <system> - <section id="shipping" translate="label" type="text" sortOrder="310" showInDefault="1" showInWebsite="1" showInStore="0"> + <section id="shipping" translate="label" type="text" sortOrder="310" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Shipping Settings</label> <tab>sales</tab> <resource>Magento_Shipping::config_shipping</resource> @@ -34,6 +34,19 @@ <label>Street Address Line 2</label> </field> </group> + <group id="shipping_policy" translate="label" type="text" sortOrder="120" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Shipping Policy Parameters</label> + <field id="enable_shipping_policy" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0"> + <label>Apply custom Shipping Policy</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + </field> + <field id="shipping_policy_content" translate="label" type="textarea" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Shipping Policy</label> + <depends> + <field id="enable_shipping_policy">1</field> + </depends> + </field> + </group> </section> <section id="carriers" translate="label" type="text" sortOrder="320" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Shipping Methods</label> diff --git a/app/code/Magento/Shipping/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Shipping/view/frontend/layout/checkout_onepage_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..14a25393667d7b7bfe54cce7ba0b750f65b0cfd6 --- /dev/null +++ b/app/code/Magento/Shipping/view/frontend/layout/checkout_onepage_index.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shippingAddress" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="before-shipping-method-form" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping_policy" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Shipping/js/view/checkout/shipping/shipping-policy</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/Shipping/view/frontend/web/js/model/config.js b/app/code/Magento/Shipping/view/frontend/web/js/model/config.js new file mode 100644 index 0000000000000000000000000000000000000000..d69bd10ae7c674ea543ddd0cb30d97b567ef3056 --- /dev/null +++ b/app/code/Magento/Shipping/view/frontend/web/js/model/config.js @@ -0,0 +1,13 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define([], function () { + "use strict"; + return function () { + return window.checkoutConfig.shippingPolicy + } + } +); diff --git a/app/code/Magento/Shipping/view/frontend/web/js/view/checkout/shipping/shipping-policy.js b/app/code/Magento/Shipping/view/frontend/web/js/view/checkout/shipping/shipping-policy.js new file mode 100644 index 0000000000000000000000000000000000000000..1a41b1ae5770388c85fa13b76b3fa4abdf2689a7 --- /dev/null +++ b/app/code/Magento/Shipping/view/frontend/web/js/view/checkout/shipping/shipping-policy.js @@ -0,0 +1,18 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'uiComponent', + 'Magento_Shipping/js/model/config' + +], function (Component, config) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_Shipping/checkout/shipping/shipping-policy' + }, + config: config() + }); +}); diff --git a/app/code/Magento/Shipping/view/frontend/web/template/checkout/shipping/shipping-policy.html b/app/code/Magento/Shipping/view/frontend/web/template/checkout/shipping/shipping-policy.html new file mode 100644 index 0000000000000000000000000000000000000000..1c0cc5c80e2efc4a25ad4c7f9e52266b569bbb82 --- /dev/null +++ b/app/code/Magento/Shipping/view/frontend/web/template/checkout/shipping/shipping-policy.html @@ -0,0 +1,14 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="shipping-policy-block field-tooltip" data-bind="visible: config.isEnabled"> + <span class="field-tooltip-action"> + <!-- ko text: $t('See our shipping policy') --><!-- /ko --> + </span> + <div class="field-tooltip-content"> + <span data-bind="html: config.shippingPolicyContent"></span> + </div> +</div> diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml index c47f73ec9012bd91e4218009b662d754d6905645..1bc032018f7c8a1ff22c9c0863f1c5aaac1d62b0 100644 --- a/app/code/Magento/Store/etc/di.xml +++ b/app/code/Magento/Store/etc/di.xml @@ -23,6 +23,11 @@ <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Config</argument> </arguments> </type> + <type name="Magento\Framework\View\Element\Template\File\Validator"> + <arguments> + <argument name="scope" xsi:type="string">store</argument> + </arguments> + </type> <type name="Magento\Store\Model\Config\Reader\Website"> <arguments> <argument name="scopePool" xsi:type="object">Magento\Framework\App\Config\ScopePool\Proxy</argument> diff --git a/app/code/Magento/Tax/Api/Data/GrandTotalDetailsInterface.php b/app/code/Magento/Tax/Api/Data/GrandTotalDetailsInterface.php index 3fb1e6fd5b28ea248de75a35a11bf4336d10684c..e36af22d214c62161943940fd4e7439596ca4b56 100644 --- a/app/code/Magento/Tax/Api/Data/GrandTotalDetailsInterface.php +++ b/app/code/Magento/Tax/Api/Data/GrandTotalDetailsInterface.php @@ -3,11 +3,9 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Tax\Api\Data; - -interface GrandTotalDetailsInterface extends \Magento\Framework\Api\ExtensibleDataInterface +interface GrandTotalDetailsInterface { /** * Get tax amount value @@ -47,21 +45,4 @@ interface GrandTotalDetailsInterface extends \Magento\Framework\Api\ExtensibleDa * @return $this */ public function setGroupId($id); - - /** - * {@inheritdoc} - * - * @return \Magento\Tax\Api\Data\GrandTotalDetailsExtensionInterface|null - */ - public function getExtensionAttributes(); - - /** - * {@inheritdoc} - * - * @param \Magento\Tax\Api\Data\GrandTotalDetailsExtensionInterface $extensionAttributes - * @return $this - */ - public function setExtensionAttributes( - \Magento\Tax\Api\Data\GrandTotalDetailsExtensionInterface $extensionAttributes - ); } diff --git a/app/code/Magento/Tax/Api/Data/GrandTotalRatesInterface.php b/app/code/Magento/Tax/Api/Data/GrandTotalRatesInterface.php index f6d39a9d385d5add5389df19846d273fd42f31c9..39dda8c3536fc456bf9ac4d9d22dd9c46d9d2d22 100644 --- a/app/code/Magento/Tax/Api/Data/GrandTotalRatesInterface.php +++ b/app/code/Magento/Tax/Api/Data/GrandTotalRatesInterface.php @@ -3,11 +3,9 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Tax\Api\Data; - -interface GrandTotalRatesInterface extends \Magento\Framework\Api\ExtensibleDataInterface +interface GrandTotalRatesInterface { /** * Get tax percentage value @@ -34,21 +32,4 @@ interface GrandTotalRatesInterface extends \Magento\Framework\Api\ExtensibleData * @return $this */ public function setTitle($title); - - /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Tax\Api\Data\GrandTotalRatesExtensionInterface|null - */ - public function getExtensionAttributes(); - - /** - * Set an extension attributes object. - * - * @param \Magento\Tax\Api\Data\GrandTotalRatesExtensionInterface $extensionAttributes - * @return $this - */ - public function setExtensionAttributes( - \Magento\Tax\Api\Data\GrandTotalRatesExtensionInterface $extensionAttributes - ); } diff --git a/app/code/Magento/Tax/Model/Calculation/GrandTotalDetails.php b/app/code/Magento/Tax/Model/Calculation/GrandTotalDetails.php index 79cc180e80fceddbf6fde95b704b79c5c09e143b..a3301eb85796a2163d3435005b0a11c80ee6d83a 100644 --- a/app/code/Magento/Tax/Model/Calculation/GrandTotalDetails.php +++ b/app/code/Magento/Tax/Model/Calculation/GrandTotalDetails.php @@ -7,19 +7,19 @@ namespace Magento\Tax\Model\Calculation; use Magento\Tax\Api\Data\GrandTotalDetailsInterface; -use Magento\Framework\Model\AbstractExtensibleModel; +use Magento\Framework\Api\AbstractSimpleObject; /** * Grand Total Tax Details Model */ -class GrandTotalDetails extends AbstractExtensibleModel implements GrandTotalDetailsInterface +class GrandTotalDetails extends AbstractSimpleObject implements GrandTotalDetailsInterface { /**#@+ * Constants defined for keys of array, makes typos less likely */ - const AMOUNT = 'amount'; - const RATES = 'rates'; - const GROUP_ID = 'group_id'; + const AMOUNT = 'amount'; + const RATES = 'rates'; + const GROUP_ID = 'group_id'; /**#@-*/ /** @@ -27,7 +27,7 @@ class GrandTotalDetails extends AbstractExtensibleModel implements GrandTotalDet */ public function getGroupId() { - return $this->getData(self::GROUP_ID); + return $this->_get(self::GROUP_ID); } /** @@ -43,7 +43,7 @@ class GrandTotalDetails extends AbstractExtensibleModel implements GrandTotalDet */ public function getAmount() { - return $this->getData(self::AMOUNT); + return $this->_get(self::AMOUNT); } /** @@ -59,7 +59,7 @@ class GrandTotalDetails extends AbstractExtensibleModel implements GrandTotalDet */ public function getRates() { - return $this->getData(self::RATES); + return $this->_get(self::RATES); } /** @@ -69,26 +69,4 @@ class GrandTotalDetails extends AbstractExtensibleModel implements GrandTotalDet { return $this->setData(self::RATES, $rates); } - - /** - * {@inheritdoc} - * - * @return \Magento\Tax\Api\Data\GrandTotalDetailsExtensionInterface|null - */ - public function getExtensionAttributes() - { - return $this->_getExtensionAttributes(); - } - - /** - * {@inheritdoc} - * - * @param \Magento\Tax\Api\Data\GrandTotalDetailsExtensionInterface $extensionAttributes - * @return $this - */ - public function setExtensionAttributes( - \Magento\Tax\Api\Data\GrandTotalDetailsExtensionInterface $extensionAttributes - ) { - return $this->_setExtensionAttributes($extensionAttributes); - } } diff --git a/app/code/Magento/Tax/Model/Calculation/GrandTotalRates.php b/app/code/Magento/Tax/Model/Calculation/GrandTotalRates.php index 4c23c6444d7236a25ebf661b9d5d75a53f0fa829..b7be0cc4a3d36ab0aa5ae35cd8286245064d62d8 100644 --- a/app/code/Magento/Tax/Model/Calculation/GrandTotalRates.php +++ b/app/code/Magento/Tax/Model/Calculation/GrandTotalRates.php @@ -7,12 +7,12 @@ namespace Magento\Tax\Model\Calculation; use Magento\Tax\Api\Data\GrandTotalRatesInterface; -use Magento\Framework\Model\AbstractExtensibleModel; +use Magento\Framework\Api\AbstractSimpleObject; /** * Grand Total Tax Details Model */ -class GrandTotalRates extends AbstractExtensibleModel implements GrandTotalRatesInterface +class GrandTotalRates extends AbstractSimpleObject implements GrandTotalRatesInterface { /**#@+ * Constants defined for keys of array, makes typos less likely @@ -26,7 +26,7 @@ class GrandTotalRates extends AbstractExtensibleModel implements GrandTotalRates */ public function getTitle() { - return $this->getData(self::TITLE); + return $this->_get(self::TITLE); } /** @@ -42,7 +42,7 @@ class GrandTotalRates extends AbstractExtensibleModel implements GrandTotalRates */ public function getPercent() { - return $this->getData(self::PERCENT); + return $this->_get(self::PERCENT); } /** @@ -52,26 +52,4 @@ class GrandTotalRates extends AbstractExtensibleModel implements GrandTotalRates { return $this->setData(self::PERCENT, $percent); } - - /** - * {@inheritdoc} - * - * @return \Magento\Tax\Api\Data\GrandTotalRatesExtensionInterface|null - */ - public function getExtensionAttributes() - { - return $this->_getExtensionAttributes(); - } - - /** - * {@inheritdoc} - * - * @param \Magento\Tax\Api\Data\GrandTotalRatesExtensionInterface $extensionAttributes - * @return $this - */ - public function setExtensionAttributes( - \Magento\Tax\Api\Data\GrandTotalRatesExtensionInterface $extensionAttributes - ) { - return $this->_setExtensionAttributes($extensionAttributes); - } } diff --git a/app/code/Magento/Tax/Model/Quote/GrandTotalDetails.php b/app/code/Magento/Tax/Model/Quote/GrandTotalDetailsPlugin.php similarity index 87% rename from app/code/Magento/Tax/Model/Quote/GrandTotalDetails.php rename to app/code/Magento/Tax/Model/Quote/GrandTotalDetailsPlugin.php index e20684a73b880754f7285dbe561485e298361d28..1de7b6d223d5648f009b1598917b54d46dc6643c 100644 --- a/app/code/Magento/Tax/Model/Quote/GrandTotalDetails.php +++ b/app/code/Magento/Tax/Model/Quote/GrandTotalDetailsPlugin.php @@ -6,8 +6,9 @@ namespace Magento\Tax\Model\Quote; use Magento\Quote\Model\Cart\CartTotalRepository; +use Magento\Quote\Api\Data\TotalsExtensionFactory; -class GrandTotalDetails +class GrandTotalDetailsPlugin { /** * @var \Magento\Tax\Api\Data\GrandTotalDetailsInterfaceFactory @@ -20,7 +21,7 @@ class GrandTotalDetails protected $ratesFactory; /** - * @var \Magento\Framework\Api\ExtensionAttributesFactory + * @var TotalsExtensionFactory */ protected $extensionFactory; @@ -42,7 +43,7 @@ class GrandTotalDetails /** * @param \Magento\Tax\Api\Data\GrandTotalDetailsInterfaceFactory $detailsFactory * @param \Magento\Tax\Api\Data\GrandTotalRatesInterfaceFactory $ratesFactory - * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory + * @param TotalsExtensionFactory $extensionFactory * @param \Magento\Tax\Model\Config $taxConfig * @param \Magento\Quote\Model\Quote\Address\Total\Tax $taxTotal * @param \Magento\Quote\Model\QuoteRepository $quoteRepository @@ -50,7 +51,7 @@ class GrandTotalDetails public function __construct( \Magento\Tax\Api\Data\GrandTotalDetailsInterfaceFactory $detailsFactory, \Magento\Tax\Api\Data\GrandTotalRatesInterfaceFactory $ratesFactory, - \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory, + TotalsExtensionFactory $extensionFactory, \Magento\Tax\Model\Config $taxConfig, \Magento\Quote\Model\Quote\Address\Total\Tax $taxTotal, \Magento\Quote\Model\QuoteRepository $quoteRepository @@ -81,7 +82,7 @@ class GrandTotalDetails /** * @param CartTotalRepository $subject - * @param callable $proceed + * @param \Closure $proceed * @param int $cartId * @return \Magento\Quote\Model\Cart\Totals * @throws \Magento\Framework\Exception\NoSuchEntityException @@ -119,11 +120,13 @@ class GrandTotalDetails $finalData[] = $taxDetails; $detailsId++; } - $taxInfo = $this->extensionFactory->create('\\Magento\\Quote\\Model\\Cart\\Totals', []); - $taxInfo->setTaxGrandtotalDetails($finalData); + $attributes = $result->getExtensionAttributes(); + if ($attributes === null) { + $attributes = $this->extensionFactory->create(); + } + $attributes->setTaxGrandtotalDetails($finalData); /** @var $result \Magento\Quote\Model\Cart\Totals */ - $result->setExtensionAttributes($taxInfo); - $result->setTaxAmount($taxes['value']); + $result->setExtensionAttributes($attributes); return $result; } } diff --git a/app/code/Magento/Tax/Model/TaxConfigProvider.php b/app/code/Magento/Tax/Model/TaxConfigProvider.php index 4f40850d8bfb1657011a84f9d135076b82b4f9a4..8ce354850537f39125869c4f4baf5b01161c19ee 100644 --- a/app/code/Magento/Tax/Model/TaxConfigProvider.php +++ b/app/code/Magento/Tax/Model/TaxConfigProvider.php @@ -43,6 +43,7 @@ class TaxConfigProvider implements ConfigProviderInterface 'reviewTotalsDisplayMode' => $this->getReviewTotalsDisplayMode(), 'includeTaxInGrandTotal' => $this->isTaxDisplayedInGrandTotal(), 'isFullTaxSummaryDisplayed' => $this->isFullTaxSummaryDisplayed(), + 'isZeroTaxDisplayed' => $this->taxConfig->displayCartZeroTax(), ]; } diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..cad8010f39cf0056c67efb00f98d427cdbbc9d9a --- /dev/null +++ b/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php @@ -0,0 +1,197 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Tax\Test\Unit\Model; + +class TaxConfigProviderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $taxHelperMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $taxConfigMock; + + /** + * @var \Magento\Tax\Model\TaxConfigProvider + */ + protected $model; + + protected function setUp() + { + $this->taxHelperMock = $this->getMock('Magento\Tax\Helper\Data', [], [], '', false); + $this->taxConfigMock = $this->getMock('Magento\Tax\Model\Config', [], [], '', false); + + $this->model = new \Magento\Tax\Model\TaxConfigProvider($this->taxHelperMock, $this->taxConfigMock); + } + + /** + * @dataProvider getConfigDataProvider + * @param array $expectedResult + * @param int $cartShippingBoth + * @param int $cartShippingExclTax + * @param int $cartBothPrices + * @param int $cartPriceExclTax + * @param int $cartSubTotalBoth + * @param int $cartSubTotalExclTax + */ + public function testGetConfig( + $expectedResult, + $cartShippingBoth, + $cartShippingExclTax, + $cartBothPrices, + $cartPriceExclTax, + $cartSubTotalBoth, + $cartSubTotalExclTax + ) { + $this->taxConfigMock->expects($this->any())->method('displayCartShippingBoth') + ->will($this->returnValue($cartShippingBoth)); + $this->taxConfigMock->expects($this->any())->method('displayCartShippingExclTax') + ->will($this->returnValue($cartShippingExclTax)); + + $this->taxHelperMock->expects($this->any())->method('displayCartBothPrices') + ->will($this->returnValue($cartBothPrices)); + $this->taxHelperMock->expects($this->any())->method('displayCartPriceExclTax') + ->will($this->returnValue($cartPriceExclTax)); + + $this->taxConfigMock->expects($this->any())->method('displayCartSubtotalBoth') + ->will($this->returnValue($cartSubTotalBoth)); + $this->taxConfigMock->expects($this->any())->method('displayCartSubtotalExclTax') + ->will($this->returnValue($cartSubTotalExclTax)); + + $this->taxHelperMock->expects(($this->any()))->method('displayShippingPriceExcludingTax') + ->will($this->returnValue(1)); + $this->taxHelperMock->expects(($this->any()))->method('displayShippingBothPrices') + ->will($this->returnValue(1)); + $this->taxHelperMock->expects(($this->any()))->method('displayFullSummary') + ->will($this->returnValue(1)); + $this->taxConfigMock->expects(($this->any()))->method('displayCartTaxWithGrandTotal') + ->will($this->returnValue(1)); + $this->taxConfigMock->expects(($this->any()))->method('displayCartZeroTax') + ->will($this->returnValue(1)); + $this->assertEquals($expectedResult, $this->model->getConfig()); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getConfigDataProvider() + { + return [ + [ + 'expectedResult' => [ + 'isDisplayShippingPriceExclTax' => 1, + 'isDisplayShippingBothPrices' => 1, + 'reviewShippingDisplayMode' => 'both', + 'reviewItemPriceDisplayMode' => 'both', + 'reviewTotalsDisplayMode' => 'both', + 'includeTaxInGrandTotal' => 1, + 'isFullTaxSummaryDisplayed' => 1, + 'isZeroTaxDisplayed' => 1 + ], + 'cartShippingBoth' => 1, + 'cartShippingExclTax' => 1, + 'cartBothPrices' => 1, + 'cartPriceExclTax' => 1, + 'cartSubTotalBoth' => 1, + 'cartSubTotalExclTax' => 1 + ], + [ + 'expectedResult' => [ + 'isDisplayShippingPriceExclTax' => 1, + 'isDisplayShippingBothPrices' => 1, + 'reviewShippingDisplayMode' => 'excluding', + 'reviewItemPriceDisplayMode' => 'excluding', + 'reviewTotalsDisplayMode' => 'excluding', + 'includeTaxInGrandTotal' => 1, + 'isFullTaxSummaryDisplayed' => 1, + 'isZeroTaxDisplayed' => 1 + ], + 'cartShippingBoth' => 0, + 'cartShippingExclTax' => 1, + 'cartBothPrices' => 0, + 'cartPriceExclTax' => 1, + 'cartSubTotalBoth' => 0, + 'cartSubTotalExclTax' => 1 + ], + [ + 'expectedResult' => [ + 'isDisplayShippingPriceExclTax' => 1, + 'isDisplayShippingBothPrices' => 1, + 'reviewShippingDisplayMode' => 'including', + 'reviewItemPriceDisplayMode' => 'including', + 'reviewTotalsDisplayMode' => 'including', + 'includeTaxInGrandTotal' => 1, + 'isFullTaxSummaryDisplayed' => 1, + 'isZeroTaxDisplayed' => 1 + ], + 'cartShippingBoth' => 0, + 'cartShippingExclTax' => 0, + 'cartBothPrices' => 0, + 'cartPriceExclTax' => 0, + 'cartSubTotalBoth' => 0, + 'cartSubTotalExclTax' => 0 + ], + [ + 'expectedResult' => [ + 'isDisplayShippingPriceExclTax' => 1, + 'isDisplayShippingBothPrices' => 1, + 'reviewShippingDisplayMode' => 'including', + 'reviewItemPriceDisplayMode' => 'including', + 'reviewTotalsDisplayMode' => 'including', + 'includeTaxInGrandTotal' => 1, + 'isFullTaxSummaryDisplayed' => 1, + 'isZeroTaxDisplayed' => 1 + ], + 'cartShippingBoth' => 0, + 'cartShippingExclTax' => 0, + 'cartBothPrices' => 0, + 'cartPriceExclTax' => 0, + 'cartSubTotalBoth' => 0, + 'cartSubTotalExclTax' => 0 + ], + [ + 'expectedResult' => [ + 'isDisplayShippingPriceExclTax' => 1, + 'isDisplayShippingBothPrices' => 1, + 'reviewShippingDisplayMode' => 'both', + 'reviewItemPriceDisplayMode' => 'both', + 'reviewTotalsDisplayMode' => 'both', + 'includeTaxInGrandTotal' => 1, + 'isFullTaxSummaryDisplayed' => 1, + 'isZeroTaxDisplayed' => 1 + ], + 'cartShippingBoth' => 1, + 'cartShippingExclTax' => 0, + 'cartBothPrices' => 1, + 'cartPriceExclTax' => 0, + 'cartSubTotalBoth' => 1, + 'cartSubTotalExclTax' => 0 + ], + [ + 'expectedResult' => [ + 'isDisplayShippingPriceExclTax' => 1, + 'isDisplayShippingBothPrices' => 1, + 'reviewShippingDisplayMode' => 'excluding', + 'reviewItemPriceDisplayMode' => 'including', + 'reviewTotalsDisplayMode' => 'both', + 'includeTaxInGrandTotal' => 1, + 'isFullTaxSummaryDisplayed' => 1, + 'isZeroTaxDisplayed' => 1 + ], + 'cartShippingBoth' => 0, + 'cartShippingExclTax' => 1, + 'cartBothPrices' => 0, + 'cartPriceExclTax' => 0, + 'cartSubTotalBoth' => 1, + 'cartSubTotalExclTax' => 0 + ], + ]; + } +} diff --git a/app/code/Magento/Tax/etc/di.xml b/app/code/Magento/Tax/etc/di.xml index 48b3173d60f09e739305f3c68cf501be8315be96..12dd5b270fc3c2740cf0f272bcd38fdb812d9b0d 100644 --- a/app/code/Magento/Tax/etc/di.xml +++ b/app/code/Magento/Tax/etc/di.xml @@ -65,7 +65,7 @@ <plugin name="add_tax_to_order" type="Magento\Tax\Model\Quote\ToOrderConverter"/> </type> <type name="Magento\Quote\Model\Cart\CartTotalRepository"> - <plugin name="add_tax_details" type="Magento\Tax\Model\Quote\GrandTotalDetails"/> + <plugin name="add_tax_details" type="Magento\Tax\Model\Quote\GrandTotalDetailsPlugin"/> </type> <type name="Magento\Tax\Model\Resource\Report\Tax\Createdat"> <arguments> diff --git a/app/code/Magento/Tax/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Tax/view/frontend/layout/checkout_onepage_index.xml index 85969a844c674559ccb839ed2d3d092807e691bf..db20c4572b1d90cde9ed306a8e68a06ae42a6ada 100644 --- a/app/code/Magento/Tax/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/Tax/view/frontend/layout/checkout_onepage_index.xml @@ -15,52 +15,71 @@ <item name="children" xsi:type="array"> <item name="steps" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="shipping" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="price" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/shipping_method/price</item> - <item name="displayArea" xsi:type="string">price</item> + <item name="shippingAddress" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="price" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/shipping_method/price</item> + <item name="displayArea" xsi:type="string">price</item> + </item> + </item> </item> </item> </item> - <item name="review" xsi:type="array"> + </item> + </item> + <item name="summary" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="totals" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="columns" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Checkout/js/view/columns</item> + <!-- sort order for this totals is configured on admin panel--> + <!-- Stores->Configuration->SALES->Sales->General->Checkout Totals Sort Order --> + <item name="subtotal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/summary/subtotal</item> + <item name="config" xsi:type="array"> + <item name="excludingTaxMessage" xsi:type="string">Excl. Tax</item> + <item name="includingTaxMessage" xsi:type="string">Incl. Tax</item> + </item> + </item> + <item name="shipping" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/summary/shipping</item> + <item name="sortOrder" xsi:type="string">20</item> + <item name="config" xsi:type="array"> + <item name="excludingTaxMessage" xsi:type="string">Excl. Tax</item> + <item name="includingTaxMessage" xsi:type="string">Incl. Tax</item> + </item> + </item> + <item name="before_grandtotal" xsi:type="array"> + <item name="component" xsi:type="string">uiComponent</item> + <item name="sortOrder" xsi:type="string">30</item> <item name="children" xsi:type="array"> - <item name="price" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/item/columns/price</item> - </item> - <item name="subtotal" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/item/columns/subtotal</item> - </item> + <!-- merge your components here --> + </item> + </item> + <item name="tax" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/summary/tax</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string">Tax</item> + </item> + </item> + <item name="grand-total" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/summary/grand-total</item> + <item name="config" xsi:type="array"> + <item name="exclTaxLabel" xsi:type="string">Order Total Excl. Tax</item> + <item name="inclTaxLabel" xsi:type="string">Order Total Incl. Tax</item> + <item name="basicCurrencyMessage" xsi:type="string">Your credit card will be charged for</item> + <item name="title" xsi:type="string">Order Total</item> </item> </item> - <item name="totals" xsi:type="array"> + </item> + </item> + <item name="cart_items" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="details" xsi:type="array"> <item name="children" xsi:type="array"> <item name="subtotal" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/subtotal</item> - <item name="sortOrder" xsi:type="string">10</item> - </item> - <item name="shipping" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/shipping</item> - <item name="sortOrder" xsi:type="string">20</item> - </item> - <item name="before_grandtotal" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/before_grandtotal</item> - <item name="sortOrder" xsi:type="string">30</item> - <item name="children" xsi:type="array"> - <!-- merge your components here --> - </item> - </item> - <item name="grandtotal" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/grandtotal</item> - <item name="sortOrder" xsi:type="string">40</item> - <item name="children" xsi:type="array"> - <item name="grandtotal_tax" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/tax_total</item> - </item> - </item> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/summary/item/details/subtotal</item> </item> </item> </item> diff --git a/app/code/Magento/Tax/view/frontend/layout/checkout_onepage_original.xml b/app/code/Magento/Tax/view/frontend/layout/checkout_onepage_original.xml new file mode 100644 index 0000000000000000000000000000000000000000..012d3de66d1ddaf42f7320f1cb3c064b9f2c4486 --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/layout/checkout_onepage_original.xml @@ -0,0 +1,79 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- TODO remove this file as soon as enhanced checkout is implemented --> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="price" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/shipping_method/price</item> + <item name="displayArea" xsi:type="string">price</item> + </item> + </item> + </item> + <item name="review" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="columns" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Checkout/js/view/columns</item> + <item name="children" xsi:type="array"> + <item name="price" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/item/columns/price</item> + </item> + <item name="subtotal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/item/columns/subtotal</item> + </item> + </item> + </item> + <item name="totals" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="subtotal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/subtotal</item> + <item name="sortOrder" xsi:type="string">10</item> + </item> + <item name="shipping" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/shipping</item> + <item name="sortOrder" xsi:type="string">20</item> + </item> + <item name="before_grandtotal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/before_grandtotal</item> + <item name="sortOrder" xsi:type="string">30</item> + <item name="children" xsi:type="array"> + <!-- merge your components here --> + </item> + </item> + <item name="grandtotal" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/grandtotal</item> + <item name="sortOrder" xsi:type="string">40</item> + <item name="children" xsi:type="array"> + <item name="grandtotal_tax" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/review/tax_total</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> \ No newline at end of file diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/before_grandtotal.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/before_grandtotal.js deleted file mode 100644 index 72f01914f2df6bd4afd9e0478616f8c2a9474373..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/before_grandtotal.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - 'uiComponent' - ], - function (Component) { - "use strict"; - return Component.extend({ - defaults: { - template: 'Magento_Tax/checkout/review/before_grandtotal' - } - }); - } -); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/item/columns/price.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/item/columns/price.js deleted file mode 100644 index 839e4a1be856e3fcd8ea4ae7dafaa25ea6030066..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/item/columns/price.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - 'Magento_Checkout/js/view/review/item/column' - ], - function (column) { - "use strict"; - var displayPriceMode = window.checkoutConfig.reviewItemPriceDisplayMode || 'including'; - return column.extend({ - defaults: { - displayPriceMode: displayPriceMode, - ownClass: 'price', - columnTitle: 'Price', - template: 'Magento_Tax/checkout/review/item/columns/price' - }, - isPriceInclTaxDisplayed: function() { - return 'both' == this.displayPriceMode || 'including' == this.displayPriceMode; - }, - isPriceExclTaxDisplayed: function() { - return 'both' == this.displayPriceMode || 'excluding' == this.displayPriceMode; - }, - isBothPricesDisplayed: function() { - return 'both' == this.displayPriceMode; - }, - getPriceExclTax: function(quoteItem) { - return this.getFormattedPrice(quoteItem.price); - }, - getPriceInclTax: function(quoteItem) { - return this.getFormattedPrice(quoteItem.price_incl_tax); - } - }); - } -); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/item/columns/subtotal.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/item/columns/subtotal.js deleted file mode 100644 index 2d1bee80d8fb585c4bd0f7277cdec70cb24da129..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/item/columns/subtotal.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - 'Magento_Tax/js/view/checkout/review/item/columns/price' - ], - function (Price) { - "use strict"; - var displayPriceMode = window.checkoutConfig.reviewItemPriceDisplayMode || 'including'; - return Price.extend({ - defaults: { - displayPriceMode: displayPriceMode, - ownClass: 'subtotal', - columnTitle: 'Subtotal', - template: 'Magento_Tax/checkout/review/item/columns/subtotal' - } - }); - } -); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/shipping.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/shipping.js deleted file mode 100644 index 1fc18683237bb750ea9ca55548be418378c1d5cb..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/shipping.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - 'jquery', - 'uiComponent', - 'Magento_Checkout/js/model/quote', - 'Magento_Catalog/js/price-utils', - 'Magento_Checkout/js/model/shipping-service' - ], - function ($, Component, quote, priceUtils, shippingService) { - var displayMode = window.checkoutConfig.reviewShippingDisplayMode; - return Component.extend({ - defaults: { - displayMode: displayMode, - template: 'Magento_Tax/checkout/review/shipping' - }, - getColspan: 3, - style: "", - quoteIsVirtual: quote.isVirtual(), - selectedShippingMethod: quote.getShippingMethod(), - getTitle: function() { - return "Shipping & Handling" + "(" + shippingService.getTitleByCode(this.selectedShippingMethod()) + ")"; - }, - getExcludingLabel: function() { - return "Shipping Excl. Tax" + "(" + shippingService.getTitleByCode(this.selectedShippingMethod()) + ")"; - }, - getIncludingLabel: function() { - return "Shipping Incl. Tax" + "(" + shippingService.getTitleByCode(this.selectedShippingMethod()) + ")"; - }, - totals: quote.getTotals(), - isBothPricesDisplayed: function() { - return 'both' == this.displayMode - }, - isIncludingDisplayed: function() { - return 'including' == this.displayMode; - }, - isExcludingDisplayed: function() { - return 'excluding' == this.displayMode; - }, - getValue: function() { - var price = 0; - if (this.totals()) { - price = this.totals().shipping_amount; - } - return priceUtils.formatPrice(price, quote.getPriceFormat()); - }, - getIncludingValue: function() { - var price = 0; - if (this.totals()) { - price = this.totals().shipping_incl_tax; - } - return priceUtils.formatPrice(price, quote.getPriceFormat()); - }, - getExcludingValue: function() { - var price = 0; - if (this.totals()) { - price = this.totals().shipping_amount; - } - return priceUtils.formatPrice(price, quote.getPriceFormat()); - } - }); - } -); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/tax_total.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/tax_total.js deleted file mode 100644 index 56f70a8993f977d833331dd7c3d76c44d61c37cc..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/tax_total.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global alert*/ -define( - [ - 'ko', - 'uiComponent', - 'Magento_Checkout/js/model/quote', - 'Magento_Catalog/js/price-utils' - ], - function (ko, Component, quote, priceUtils) { - "use strict"; - var isTaxDisplayedInGrandTotal = window.checkoutConfig.includeTaxInGrandTotal; - var isFullTaxSummaryDisplayed = window.checkoutConfig.isFullTaxSummaryDisplayed; - return Component.extend({ - defaults: { - isTaxDisplayedInGrandTotal: isTaxDisplayedInGrandTotal, - template: 'Magento_Tax/checkout/review/tax_total' - }, - colspan: 3, - totals: quote.getTotals(), - style: "", - isFullTaxSummaryDisplayed: isFullTaxSummaryDisplayed, - lastTaxGroupId: null, - isDetailsVisible: ko.observable(), - getTitle: function() { - return "Tax"; - }, - getValue: function() { - var amount = 0; - if (this.totals()) { - amount = this.totals().tax_amount; - } - return priceUtils.formatPrice(amount, quote.getPriceFormat()); - }, - formatPrice: function(amount) { - return priceUtils.formatPrice(amount, quote.getPriceFormat()); - }, - getDetails: function() { - var totals = this.totals(); - if (totals.extension_attributes) { - return totals.extension_attributes.tax_grandtotal_details; - } - return []; - }, - toggleDetails: function() { - this.isDetailsVisible(!this.isDetailsVisible()); - } - }); - } -); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/shipping_method/price.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/shipping_method/price.js index bdb1256f25678a1a3ac005965ebc90ddc69682c4..018eb3b9d3ef7ea9206f43f5ac1efb2562c1779d 100644 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/shipping_method/price.js +++ b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/shipping_method/price.js @@ -14,7 +14,7 @@ define( "use strict"; return Component.extend({ defaults: { - template: 'Magento_Tax/checkout/shipping_method/price', + template: 'Magento_Tax/checkout/shipping_method/price' }, isDisplayShippingPriceExclTax: window.checkoutConfig.isDisplayShippingPriceExclTax, diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/grandtotal.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/grand-total.js similarity index 51% rename from app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/grandtotal.js rename to app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/grand-total.js index 214e16f531e78aee0aec37621fbbd41ffc62f5e6..2ad991e704ed63d83dd1d3c91bd9e8a69dc63e7c 100644 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/grandtotal.js +++ b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/grand-total.js @@ -6,34 +6,29 @@ /*global alert*/ define( [ - 'uiComponent', + 'Magento_Checkout/js/view/summary/abstract-total', 'Magento_Checkout/js/model/quote', - 'Magento_Catalog/js/price-utils' + 'Magento_Catalog/js/price-utils', + 'Magento_Checkout/js/model/totals' ], - function (Component, quote, priceUtils) { + function (Component, quote, priceUtils, totals) { "use strict"; - var isTaxDisplayedInGrandTotal = window.checkoutConfig.includeTaxInGrandTotal || false; - var isFullTaxSummaryDisplayed = window.checkoutConfig.isFullTaxSummaryDisplayed || false; return Component.extend({ defaults: { - isFullTaxSummaryDisplayed: isFullTaxSummaryDisplayed, - template: 'Magento_Tax/checkout/review/grandtotal' - }, - getColspan: 3, - style: "", - exclTaxLabel: 'Grand Total Excl. Tax', - inclTaxLabel: 'Grand Total Incl. Tax', - basicCurrencyMessage: 'Your credit card will be charged for', - getTitle: function() { - return "Grand Total"; + isFullTaxSummaryDisplayed: window.checkoutConfig.isFullTaxSummaryDisplayed || false, + template: 'Magento_Tax/checkout/summary/grand-total' }, totals: quote.getTotals(), + isTaxDisplayedInGrandTotal: window.checkoutConfig.includeTaxInGrandTotal || false, + isDisplayed: function() { + return this.isFullMode(); + }, getValue: function() { var price = 0; if (this.totals()) { - price = this.totals().grand_total; + price = totals.getSegment('grand_total').value; } - return priceUtils.formatPrice(price, quote.getPriceFormat()); + return this.getFormattedPrice(price); }, getBaseValue: function() { var price = 0; @@ -42,17 +37,12 @@ define( } return priceUtils.formatPrice(price, quote.getBasePriceFormat()); }, - isTaxDisplayedInGrandTotal: isTaxDisplayedInGrandTotal, getGrandTotalExclTax: function() { var totals = this.totals(); if (!totals) { return 0; } - var amount = totals.grand_total - totals.tax_amount; - if (amount < 0) { - return 0; - } - return priceUtils.formatPrice(amount, quote.getPriceFormat()); + return this.getFormattedPrice(totals.grand_total); }, isBaseGrandTotalDisplayNeeded: function() { var totals = this.totals(); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/item/details/subtotal.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/item/details/subtotal.js new file mode 100644 index 0000000000000000000000000000000000000000..f75c7733bab9a9aa72776d85af6dedf7d5442225 --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/item/details/subtotal.js @@ -0,0 +1,34 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'Magento_Checkout/js/view/summary/item/details/subtotal' + ], + function (subtotal) { + "use strict"; + var displayPriceMode = window.checkoutConfig.reviewItemPriceDisplayMode || 'including'; + return subtotal.extend({ + defaults: { + displayPriceMode: displayPriceMode, + template: 'Magento_Tax/checkout/summary/item/details/subtotal' + }, + isPriceInclTaxDisplayed: function() { + return 'both' == displayPriceMode || 'including' == displayPriceMode; + }, + isPriceExclTaxDisplayed: function() { + return 'both' == displayPriceMode || 'excluding' == displayPriceMode; + }, + getValueInclTax: function(quoteItem) { + return this.getFormattedPrice(quoteItem['row_total_incl_tax']); + }, + getValueExclTax: function(quoteItem) { + return this.getFormattedPrice(quoteItem['row_total']); + } + + }); + } +); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/shipping.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/shipping.js new file mode 100644 index 0000000000000000000000000000000000000000..b6c3631c7869d1b912a046c8b3a097897a973eeb --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/shipping.js @@ -0,0 +1,48 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'jquery', + 'Magento_Checkout/js/view/summary/shipping', + 'Magento_Checkout/js/model/quote' + ], + function ($, Component, quote) { + var displayMode = window.checkoutConfig.reviewShippingDisplayMode; + return Component.extend({ + defaults: { + displayMode: displayMode, + template: 'Magento_Tax/checkout/summary/shipping' + }, + isBothPricesDisplayed: function() { + return 'both' == this.displayMode + }, + isIncludingDisplayed: function() { + return 'including' == this.displayMode; + }, + isExcludingDisplayed: function() { + return 'excluding' == this.displayMode; + }, + isCalculated: function() { + return this.totals() && this.isFullMode() && null != quote.shippingMethod(); + }, + getIncludingValue: function() { + if (!this.isCalculated()) { + return this.notCalculatedMessage; + } + var price = this.totals().shipping_incl_tax; + return this.getFormattedPrice(price); + }, + getExcludingValue: function() { + if (!this.isCalculated()) { + return this.notCalculatedMessage; + } + var price = this.totals().shipping_amount; + return this.getFormattedPrice(price); + } + }); + } +); diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/subtotal.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/subtotal.js similarity index 63% rename from app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/subtotal.js rename to app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/subtotal.js index 06a169784c3f625b7784a67dec4b79905c8d1bad..e9e86cd9fa03119f034eb91a70b48227ad169987 100644 --- a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/review/subtotal.js +++ b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/subtotal.js @@ -6,23 +6,15 @@ /*global alert*/ define( [ - 'uiComponent', - 'Magento_Checkout/js/model/quote', - 'Magento_Catalog/js/price-utils' + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote' ], - function (Component, quote, priceUtils) { + function (Component, quote) { var displaySubtotalMode = window.checkoutConfig.reviewTotalsDisplayMode; return Component.extend({ defaults: { displaySubtotalMode: displaySubtotalMode, - template: 'Magento_Tax/checkout/review/subtotal' - }, - getColspan: 3, - style: "", - excludingTaxMessage: 'Subtotal (Excl. Tax)', - includingTaxMessage: 'Subtotal (Incl. Tax)', - getTitle: function() { - return "Subtotal" + template: 'Magento_Tax/checkout/summary/subtotal' }, totals: quote.getTotals(), getValue: function () { @@ -30,7 +22,7 @@ define( if (this.totals()) { price = this.totals().subtotal; } - return priceUtils.formatPrice(price, quote.getPriceFormat()); + return this.getFormattedPrice(price); }, isBothPricesDisplayed: function() { return 'both' == this.displaySubtotalMode; @@ -43,7 +35,7 @@ define( if (this.totals()) { price = this.totals().subtotal_incl_tax; } - return priceUtils.formatPrice(price, quote.getPriceFormat()); + return this.getFormattedPrice(price); } }); } diff --git a/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js new file mode 100644 index 0000000000000000000000000000000000000000..019b0717c70afdebf57d04f73e75e6fdb6564956 --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/web/js/view/checkout/summary/tax.js @@ -0,0 +1,77 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'ko', + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/totals' + ], + function (ko, Component, quote, totals) { + "use strict"; + var isTaxDisplayedInGrandTotal = window.checkoutConfig.includeTaxInGrandTotal; + var isFullTaxSummaryDisplayed = window.checkoutConfig.isFullTaxSummaryDisplayed; + var isZeroTaxDisplayed = window.checkoutConfig.isZeroTaxDisplayed; + return Component.extend({ + defaults: { + isTaxDisplayedInGrandTotal: isTaxDisplayedInGrandTotal, + notCalculatedMessage: 'Not yet calculated', + template: 'Magento_Tax/checkout/summary/tax' + }, + totals: quote.getTotals(), + isFullTaxSummaryDisplayed: isFullTaxSummaryDisplayed, + ifShowValue: function() { + if (!isTaxDisplayedInGrandTotal) { + return false; + } + if (!this.totals() || null == totals.getSegment('tax')) { + return true; + } + if (this.getPureValue() == 0) { + return isZeroTaxDisplayed; + } + return true; + }, + ifShowDetails: function() { + if (!this.isFullMode()) { + return false; + } + return isTaxDisplayedInGrandTotal && this.getPureValue() > 0 && isFullTaxSummaryDisplayed; + }, + getPureValue: function() { + var amount = 0; + if (this.totals()) { + var taxTotal = totals.getSegment('tax'); + if (taxTotal) { + amount = taxTotal.value; + } + } + return amount; + }, + isCalculated: function() { + return this.totals() && this.isFullMode() && null != totals.getSegment('tax'); + }, + getValue: function() { + if (!this.isCalculated()) { + return this.notCalculatedMessage; + } + var amount = totals.getSegment('tax').value; + return this.getFormattedPrice(amount); + }, + formatPrice: function(amount) { + return this.getFormattedPrice(amount); + }, + getDetails: function() { + var totals = this.totals(); + if (totals.extension_attributes) { + return totals.extension_attributes.tax_grandtotal_details; + } + return []; + } + }); + } +); diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/before_grandtotal.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/review/before_grandtotal.html deleted file mode 100644 index 237b692b59a6f20c62fab5b3c9c5ef157ffe37ab..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/before_grandtotal.html +++ /dev/null @@ -1,10 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<!-- ko foreach: elems() --> -<!-- ko template: getTemplate() --><!-- /ko --> -<!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/grandtotal.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/review/grandtotal.html deleted file mode 100644 index 8c533bcae6fca5bb34f84282e33adcf595e4167d..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/grandtotal.html +++ /dev/null @@ -1,43 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko if: isTaxDisplayedInGrandTotal --> -<tr class="grand totals excl"> - <th data-bind="attr: {'style':style, 'colspan': getColspan}" class="mark" scope="row"> - <strong data-bind="text: exclTaxLabel"></strong> - </th> - <td data-bind="attr: {'style': style, 'data-th': exclTaxLabel }" class="amount"> - <strong data-bind="text: getGrandTotalExclTax()"></strong> - </td> -</tr> - <!-- ko foreach: elems() --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> -<tr class="grand totals incl"> - <th data-bind="attr: {'style':style, 'colspan': getColspan}" class="mark" scope="row"> - <strong data-bind="text: $t(inclTaxLabel)"></strong> - </th> - <td data-bind="attr: {'style': style, 'data-th': $t(inclTaxLabel) }" class="amount"> - <strong data-bind="text: getValue()"></strong> - </td> -</tr> -<!-- /ko --> -<!-- ko if: !isTaxDisplayedInGrandTotal --> -<tr class="grand totals"> - <th data-bind="attr: {'style':style, 'colspan': getColspan }" class="mark" scope="row"> - <strong data-bind="text: $t(getTitle())"></strong> - </th> - <td data-bind="attr: {'style':style, 'data-th': getTitle()}" class="amount"> - <strong data-bind="text: getValue()"></strong> - </td> -</tr> -<!-- /ko --> -<!-- ko if: isBaseGrandTotalDisplayNeeded() --> -<tr class="totals charge"> - <th class="mark" data-bind="text: $t(basicCurrencyMessage), attr: { 'colspan': getColspan }" scope="row"></th> - <td class="amount" data-bind="text: getBaseValue(), attr: {'data-th': $t(basicCurrencyMessage)}"></td> -</tr> -<!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/item/columns/price.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/review/item/columns/price.html deleted file mode 100644 index fc596c7d1ac5e35a6d6590ecf2231b0fc88b52e9..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/item/columns/price.html +++ /dev/null @@ -1,23 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<td data-bind="attr: { 'data-th': $t(getColName()), class: getClass() }"> - <!-- ko if: isPriceInclTaxDisplayed() --> - <span class="price-including-tax" data-bind ="attr:{'data-label': $t('Incl. Tax')}"> - <!-- ko foreach: getRegion('unit_incl_tax') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - </span> - - <!-- /ko --> - <!-- ko if: isPriceExclTaxDisplayed() --> - <span class="price-excluding-tax" data-bind ="attr:{'data-label': $t('Excl. Tax')}"> - <!-- ko foreach: getRegion('unit_excl_tax') --> - <!-- ko template: getTemplate() --><!-- /ko --> - <!-- /ko --> - </span> - <!-- /ko --> -</td> \ No newline at end of file diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/shipping.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/review/shipping.html deleted file mode 100644 index 6c7900d23315bdf25c4b3ad02a2382295cc1a90d..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/shipping.html +++ /dev/null @@ -1,31 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko if: quoteIsVirtual == 0 --> - <!-- ko if: isBothPricesDisplayed() --> - <tr class="totals shipping excl"> - <th data-bind="text: $t(getExcludingLabel()), attr: {'style':style, 'colspan': getColspan }" class="mark" scope="row"></th> - <td class="amount" data-bind="text: getExcludingValue(), attr: {'style':style, 'data-th': $t(getExcludingLabel())}"></td> - </tr> - <tr class="totals shipping incl"> - <th data-bind="text: $t(getIncludingLabel()), attr: {'style':style, 'colspan': getColspan }" class="mark" scope="row"></th> - <td class="amount" data-bind="text: getIncludingValue(), attr: {'style':style, 'data-th': $t(getIncludingLabel())}"></td> - </tr> - <!-- /ko --> - <!-- ko if: isIncludingDisplayed() --> - <tr class="totals shipping incl"> - <th data-bind="text: $t(getTitle()), attr: {'style':style, 'colspan': getColspan }" class="mark" scope="row"></th> - <td class="amount" data-bind="text: getIncludingValue(), attr: {'style':style, 'data-th': $t(getTitle())}"></td> - </tr> - <!-- /ko --> - <!-- ko if: isExcludingDisplayed() --> - <tr class="totals shipping excl"> - <th data-bind="text: $t(getTitle()), attr: {'style':style, 'colspan': getColspan }" class="mark" scope="row"></th> - <td data-bind="text: getValue(), attr: {'style':style, 'data-th': $t(getTitle())}" class="amount"></td> - </tr> - <!-- /ko --> -<!-- /ko --> - diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/subtotal.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/review/subtotal.html deleted file mode 100644 index 022131d8a0cc957a96ea074f4fe05c1292e4616d..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/subtotal.html +++ /dev/null @@ -1,31 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko if: isBothPricesDisplayed() --> -<tr class="totals sub excl"> - <th data-bind="text: excludingTaxMessage, attr: {'style':style, 'colspan': getColspan}" class="mark" scope="row"> - </th> - <td data-bind="text: getValue(), attr: {'style': style, 'data-th': $t(excludingTaxMessage) }" class="amount"></td> -</tr> -<tr class="totals sub incl"> - <th data-bind="text: includingTaxMessage, attr: {'style':style, 'colspan': getColspan}" class="mark" scope="row"> - </th> - <td data-bind="text: getValueInclTax(), attr: {'style': style, 'data-th': $t(includingTaxMessage) }" class="amount"> - </td> -</tr> -<!-- /ko --> -<!-- ko if: !isBothPricesDisplayed() && isIncludingTaxDisplayed() --> -<tr class="totals sub"> - <th data-bind="text: $t(getTitle()), attr: {'style':style, 'colspan': getColspan}" class="mark" scope="row"></th> - <td data-bind="text: getValueInclTax(), attr: {'style':style, 'data-th': $t(getTitle())}" class="amount"></td> -</tr> -<!-- /ko --> -<!-- ko if: !isBothPricesDisplayed() && !isIncludingTaxDisplayed() --> -<tr class="totals sub"> - <th data-bind="text: $t(getTitle()), attr: {'style':style, 'colspan': getColspan}" class="mark" scope="row"></th> - <td data-bind="text: getValue(), attr: {'style':style, 'data-th': $t(getTitle())}" class="amount"></td> -</tr> -<!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/tax_total.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/review/tax_total.html deleted file mode 100644 index e22db68f36617b6c3ceb614fcf4fc1d250bf62ed..0000000000000000000000000000000000000000 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/tax_total.html +++ /dev/null @@ -1,42 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko ifnot: isFullTaxSummaryDisplayed --> -<tr class="totals-tax"> - <th data-bind="text: getTitle(), attr: {'style':style, 'colspan': colspan}" class="mark" scope="row"> - </th> - <td data-bind="attr: {'style': style, 'data-th': $t(getTitle()) }" class="amount"> - <span class="price" data-bind="text: getValue()"></span> - </td> -</tr> -<!-- /ko --> -<!-- ko if: isFullTaxSummaryDisplayed --> - <tr class="totals-tax-summary" data-bind="click: toggleDetails()"> - <th data-bind="text: getTitle(), attr: {'style':style, 'colspan': colspan}" class="mark" scope="row"> - </th> - <td data-bind="attr: {'style': style, 'data-th': $t(getTitle()) }" class="amount"> - <span class="price" data-bind="text: getValue()"></span> - </td> - </tr> - <!-- ko foreach: getDetails() --> - <!-- ko foreach: rates --> - <tr class="totals-tax-details" data-bind="visible: $parents[1].isDetailsVisible"> - <!-- ko if: percent --> - <th class="mark" scope="row" data-bind="text: title + ' (' + percent + '%)', attr: {'style': $parents[1].style, 'colspan': $parents[1].colspan}"> - </th> - <!-- /ko --> - <!-- ko if: !percent --> - <th class="mark" scope="row" data-bind="text: title, attr: {'style': $parents[1].style, 'colspan': $parents[1].colspan}"> - </th> - <!-- /ko --> - <!-- ko if: $index() == 0 --> - <td class="amount" data-bind="text: $parents[1].formatPrice($parents[0].amount), attr: {'data-th': title, 'style': $parents[1].style, 'rowspan': $parents[0].rates.length }"> - </td> - <!-- /ko --> - </tr> - <!-- /ko --> - <!-- /ko --> -<!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html index e854b9f1e0bc2e4a9a8f50c89ebc77e82f084fce..345b3eea5b0490a15af75cda91627f31bf06ffa6 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html @@ -5,22 +5,22 @@ */ --> <!-- ko if: isDisplayShippingPriceExclTax --> -<span class="price"><span class="price" data-bind="text: getFormattedPrice(item.price_excl_tax)"></span></span> +<span class="price"><span class="price" data-bind="text: getFormattedPrice(method.price_excl_tax)"></span></span> <!-- /ko --> <!-- ko ifnot: isDisplayShippingPriceExclTax --> -<!-- ko if: (isDisplayShippingBothPrices && (item.price_excl_tax != item.price_incl_tax))--> +<!-- ko if: (isDisplayShippingBothPrices && (method.price_excl_tax != method.price_incl_tax))--> <span class="price-including-tax" data-bind = "attr: {'data-label': $t('Incl. Tax')}"> - <span class="price"><span class="price" data-bind="text: getFormattedPrice(item.price_incl_tax)"></span></span> + <span class="price"><span class="price" data-bind="text: getFormattedPrice(method.price_incl_tax)"></span></span> </span> <!-- /ko --> -<!-- ko ifnot: (isDisplayShippingBothPrices && (item.price_excl_tax != item.price_incl_tax))--> - <span class="price"><span class="price" data-bind="text: getFormattedPrice(item.price_incl_tax)"></span></span> +<!-- ko ifnot: (isDisplayShippingBothPrices && (method.price_excl_tax != method.price_incl_tax))--> + <span class="price"><span class="price" data-bind="text: getFormattedPrice(method.price_incl_tax)"></span></span> <!-- /ko --> <!-- /ko --> -<!-- ko if: (isDisplayShippingBothPrices && (item.price_excl_tax != item.price_incl_tax))--> +<!-- ko if: (isDisplayShippingBothPrices && (method.price_excl_tax != method.price_incl_tax))--> <span class="price-excluding-tax" data-bind = "attr: {'data-label': $t('Excl. Tax')}"> - <span class="price"><span class="price" data-bind="text: getFormattedPrice(item.price_excl_tax)"></span></span> + <span class="price"><span class="price" data-bind="text: getFormattedPrice(method.price_excl_tax)"></span></span> </span> <!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/grand-total.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/grand-total.html new file mode 100644 index 0000000000000000000000000000000000000000..d37e8816ae3e05c1cf806e520ac810e4d7a653b2 --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/grand-total.html @@ -0,0 +1,42 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: isTaxDisplayedInGrandTotal && isDisplayed() --> +<tr class="grand totals incl"> + <th class="mark" scope="row"> + <strong data-bind="text: $t(inclTaxLabel)"></strong> + </th> + <td data-bind="attr: {'data-th': $t(inclTaxLabel) }" class="amount"> + <strong><span class="price" data-bind="text: getValue()"></span></strong> + </td> +</tr> +<tr class="grand totals excl"> + <th class="mark" scope="row"> + <strong data-bind="text: $t(exclTaxLabel)"></strong> + </th> + <td data-bind="attr: {'data-th': exclTaxLabel }" class="amount"> + <strong><span class="price" data-bind="text: getGrandTotalExclTax()"></span></strong> + </td> +</tr> +<!-- /ko --> +<!-- ko if: !isTaxDisplayedInGrandTotal && isDisplayed() --> +<tr class="grand totals"> + <th class="mark" scope="row"> + <strong data-bind="text: $t(title)"></strong> + </th> + <td data-bind="attr: {'data-th': $t(title)}" class="amount"> + <strong><span class="price" data-bind="text: getValue()"></span></strong> + </td> +</tr> +<!-- /ko --> +<!-- ko if: isBaseGrandTotalDisplayNeeded() && isDisplayed() --> +<tr class="totals charge"> + <th class="mark" data-bind="text: $t(basicCurrencyMessage)" scope="row"></th> + <td class="amount"> + <span class="price" data-bind="text: getBaseValue(), attr: {'data-th': $t(basicCurrencyMessage)}"></span> + </td> +</tr> +<!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/item/columns/subtotal.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/item/details/subtotal.html similarity index 50% rename from app/code/Magento/Tax/view/frontend/web/template/checkout/review/item/columns/subtotal.html rename to app/code/Magento/Tax/view/frontend/web/template/checkout/summary/item/details/subtotal.html index d489e741ba0474ea1af3e1ca0c72e24d8ac4de85..5d555b1b54f50c13ada9f31da8ffce63f85795a3 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/review/item/columns/subtotal.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/item/details/subtotal.html @@ -4,20 +4,29 @@ * See COPYING.txt for license details. */ --> -<td data-bind="attr: { 'data-th': $t(getColName())}" class="col subtotal"> - <!-- ko if: isPriceInclTaxDisplayed() --> +<div class="subtotal"> + <!-- ko if: isPriceInclTaxDisplayed() && !getRegion('row_incl_tax') --> + <span class="price-including-tax" data-bind ="text: getValueInclTax($parents[1]), attr:{'data-label': $t('Incl. Tax')}"> + </span> + <!-- /ko --> + + <!-- ko if: isPriceInclTaxDisplayed() && getRegion('row_incl_tax') --> <span class="price-including-tax" data-bind ="attr:{'data-label': $t('Incl. Tax')}"> <!-- ko foreach: getRegion('row_incl_tax') --> <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> </span> + <!-- /ko --> + <!-- ko if: isPriceExclTaxDisplayed() && !getRegion('row_excl_tax') --> + <span class="price-excluding-tax" data-bind ="text: getValueExclTax($parents[1]), attr:{'data-label': $t('Excl. Tax')}"> + </span> <!-- /ko --> - <!-- ko if: isPriceExclTaxDisplayed() --> + <!-- ko if: isPriceExclTaxDisplayed() && getRegion('row_excl_tax') --> <span class="price-excluding-tax" data-bind ="attr:{'data-label': $t('Excl. Tax')}"> <!-- ko foreach: getRegion('row_excl_tax') --> <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> </span> <!-- /ko --> -</td> \ No newline at end of file +</div> \ No newline at end of file diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/shipping.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/shipping.html new file mode 100644 index 0000000000000000000000000000000000000000..8caba625561dfde89afdef0c04a97dbfb0de6c0e --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/shipping.html @@ -0,0 +1,78 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: quoteIsVirtual == 0 --> + <!-- ko if: isBothPricesDisplayed() --> + <tr class="totals shipping excl"> + <th class="mark" scope="row"> + <span class="label" data-bind="text: $t(title) + ' ' + $t(excludingTaxMessage)"></span> + <span class="value" data-bind="text: $t(getShippingMethodTitle())"></span> + </th> + <td class="amount"> + <!-- ko if: isCalculated() --> + <span class="price" + data-bind="text: $t(getExcludingValue()), attr: {'data-th': $t(excludingTaxMessage)}"></span> + <!-- /ko --> + <!-- ko ifnot: isCalculated() --> + <span class="not-calculated" + data-bind="text: $t(getExcludingValue()), attr: {'data-th': $t(excludingTaxMessage)}"></span> + <!-- /ko --> + </td> + </tr> + <tr class="totals shipping incl"> + <th class="mark" scope="row"> + <span class="label" data-bind="text: $t(title) + ' ' + $t(includingTaxMessage)"></span> + <span class="value" data-bind="text: $t(getShippingMethodTitle())"></span> + </th> + <td class="amount"> + <!-- ko if: isCalculated() --> + <span class="price" + data-bind="text: $t(getIncludingValue()), attr: {'data-th': $t(title) + ' ' + $t(excludingTaxMessage)}"></span> + <!-- /ko --> + <!-- ko ifnot: isCalculated() --> + <span class="not-calculated" + data-bind="text: $t(getIncludingValue()), attr: {'data-th': $t(title) + ' ' + $t(excludingTaxMessage)}"></span> + <!-- /ko --> + </td> + </tr> + <!-- /ko --> + <!-- ko if: isIncludingDisplayed() --> + <tr class="totals shipping incl"> + <th class="mark" scope="row"> + <span class="label" data-bind="text: $t(title)"></span> + <span class="value" data-bind="text: $t(getShippingMethodTitle())"></span> + </th> + <td class="amount"> + <!-- ko if: isCalculated() --> + <span class="price" + data-bind="text: $t(getIncludingValue()), attr: {'data-th': $t(title)}"></span> + <!-- /ko --> + <!-- ko ifnot: isCalculated() --> + <span class="not-calculated" + data-bind="text: $t(getIncludingValue()), attr: {'data-th': $t(title)}"></span> + <!-- /ko --> + </td> + </tr> + <!-- /ko --> + <!-- ko if: isExcludingDisplayed() --> + <tr class="totals shipping excl"> + <th class="mark" scope="row"> + <span class="label" data-bind="text: $t(title)"></span> + <span class="value" data-bind="text: $t(getShippingMethodTitle())"></span> + </th> + <td class="amount"> + <!-- ko if: isCalculated() --> + <span class="price" + data-bind="text: $t(getValue()), attr: {'data-th': $t(title)}"></span> + <!-- /ko --> + <!-- ko ifnot: isCalculated() --> + <span class="not-calculated" + data-bind="text: $t(getValue()), attr: {'data-th': $t(title)}"></span> + <!-- /ko --> + </td> + </tr> + <!-- /ko --> +<!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/subtotal.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/subtotal.html new file mode 100644 index 0000000000000000000000000000000000000000..4652d47e5e35a6b7a868c795ac946999b43b6612 --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/subtotal.html @@ -0,0 +1,42 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: isBothPricesDisplayed() --> +<tr class="totals sub excl"> + <th class="mark" scope="row"> + <span data-bind="text: $t(title)"></span> + <span data-bind="text: $t(excludingTaxMessage)"></span> + </th> + <td class="amount"> + <span class="price" data-bind="text: getValue(), attr: {'data-th': $t(excludingTaxMessage) }"></span> + </td> +</tr> +<tr class="totals sub incl"> + <th class="mark" scope="row"> + <span data-bind="text: $t(title)"></span> + <span data-bind="text: $t(includingTaxMessage)"></span> + </th> + <td class="amount"> + <span class="price" data-bind="text: getValueInclTax(), attr: {'data-th': $t(includingTaxMessage) }"></span> + </td> +</tr> +<!-- /ko --> +<!-- ko if: !isBothPricesDisplayed() && isIncludingTaxDisplayed() --> +<tr class="totals sub"> + <th data-bind="text: $t(title)" class="mark" scope="row"></th> + <td class="amount"> + <span class="price" data-bind="text: getValueInclTax(), attr: {'data-th': $t(title)}"></span> + </td> +</tr> +<!-- /ko --> +<!-- ko if: !isBothPricesDisplayed() && !isIncludingTaxDisplayed() --> +<tr class="totals sub"> + <th data-bind="text: $t(title)" class="mark" scope="row"></th> + <td class="amount"> + <span class="price" data-bind="text: getValue(), attr: {'data-th': $t(title)}"></span> + </td> +</tr> +<!-- /ko --> diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/tax.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/tax.html new file mode 100644 index 0000000000000000000000000000000000000000..5b2b739402261b01f95e51d363961e015d840c1a --- /dev/null +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/tax.html @@ -0,0 +1,61 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: ifShowValue() && !ifShowDetails() --> +<tr class="totals-tax"> + <th data-bind="text: $t(title)" class="mark" scope="row"></th> + <td data-bind="attr: {'data-th': $t(title) }" class="amount"> + <!-- ko if: isCalculated() --> + <span class="price" + data-bind="text: $t(getValue())"></span> + <!-- /ko --> + <!-- ko ifnot: isCalculated() --> + <span class="not-calculated" + data-bind="text: $t(getValue())"></span> + <!-- /ko --> + </td> +</tr> +<!-- /ko --> +<!-- ko if: ifShowValue() && ifShowDetails() --> + <tr class="totals-tax-summary" + data-bind="mageInit: {'toggleAdvanced':{'selectorsToggleClass': 'shown', 'baseToggleClass': 'expanded', 'toggleContainers': '.totals-tax-details'}}"> + <th data-bind="text: $t(title)" class="mark" scope="row"></th> + <td data-bind="attr: {'data-th': $t(title) }" class="amount"> + <!-- ko if: isCalculated() --> + <span class="price" + data-bind="text: $t(getValue())"></span> + <!-- /ko --> + <!-- ko ifnot: isCalculated() --> + <span class="not-calculated" + data-bind="text: $t(getValue())"></span> + <!-- /ko --> + </td> + </tr> + <!-- ko foreach: getDetails() --> + <!-- ko foreach: rates --> + <tr class="totals-tax-details"> + <!-- ko if: percent --> + <th class="mark" scope="row" data-bind="text: title + ' (' + percent + '%)'"></th> + <!-- /ko --> + <!-- ko if: !percent --> + <th class="mark" scope="row" data-bind="text: title"></th> + <!-- /ko --> + <!-- ko if: $index() == 0 --> + <td class="amount"> + <!-- ko if: $parents[1].isCalculated() --> + <span class="price" + data-bind="text: $parents[1].formatPrice($parents[0].amount), attr: {'data-th': title, 'rowspan': $parents[0].rates.length }"></span> + <!-- /ko --> + <!-- ko ifnot: $parents[1].isCalculated() --> + <span class="not-calculated" + data-bind="text: $parents[1].formatPrice($parents[0].amount), attr: {'data-th': title, 'rowspan': $parents[0].rates.length }"></span> + <!-- /ko --> + </td> + <!-- /ko --> + </tr> + <!-- /ko --> + <!-- /ko --> +<!-- /ko --> diff --git a/app/code/Magento/Ui/Component/AbstractComponent.php b/app/code/Magento/Ui/Component/AbstractComponent.php index c7af5b3f471c7c084826bc98c45a0ab6c2610cb2..0a15bafe9915faa5aefea6f006e169ea626523db 100644 --- a/app/code/Magento/Ui/Component/AbstractComponent.php +++ b/app/code/Magento/Ui/Component/AbstractComponent.php @@ -8,14 +8,13 @@ namespace Magento\Ui\Component; use Magento\Framework\Object; use Magento\Framework\View\Element\UiComponentInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; -use Magento\Framework\View\Element\UiComponent\JsConfigInterface; use Magento\Framework\View\Element\UiComponent\DataSourceInterface; /** * Abstract class AbstractComponent * @SuppressWarnings(PHPMD.NumberOfChildren) */ -abstract class AbstractComponent extends Object implements UiComponentInterface, JsConfigInterface +abstract class AbstractComponent extends Object implements UiComponentInterface { /** * Render context @@ -227,6 +226,7 @@ abstract class AbstractComponent extends Object implements UiComponentInterface, * * @param array $dataSource * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function prepareDataSource(array & $dataSource) { diff --git a/app/code/Magento/Ui/Component/Container.php b/app/code/Magento/Ui/Component/Container.php index 6b642b9a3e04525c63ac0df53a8c6113eb44cf66..352dfdf2942bcd5d1557d1f9df5041c588f1074e 100644 --- a/app/code/Magento/Ui/Component/Container.php +++ b/app/code/Magento/Ui/Component/Container.php @@ -5,8 +5,6 @@ */ namespace Magento\Ui\Component; -use Magento\Framework\View\Element\UiComponent\DataSourceInterface; - /** * Class Container */ diff --git a/app/code/Magento/Ui/Component/Form.php b/app/code/Magento/Ui/Component/Form.php index ed0b344658a30c610169de97e9de8aaeb20d41f8..ee1e32e30e07e954786963644079ba439842ae0a 100644 --- a/app/code/Magento/Ui/Component/Form.php +++ b/app/code/Magento/Ui/Component/Form.php @@ -5,8 +5,6 @@ */ namespace Magento\Ui\Component; -use Magento\Framework\View\Element\UiComponent\DataSourceInterface; - /** * Class Form */ diff --git a/app/code/Magento/Ui/Component/Form/Element/Multiline.php b/app/code/Magento/Ui/Component/Form/Element/Multiline.php index 5f508343d4316fbf6b3f788fddab37057d669474..3669cd079a44f56e85d0c816da41f7cdb78b675e 100644 --- a/app/code/Magento/Ui/Component/Form/Element/Multiline.php +++ b/app/code/Magento/Ui/Component/Form/Element/Multiline.php @@ -5,6 +5,11 @@ */ namespace Magento\Ui\Component\Form\Element; +use Magento\Ui\Component\Form\Field; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; + /** * Class Multiline */ @@ -12,6 +17,35 @@ class Multiline extends AbstractElement { const NAME = 'multiline'; + const FORM_ELEMENT = 'input'; + + const DATA_TYPE = 'text'; + + /** + * UI component factory + * + * @var UiComponentFactory + */ + protected $uiComponentFactory; + + /** + * Constructor + * + * @param ContextInterface $context + * @param UiComponentFactory $uiComponentFactory + * @param UiComponentInterface[] $components + * @param array $data + */ + public function __construct( + ContextInterface $context, + UiComponentFactory $uiComponentFactory, + array $components = [], + array $data = [] + ) { + $this->uiComponentFactory = $uiComponentFactory; + parent::__construct($context, $components, $data); + } + /** * Get component name * @@ -23,10 +57,37 @@ class Multiline extends AbstractElement } /** - * @return mixed|string + * Prepare component configuration + * + * @return void */ - public function getType() + public function prepare() { - return $this->getData('input_type') ? $this->getData('input_type') : 'text'; + $size = abs((int) $this->getData('config/size')); + $validation = [$this->getData('config/validation')]; + while ($size--) { + $identifier = $this->getName() . '_' . $size; + $arguments = [ + 'data' => [ + 'name' => $identifier, + 'config' => [ + 'dataScope' => $size, + 'dataType' => static::DATA_TYPE, + 'formElement' => static::FORM_ELEMENT, + 'sortOrder' => $size, + ] + ] + ]; + + if (!empty($validation[$size])) { + $arguments['data']['config']['validation'] = $validation[$size]; + } + + $component = $this->uiComponentFactory->create($identifier, Field::NAME, $arguments); + $component->prepare(); + + $this->components[$identifier] = $component; + } + parent::prepare(); } } diff --git a/app/code/Magento/Ui/Component/Form/Field.php b/app/code/Magento/Ui/Component/Form/Field.php index 670fa9004b6752f1afad78854824a9a0b66547c3..d2ff377ae5bd4868179d4bef1db12cf640df4fb5 100644 --- a/app/code/Magento/Ui/Component/Form/Field.php +++ b/app/code/Magento/Ui/Component/Form/Field.php @@ -80,23 +80,23 @@ class Field extends AbstractComponent $formElement, array_merge(['context' => $this->getContext()], (array)$this->getData()) ); + $this->wrappedComponent->setData( + 'config', + array_replace_recursive( + (array) $this->wrappedComponent->getData('config'), + (array) $this->getData('config') + ) + ); $this->wrappedComponent->prepare(); + $this->components = $this->wrappedComponent->getChildComponents(); // Merge JS configuration with wrapped component configuration $wrappedComponentConfig = $this->getJsConfig($this->wrappedComponent); - $jsConfig = array_replace_recursive( - $wrappedComponentConfig, - $this->getJsConfig($this) - ); + + $jsConfig = array_replace_recursive($wrappedComponentConfig, $this->getJsConfig($this)); $jsConfig['extends'] = $this->wrappedComponent->getComponentName(); $this->setData('js_config', $jsConfig); - $this->setData( - 'config', - array_replace_recursive( - (array)$this->wrappedComponent->getData('config'), - (array)$this->getData('config') - ) - ); + $this->setData('config', $this->wrappedComponent->getData('config')); parent::prepare(); } diff --git a/app/code/Magento/Ui/Component/Form/Fieldset.php b/app/code/Magento/Ui/Component/Form/Fieldset.php index 00a1b0579e9e8e6767a2fcd17e41ed46be0f2cd1..45d03c005f602734617487639dda3f1f91748d7a 100644 --- a/app/code/Magento/Ui/Component/Form/Fieldset.php +++ b/app/code/Magento/Ui/Component/Form/Fieldset.php @@ -5,7 +5,6 @@ */ namespace Magento\Ui\Component\Form; -use Magento\Framework\Exception\LocalizedException; use Magento\Ui\Component\Container; use Magento\Ui\Component\AbstractComponent; use Magento\Framework\View\Element\UiComponentFactory; @@ -104,7 +103,7 @@ class Fieldset extends AbstractComponent 'config' => $fieldData ] ]; - $fieldComponent = $this->uiComponentFactory->create($name, 'field', $argument); + $fieldComponent = $this->uiComponentFactory->create($name, Field::NAME, $argument); $fieldComponent->prepare(); $this->addComponent($name, $fieldComponent); } else { diff --git a/app/code/Magento/Ui/Component/Layout/Generic.php b/app/code/Magento/Ui/Component/Layout/Generic.php index 0d8ee7d0cea07c5dcda4197b2dcf68833aa572ae..92d0a406f38e067fd5fc189ae3e1821fd788eeac 100644 --- a/app/code/Magento/Ui/Component/Layout/Generic.php +++ b/app/code/Magento/Ui/Component/Layout/Generic.php @@ -6,7 +6,6 @@ namespace Magento\Ui\Component\Layout; use Magento\Framework\View\Element\UiComponent\DataSourceInterface; -use Magento\Framework\View\Element\UiComponent\JsConfigInterface; use Magento\Framework\View\Element\UiComponent\LayoutInterface; use Magento\Framework\View\Element\UiComponentInterface; diff --git a/app/code/Magento/Ui/Component/Listing.php b/app/code/Magento/Ui/Component/Listing.php index 7d7d7b692b26042a08d41295f7a24d6536fd1802..363144c10d29a3991d070e65299de367be2425d1 100644 --- a/app/code/Magento/Ui/Component/Listing.php +++ b/app/code/Magento/Ui/Component/Listing.php @@ -6,8 +6,6 @@ namespace Magento\Ui\Component; use Magento\Ui\Component\Listing\Columns; -use Magento\Ui\Component\Listing\Columns\Column; -use Magento\Framework\View\Element\UiComponent\DataSourceInterface; /** * Class Listing diff --git a/app/code/Magento/Ui/DataProvider/EavValidationRul.php b/app/code/Magento/Ui/DataProvider/EavValidationRules.php similarity index 96% rename from app/code/Magento/Ui/DataProvider/EavValidationRul.php rename to app/code/Magento/Ui/DataProvider/EavValidationRules.php index 1d338ec30755af34f8653ca99b65f8202b141d7a..28551180b16fb4e33da680fe0f24211639f35bd7 100644 --- a/app/code/Magento/Ui/DataProvider/EavValidationRul.php +++ b/app/code/Magento/Ui/DataProvider/EavValidationRules.php @@ -8,9 +8,9 @@ namespace Magento\Ui\DataProvider; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; /** - * Class EavValidationRul + * Class EavValidationRules */ -class EavValidationRul +class EavValidationRules { /** * @var array diff --git a/app/code/Magento/Ui/Test/Unit/Component/Form/Field/MultilineTest.php b/app/code/Magento/Ui/Test/Unit/Component/Form/Field/MultilineTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c1e717c1525fed4c226a20a697b0e9ce5f488172 --- /dev/null +++ b/app/code/Magento/Ui/Test/Unit/Component/Form/Field/MultilineTest.php @@ -0,0 +1,137 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Ui\Test\Unit\Component\Form\Field; + +use Magento\Ui\Component\Form\Field; +use Magento\Ui\Component\Form\Element\Multiline; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; + +/** + * Class MultilineTest + * + * Test for class \Magento\Ui\Component\Form\Element\Multiline + */ +class MultilineTest extends \PHPUnit_Framework_TestCase +{ + const NAME = 'test-name'; + + /** + * @var Multiline + */ + protected $multiline; + + /** + * @var UiComponentFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $uiComponentFactoryMock; + + /** + * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $contextMock; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->uiComponentFactoryMock = $this->getMockBuilder('Magento\Framework\View\Element\UiComponentFactory') + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder('Magento\Framework\View\Element\UiComponent\ContextInterface') + ->getMockForAbstractClass(); + + $this->multiline = new Multiline( + $this->contextMock, + $this->uiComponentFactoryMock + ); + } + + /** + * Run test for prepare method + * + * @param array $data + * @return void + * + * @dataProvider prepareDataProvider + */ + public function testPrepare(array $data) + { + $this->uiComponentFactoryMock->expects($this->exactly($data['config']['size'])) + ->method('create') + ->with($this->stringContains(self::NAME . '_'), Field::NAME, $this->logicalNot($this->isEmpty())) + ->willReturn($this->getComponentMock($data['config']['size'])); + + $this->multiline->setData($data); + $this->multiline->prepare(); + + $result = $this->multiline->getData(); + + $this->assertEquals($data, $result); + } + + /** + * @param int $exactly + * @return UiComponentInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getComponentMock($exactly) + { + $componentMock = $this->getMockBuilder('Magento\Framework\View\Element\UiComponentInterface') + ->getMockForAbstractClass(); + + $componentMock->expects($this->exactly($exactly)) + ->method('prepare'); + + return $componentMock; + } + + /** + * Data provider for testPrepare + * + * @return array + */ + public function prepareDataProvider() + { + return [ + [ + 'data' => [ + 'name' => self::NAME, + 'config' => [ + 'size' => 2, + ] + ], + ], + [ + 'data' => [ + 'name' => self::NAME, + 'config' => [ + 'size' => 3, + ] + ], + ], + [ + 'data' => [ + 'name' => self::NAME, + 'config' => [ + 'size' => 1, + ] + ], + ], + [ + 'data' => [ + 'name' => self::NAME, + 'config' => [ + 'size' => 5, + ] + ], + ], + ]; + } +} diff --git a/app/code/Magento/Ui/Test/Unit/Component/Form/FieldTest.php b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldTest.php new file mode 100644 index 0000000000000000000000000000000000000000..86a47115d31129abfedb6fe3ceafafc394879912 --- /dev/null +++ b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldTest.php @@ -0,0 +1,177 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Ui\Test\Unit\Component\Form; + +use Magento\Ui\Component\Form\Field; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; + +/** + * Class FieldTest + * + * Test for class \Magento\Ui\Component\Form\Field + */ +class FieldTest extends \PHPUnit_Framework_TestCase +{ + const NAME = 'test-name'; + const COMPONENT_NAME = 'test-name'; + const COMPONENT_NAMESPACE = 'test-name'; + + /** + * @var Field + */ + protected $field; + + /** + * @var UiComponentFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $uiComponentFactoryMock; + + /** + * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $contextMock; + + /** + * @var array + */ + protected $testConfigData = [ + ['config', null, ['test-key' => 'test-value']], + ['js_config', null, ['test-key' => 'test-value']] + ]; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->uiComponentFactoryMock = $this->getMockBuilder('Magento\Framework\View\Element\UiComponentFactory') + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder('Magento\Framework\View\Element\UiComponent\ContextInterface') + ->getMockForAbstractClass(); + + $this->field = new Field( + $this->contextMock, + $this->uiComponentFactoryMock + ); + } + + /** + * Run test for prepare method + * + * @param array $data + * @param array $expectedData + * @return void + * + * @dataProvider prepareSuccessDataProvider + */ + public function testPrepareSuccess(array $data, array $expectedData) + { + $this->uiComponentFactoryMock->expects($this->once()) + ->method('create') + ->with(self::NAME, $data['config']['formElement'], $this->arrayHasKey('context')) + ->willReturn($this->getWrappedComponentMock()); + + $this->contextMock->expects($this->any()) + ->method('getNamespace') + ->willReturn(self::COMPONENT_NAMESPACE); + + $this->field->setData($data); + $this->field->prepare(); + $result = $this->field->getData(); + + $this->assertEquals($expectedData, $result); + } + + /** + * Data provider for testPrepare + * + * @return array + */ + public function prepareSuccessDataProvider() + { + return [ + [ + 'data' => [ + 'name' => self::NAME, + 'config' => [ + 'formElement' => 'test', + ] + ], + 'expectedData' => [ + 'name' => self::NAME, + 'config' => [ + 'test-key' => 'test-value', + ], + 'js_config' => [ + 'extends' => self::NAME, + 'test-key' => 'test-value', + ] + ] + ], + ]; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|UiComponentInterface + */ + protected function getWrappedComponentMock() + { + $wrappedComponentMock = $this->getMockBuilder('Magento\Framework\View\Element\UiComponentInterface') + ->getMockForAbstractClass(); + + $wrappedComponentMock->expects($this->any()) + ->method('getData') + ->willReturnMap($this->testConfigData); + $wrappedComponentMock->expects($this->once()) + ->method('setData') + ->with('config', $this->logicalNot($this->isEmpty())); + $wrappedComponentMock->expects($this->once()) + ->method('prepare'); + $wrappedComponentMock->expects($this->once()) + ->method('getChildComponents') + ->willReturn($this->getComponentsMock()); + $wrappedComponentMock->expects($this->exactly(2)) + ->method('getComponentName') + ->willReturn(self::COMPONENT_NAME); + $wrappedComponentMock->expects($this->once()) + ->method('getContext') + ->willReturn($this->contextMock); + + return $wrappedComponentMock; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject[]|UiComponentInterface[] + */ + protected function getComponentsMock() + { + $componentMock = $this->getMockBuilder('Magento\Framework\View\Element\UiComponentInterface') + ->getMockForAbstractClass(); + + return [$componentMock]; + } + + /** + * Run test prepare method (Exception) + * + * @return void + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage The configuration parameter "formElement" is a required for "test-name" field. + */ + public function testPrepareException() + { + $this->uiComponentFactoryMock->expects($this->never()) + ->method('create'); + $this->field->setData(['name' => self::NAME]); + $this->field->prepare(); + } +} diff --git a/app/code/Magento/Ui/etc/ui_components.xsd b/app/code/Magento/Ui/etc/ui_components.xsd index 86a6f5aaeca39cee9fccbc8f6714446f57d87872..17a80e2f4ac37e725e061d347aeb431e23162244 100644 --- a/app/code/Magento/Ui/etc/ui_components.xsd +++ b/app/code/Magento/Ui/etc/ui_components.xsd @@ -177,6 +177,15 @@ </xs:extension> </xs:complexContent> </xs:complexType> + <xs:complexType name="multiline"> + <xs:complexContent> + <xs:extension base="ui_element"> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:group ref="configurable"/> + </xs:choice> + </xs:extension> + </xs:complexContent> + </xs:complexType> <xs:complexType name="fieldset"> <xs:complexContent> <xs:extension base="ui_element"> diff --git a/app/code/Magento/Ui/etc/ui_definition.xsd b/app/code/Magento/Ui/etc/ui_definition.xsd index 171b3e1b7dbef8660f7cee0d70f38d39cfb3336f..f0154eecb99647f17d7bb96c9c9c7c554806f0d1 100644 --- a/app/code/Magento/Ui/etc/ui_definition.xsd +++ b/app/code/Magento/Ui/etc/ui_definition.xsd @@ -39,6 +39,7 @@ <xs:element type="select" name="select"/> <xs:element type="multiselect" name="multiselect"/> <xs:element type="textarea" name="textarea"/> + <xs:element type="multiline" name="multiline"/> <xs:element type="dataTypeText" name="text"/> <xs:element type="dataTypeBoolean" name="boolean"/> <xs:element type="dataTypeNumber" name="number"/> diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml b/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml index 54e661645fec41aba65109bd3025aa626c27cb0b..df5cfa21eca0a080805e940d75726c60f188141f 100644 --- a/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml +++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml @@ -178,6 +178,13 @@ </item> </argument> </textarea> + <multiline class="Magento\Ui\Component\Form\Element\Multiline"> + <argument name="data" xsi:type="array"> + <item name="js_config" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Ui/js/form/components/group</item> + </item> + </argument> + </multiline> <!-- Form elements --> <!-- Form element data types --> diff --git a/app/code/Magento/Ui/view/base/web/js/block-loader.js b/app/code/Magento/Ui/view/base/web/js/block-loader.js new file mode 100644 index 0000000000000000000000000000000000000000..e3cb1b422bb31f070307e26f8f037cb3753f4e99 --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/js/block-loader.js @@ -0,0 +1,90 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'ko', + 'jquery', + 'Magento_Ui/js/lib/loader', + 'mage/template' +], function (ko, $, templateLoader, template) { + 'use strict'; + + var blockLoaderTemplatePath = 'ui/block-loader', + blockContentLoadingClass = '_block-content-loading', + blockLoader, + blockLoaderClass, + loaderImageHref; + + templateLoader.loadTemplate(blockLoaderTemplatePath).done(function (blockLoaderTemplate) { + blockLoader = template($.trim(blockLoaderTemplate), { + loaderImageHref: loaderImageHref + }); + blockLoader = $(blockLoader); + blockLoaderClass = '.' + blockLoader.attr('class'); + }); + + /** + * Helper function to check if blockContentLoading class should be applied. + * @param {Object} element + * @returns {Boolean} + */ + function isLoadingClassRequired(element) { + var position = element.css('position'); + + if (position === 'absolute' || position === 'fixed') { + return false; + } + + return true; + } + + /** + * Add loader to block. + * @param {Object} element + */ + function addBlockLoader(element) { + element.find(':focus').blur(); + element.find('input:disabled, select:disabled').addClass('_disabled'); + element.find('input, select').prop('disabled', true); + + if (isLoadingClassRequired(element)) { + element.addClass(blockContentLoadingClass); + } + element.append(blockLoader.clone()); + } + + /** + * Remove loader from block. + * @param {Object} element + */ + function removeBlockLoader(element) { + if (!element.has(blockLoaderClass).length) { + return; + } + element.find(blockLoaderClass).remove(); + element.find('input:not("._disabled"), select:not("._disabled")').prop('disabled', false); + element.find('input:disabled, select:disabled').removeClass('_disabled'); + element.removeClass(blockContentLoadingClass); + } + + return function (loaderHref) { + loaderImageHref = loaderHref; + ko.bindingHandlers.blockLoader = { + /** + * Process loader for block + * @param {String} element + * @param {Boolean} displayBlockLoader + */ + update: function (element, displayBlockLoader) { + element = $(element); + + if (ko.unwrap(displayBlockLoader())) { + addBlockLoader(element); + } else { + removeBlockLoader(element); + } + } + }; + }; +}); diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/group.js b/app/code/Magento/Ui/view/base/web/js/form/components/group.js index aeb0ce9db858cc9f7a36dd1c7b41684476830e6b..1e0ff9ac97a3259adc764509c57b49bd379c3a0f 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/group.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/group.js @@ -35,7 +35,10 @@ define([ */ initObservable: function () { this._super() - .observe('visible required'); + .observe('visible') + .observe({ + required: !!+this.required + }); return this; }, diff --git a/app/code/Magento/Ui/view/base/web/js/modal/modal.js b/app/code/Magento/Ui/view/base/web/js/modal/modal.js index 1b9c0c18860a88b2faccfa8490a5c243746ce6b5..aa415e7aeacebaf5d9ffed007bdc3cbe5a59e9fa 100644 --- a/app/code/Magento/Ui/view/base/web/js/modal/modal.js +++ b/app/code/Magento/Ui/view/base/web/js/modal/modal.js @@ -8,9 +8,10 @@ define([ "mage/template", "text!ui/template/modal/modal-popup.html", "text!ui/template/modal/modal-slide.html", + "text!ui/template/modal/modal-custom.html", "jquery/ui", "mage/translate" -], function($, _, template, popupTpl, slideTpl){ +], function($, _, template, popupTpl, slideTpl, customTpl){ "use strict"; /** @@ -23,6 +24,7 @@ define([ modalClass: '', popupTpl: popupTpl, slideTpl: slideTpl, + customTpl: customTpl, modalVisibleClass: '_show', parentModalClass: '_has-modal', innerScrollClass: '_inner-scroll', @@ -36,6 +38,7 @@ define([ wrapperClass: 'modals-wrapper', overlayClass: 'modals-overlay', responsiveClass: 'modal-slide', + trigger: '', modalLeftMargin: 45, closeText: $.mage.__('Close'), buttons: [{ @@ -56,6 +59,7 @@ define([ this._createButtons(); this.modal.find(this.options.modalCloseBtn).on('click', _.bind(this.closeModal, this)); + $(this.options.trigger).on('click', _.bind(this.toggleModal, this)); this.element.on('openModal', _.bind(this.openModal, this)); this.element.on('closeModal', _.bind(this.closeModal, this)); }, @@ -82,6 +86,13 @@ define([ return elems.filter('.'+this.options.modalVisibleClass).length; }, + toggleModal: function() { + if (this.options.isOpen == true) { + this.closeModal(); + } else { + this.openModal(); + } + }, openModal: function() { var that = this; diff --git a/app/code/Magento/Ui/view/base/web/templates/block-loader.html b/app/code/Magento/Ui/view/base/web/templates/block-loader.html new file mode 100644 index 0000000000000000000000000000000000000000..cc98e6a19688cfc7d3e92d4d7c0753075dcd901c --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/templates/block-loader.html @@ -0,0 +1,11 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div data-role="loader" class="loading-mask" style="position: absolute;"> + <div class="loader"> + <img src="<%= loaderImageHref %>" alt="Loading..." style="position: absolute;"> + </div> +</div> \ No newline at end of file diff --git a/app/code/Magento/Ui/view/base/web/templates/modal/modal-custom.html b/app/code/Magento/Ui/view/base/web/templates/modal/modal-custom.html new file mode 100644 index 0000000000000000000000000000000000000000..990630aa02b9c1ee71088b56bd345ed33e4d3a6e --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/templates/modal/modal-custom.html @@ -0,0 +1,38 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<aside class="modal-<%= data.type %> <%= data.modalClass %> + <% if(data.responsive){ %><%= data.responsiveClass %><% } %> + <% if(data.innerScroll){ %><%= data.innerScrollClass %><% } %>" + data-role="modal" + data-type="<%= data.type %>"> + <div class="modal-inner-wrap"> + <header class="modal-header"> + <% if(data.title){ %> + <h1 class="modal-title" + data-role="title"><%= data.title %></h1> + <% } %> + <button + class="action-close" + data-role="closeBtn" + type="button"> + <span><%= data.closeText %></span> + </button> + </header> + <div class="modal-content" data-role="content"></div> + <% if(data.buttons.length > 0){ %> + <footer class="modal-footer"> + <% _.each(data.buttons, function(button) { %> + <button + class="<%= button.class %>" + type="button" + data-role="action"><span><%= button.text %></span></button> + <% }); %> + </footer> + <% } %> + </div> +</aside> diff --git a/app/code/Magento/Ui/view/base/web/templates/modal/modal-popup.html b/app/code/Magento/Ui/view/base/web/templates/modal/modal-popup.html index 7c45aefbb35a66ab80274fa4891f31804b246f93..43ac20b2aeb1e26bce6330232755be77e5c4605c 100644 --- a/app/code/Magento/Ui/view/base/web/templates/modal/modal-popup.html +++ b/app/code/Magento/Ui/view/base/web/templates/modal/modal-popup.html @@ -13,8 +13,10 @@ data-type="<%= data.type %>"> <div class="modal-inner-wrap"> <header class="modal-header"> + <% if(data.title){ %> <h1 class="modal-title" data-role="title"><%= data.title %></h1> + <% } %> <button class="action-close" data-role="closeBtn" @@ -25,6 +27,7 @@ <div class="modal-content" data-role="content"></div> + <% if(data.buttons.length > 0){ %> <footer class="modal-footer"> <% _.each(data.buttons, function(button) { %> <button @@ -33,5 +36,6 @@ data-role="action"><span><%= button.text %></span></button> <% }); %> </footer> + <% } %> </div> </aside> diff --git a/app/code/Magento/Ui/view/base/web/templates/modal/modal-slide.html b/app/code/Magento/Ui/view/base/web/templates/modal/modal-slide.html index dbe99544b3e076a5d5fb670caad2ecdd77671437..abffa4573962a7acc129a0f3f0a96c2765240731 100644 --- a/app/code/Magento/Ui/view/base/web/templates/modal/modal-slide.html +++ b/app/code/Magento/Ui/view/base/web/templates/modal/modal-slide.html @@ -12,14 +12,17 @@ data-type="<%= data.type %>"> <div class="modal-inner-wrap"> <header class="modal-header"> + <% if(data.title){ %> <h1 class="modal-title" data-role="title"><%= data.title %></h1> + <% } %> <button class="action-close" data-role="closeBtn" type="button"> <span><%= data.closeText %></span> </button> + <% if(data.buttons.length > 0){ %> <div class="page-main-actions"> <div class="page-actions"> <div class="page-actions-buttons"> @@ -33,6 +36,7 @@ </div> </div> </div> + <% } %> </header> <div class="modal-content" data-role="content"></div> </div> diff --git a/app/code/Magento/Ui/view/frontend/web/js/model/errorlist.js b/app/code/Magento/Ui/view/frontend/web/js/model/errorlist.js deleted file mode 100644 index 4eca983e1f4334cc21901eec3b3a95245956c7d9..0000000000000000000000000000000000000000 --- a/app/code/Magento/Ui/view/frontend/web/js/model/errorlist.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*global define*/ -define(['ko'], function(ko) { - "use strict"; - var errors = ko.observableArray([]); - return { - add: function (error) { - var expr = /([%])\w+/g, - errorMessage; - if (!error.hasOwnProperty('parameters')) { - this.clear(); - errors.push(error.message); - return true; - } - errorMessage = error.message.replace(expr, function(varName) { - varName = varName.substr(1); - if (error.parameters.hasOwnProperty(varName)) { - return error.parameters[varName]; - } - return error.parameters.shift(); - }); - this.clear(); - errors.push(errorMessage); - return true; - }, - remove: function() { - errors.shift(); - }, - getAll: function () { - return errors; - }, - clear: function() { - errors.removeAll(); - } - }; -}); diff --git a/app/code/Magento/Ui/view/frontend/web/js/model/messageList.js b/app/code/Magento/Ui/view/frontend/web/js/model/messageList.js new file mode 100644 index 0000000000000000000000000000000000000000..15da0c25dc7922e8d69a51b5647597c2540c9db0 --- /dev/null +++ b/app/code/Magento/Ui/view/frontend/web/js/model/messageList.js @@ -0,0 +1,78 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define(['ko'], function (ko) { + 'use strict'; + + var errors = ko.observableArray([]); + var success = ko.observableArray([]); + + return { + errors: errors, + success: success, + /** + * Add message to list. + * @param {Object} messageObj + * @param {Object} type + * @returns {Boolean} + */ + add: function (messageObj, type) { + var expr = /([%])\w+/g, + message; + + if (!messageObj.hasOwnProperty('parameters')) { + this.clear(); + type.push(messageObj.message); + + return true; + } + message = messageObj.message.replace(expr, function (varName) { + varName = varName.substr(1); + + if (messageObj.parameters.hasOwnProperty(varName)) { + return messageObj.parameters[varName]; + } + + return messageObj.parameters.shift(); + }); + this.clear(); + errors.push(message); + + return true; + }, + addSuccessMessage: function (message) { + return this.add(message, this.success) + + }, + addErrorMessage: function (message) { + return this.add(message, this.errors) + }, + /** + * Remove first error message in list + */ + remove: function (type) { + type.shift(); + }, + /** + * Get all error messages + * @returns {Object} + */ + getAll: function () { + return errors; + }, + /** + * Clear error list + */ + clear: function () { + errors.removeAll(); + success.removeAll(); + }, + getAllErrors: function () { + return errors; + }, + getAllSuccess: function () { + return success; + } + }; +}); diff --git a/app/code/Magento/Ui/view/frontend/web/js/view/errors.js b/app/code/Magento/Ui/view/frontend/web/js/view/errors.js deleted file mode 100644 index 192a218bb4845cfccbef5d13a1664806bae574c7..0000000000000000000000000000000000000000 --- a/app/code/Magento/Ui/view/frontend/web/js/view/errors.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*global define*/ -define(['uiComponent', '../model/errorlist'], function (Component, errors) { - "use strict"; - return Component.extend({ - errorList: errors.getAll(), - defaults: { - template: 'Magento_Ui/errors' - } - }); -}); diff --git a/app/code/Magento/Ui/view/frontend/web/js/view/messages.js b/app/code/Magento/Ui/view/frontend/web/js/view/messages.js new file mode 100644 index 0000000000000000000000000000000000000000..02a5a2e6beb0ec893fd22b10c0a360d0984fa2d8 --- /dev/null +++ b/app/code/Magento/Ui/view/frontend/web/js/view/messages.js @@ -0,0 +1,31 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +define(['uiComponent', '../model/messageList'], function (Component, messages) { + 'use strict'; + + return Component.extend({ + errorList: messages.getAllErrors(), + successList: messages.getAllSuccess(), + + defaults: { + template: 'Magento_Ui/messages' + }, + + /** + * + * @returns {*} + */ + isVisible: function () { + return this.errorList().length || this.successList().length; + }, + /** + * Remove all errors + */ + removeAll: function () { + this.errorList.removeAll(); + this.successList.removeAll(); + } + }); +}); diff --git a/app/code/Magento/Ui/view/frontend/web/template/errors.html b/app/code/Magento/Ui/view/frontend/web/template/errors.html deleted file mode 100644 index 15d1bf5d80d2215869aa676d5acd7950a9c9c591..0000000000000000000000000000000000000000 --- a/app/code/Magento/Ui/view/frontend/web/template/errors.html +++ /dev/null @@ -1,11 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<div class="messages" data-bind="visible: errorList().length"> - <div class="message message-error error" data-bind="foreach: errorList"> - <div data-ui-id="checkout-cart-validationmessages-message-error" data-bind="text: $data"></div> - </div> -</div> \ No newline at end of file diff --git a/app/code/Magento/Ui/view/frontend/web/template/messages.html b/app/code/Magento/Ui/view/frontend/web/template/messages.html new file mode 100644 index 0000000000000000000000000000000000000000..d842c4b10ff29428a4427ad00f89a7529ece12ae --- /dev/null +++ b/app/code/Magento/Ui/view/frontend/web/template/messages.html @@ -0,0 +1,18 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="messages" data-bind="visible: isVisible(), click: removeAll"> + <!-- ko foreach: errorList --> + <div class="message message-error error"> + <div data-ui-id="checkout-cart-validationmessages-message-error" data-bind="text: $data"></div> + </div> + <!--/ko--> + <!-- ko foreach: successList --> + <div class="message message-success success"> + <div data-ui-id="checkout-cart-validationmessages-message-success" data-bind="text: $data"></div> + </div> + <!--/ko--> +</div> \ No newline at end of file diff --git a/app/code/Magento/Ui/view/frontend/web/templates/form/element/helper/tooltip.html b/app/code/Magento/Ui/view/frontend/web/templates/form/element/helper/tooltip.html new file mode 100644 index 0000000000000000000000000000000000000000..b2ef214e944a5e63c14f8b00f6d4297280baa284 --- /dev/null +++ b/app/code/Magento/Ui/view/frontend/web/templates/form/element/helper/tooltip.html @@ -0,0 +1,13 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> + <div class="field-tooltip toggle"> + <a class="field-tooltip-action action-help" target="_blank" data-bind="attr: {href: tooltip.link}"> + </a> + <div class="field-tooltip-content"> + <!-- ko text: tooltip.description --><!-- /ko --> + </div> +</div> diff --git a/app/code/Magento/Ui/view/frontend/web/templates/form/element/input.html b/app/code/Magento/Ui/view/frontend/web/templates/form/element/input.html index 75e6ff74dbe80b383441e20d4eea3dd2014d3743..e35184926cadcfd10f8a83883858be2d6e532761 100644 --- a/app/code/Magento/Ui/view/frontend/web/templates/form/element/input.html +++ b/app/code/Magento/Ui/view/frontend/web/templates/form/element/input.html @@ -6,6 +6,7 @@ --> <input class="input-text" type="text" data-bind=" value: value, + valueUpdate: 'keyup', hasFocus: focused, attr: { name: inputName, diff --git a/app/code/Magento/Ui/view/frontend/web/templates/form/field.html b/app/code/Magento/Ui/view/frontend/web/templates/form/field.html index fef8f712455113ecf7aca9f717e58192e7e0b58f..9f746c7e4542408b4e75475866a8d95676308a15 100644 --- a/app/code/Magento/Ui/view/frontend/web/templates/form/field.html +++ b/app/code/Magento/Ui/view/frontend/web/templates/form/field.html @@ -12,7 +12,7 @@ <!-- /ko --> </label> - <div class="control"> + <div class="control" data-bind="css: {'_with-tooltip': element.tooltip}"> <!-- ko ifnot: element.hasAddons() --> <!-- ko template: element.elementTmpl --><!-- /ko --> <!-- /ko --> diff --git a/app/code/Magento/Ups/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Ups/view/frontend/layout/checkout_onepage_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..50df5c58c00ce7af4c6dc661ad541bcdcad91ad4 --- /dev/null +++ b/app/code/Magento/Ups/view/frontend/layout/checkout_onepage_index.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="step-config" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-rates-validation" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="ups-rates-validation" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Ups/js/view/shipping-rates-validation</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validation-rules.js b/app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validation-rules.js new file mode 100644 index 0000000000000000000000000000000000000000..9f22914a8d29b73f75c2dfc51dfc776ed284e557 --- /dev/null +++ b/app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validation-rules.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function () { + "use strict"; + return { + getRules: function() { + return { + 'postcode': { + 'required': true + }, + 'country_id': { + 'required': true + } + }; + } + }; + } +); diff --git a/app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validator.js b/app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..71dac1b92c10ff0cab212709c93478227c2262c1 --- /dev/null +++ b/app/code/Magento/Ups/view/frontend/web/js/model/shipping-rates-validator.js @@ -0,0 +1,30 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'mageUtils', + './shipping-rates-validation-rules', + 'mage/translate' + ], + function ($, utils, validationRules, $t) { + "use strict"; + return { + validationErrors: [], + validate: function(address) { + var self = this; + this.validationErrors = []; + $.each(validationRules.getRules(), function(field, rule) { + if (rule.required && utils.isEmpty(address[field])) { + var message = $t('Field ') + field + $t(' is required.'); + self.validationErrors.push(message); + } + }); + return !Boolean(this.validationErrors.length); + } + }; + } +); diff --git a/app/code/Magento/Ups/view/frontend/web/js/view/shipping-rates-validation.js b/app/code/Magento/Ups/view/frontend/web/js/view/shipping-rates-validation.js new file mode 100644 index 0000000000000000000000000000000000000000..42d6e855218d13fa54bad60bd238a4469bb1a565 --- /dev/null +++ b/app/code/Magento/Ups/view/frontend/web/js/view/shipping-rates-validation.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-rates-validation-rules', + '../model/shipping-rates-validator', + '../model/shipping-rates-validation-rules' + ], + function ( + Component, + defaultShippingRatesValidator, + defaultShippingRatesValidationRules, + upsShippingRatesValidator, + upsShippingRatesValidationRules + ) { + "use strict"; + defaultShippingRatesValidator.registerValidator('ups', upsShippingRatesValidator); + defaultShippingRatesValidationRules.registerRules('ups', upsShippingRatesValidationRules); + return Component; + } +); diff --git a/app/code/Magento/Usps/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Usps/view/frontend/layout/checkout_onepage_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..ed6d123a6e4dfc7c7f443a2339a0f5cbfbac3d2f --- /dev/null +++ b/app/code/Magento/Usps/view/frontend/layout/checkout_onepage_index.xml @@ -0,0 +1,42 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> + <body> + <referenceBlock name="checkout.root"> + <arguments> + <argument name="jsLayout" xsi:type="array"> + <item name="components" xsi:type="array"> + <item name="checkout" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="steps" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-step" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="step-config" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="shipping-rates-validation" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="usps-rates-validation" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Usps/js/view/shipping-rates-validation</item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </item> + </argument> + </arguments> + </referenceBlock> + </body> +</page> diff --git a/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js new file mode 100644 index 0000000000000000000000000000000000000000..85ec105f7e4b3ab6886fa28534b0530b44e1a61c --- /dev/null +++ b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js @@ -0,0 +1,23 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [], + function () { + "use strict"; + return { + getRules: function() { + return { + 'country_id': { + 'required': true + }, + 'postcode': { + 'required': false + } + }; + } + }; + } +); diff --git a/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..b897eb4e83ccde4647aca4f656c4bbc67b261512 --- /dev/null +++ b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js @@ -0,0 +1,40 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*global define*/ +define( + [ + 'jquery', + 'mageUtils', + './shipping-rates-validation-rules', + 'mage/translate' + ], + function ($, utils, validationRules, $t) { + "use strict"; + var checkoutConfig = window.checkoutConfig; + + return { + validationErrors: [], + validate: function(address) { + var rules = validationRules.getRules(), + self = this; + + $.each(rules, function(field, rule) { + if (rule.required && utils.isEmpty(address[field])) { + var message = $t('Field ') + field + $t(' is required.'); + self.validationErrors.push(message); + } + }); + + if (!Boolean(this.validationErrors.length)) { + if (address.country_id == checkoutConfig.originCountryCode) { + return !utils.isEmpty(address.postcode); + } + return true; + } + return false; + } + }; + } +); diff --git a/app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js b/app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js new file mode 100644 index 0000000000000000000000000000000000000000..c47818efc2ede4a7aef4c48fcf7a4d58c5c712c9 --- /dev/null +++ b/app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js @@ -0,0 +1,27 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/shipping-rates-validator', + 'Magento_Checkout/js/model/shipping-rates-validation-rules', + '../model/shipping-rates-validator', + '../model/shipping-rates-validation-rules' + ], + function ( + Component, + defaultShippingRatesValidator, + defaultShippingRatesValidationRules, + uspsShippingRatesValidator, + uspsShippingRatesValidationRules + ) { + "use strict"; + defaultShippingRatesValidator.registerValidator('usps', uspsShippingRatesValidator); + defaultShippingRatesValidationRules.registerRules('usps', uspsShippingRatesValidationRules); + return Component; + } +); diff --git a/app/code/Magento/Weee/Test/Unit/Model/Total/Observer/Webapi/ItemTest.php b/app/code/Magento/Weee/Test/Unit/Model/Total/Observer/Webapi/ItemTest.php new file mode 100644 index 0000000000000000000000000000000000000000..772907c4b11381c761808f215afbaaba8fa9ae78 --- /dev/null +++ b/app/code/Magento/Weee/Test/Unit/Model/Total/Observer/Webapi/ItemTest.php @@ -0,0 +1,190 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Weee\Test\Unit\Model\Total\Observer\Webapi; + +class ItemTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $weeeHelperMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $storeManagerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $storeMock; + + /** + * @var \Magento\Weee\Model\Total\Observer\Webapi\Item + */ + protected $model; + + protected function setUp() + { + $this->weeeHelperMock = $this->getMock('Magento\Weee\Helper\Data', [], [], '', false); + $this->storeManagerMock = $this->getMock('Magento\Store\Model\StoreManagerInterface'); + $this->storeMock = $this->getMock('Magento\Store\Model\Store', [], [], '', false); + + $this->storeManagerMock->expects($this->any())->method('getStore')->will($this->returnValue($this->storeMock)); + + $this->model = new \Magento\Weee\Model\Total\Observer\Webapi\Item( + $this->weeeHelperMock, + $this->storeManagerMock + ); + } + + /** + * @dataProvider processTaxDataDataProvider + * + * @param bool $helperIsEnabled + * @param int $weeeTaxInclTax + * @param int $rowTotal + * @param bool $weeeTaxRowApplied + * @param int $rowTotalInclTax + * @param int $rowWeeeInclTax + * @param int $weeeTaxApplied + * @param int $weeeTaxAppliedAmount + * @param bool $includeWeeeFlag + * @param int $priceIncTax + * @param int $calculationPrice + * @param int $expectedRowTotal + * @param int $expectedRowInclTax + * @param int $expectedPrice + * @param int $expectedPriceInclTax + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function testProcessTaxData( + $helperIsEnabled, + $weeeTaxInclTax, + $rowTotal, + $weeeTaxRowApplied, + $rowTotalInclTax, + $rowWeeeInclTax, + $weeeTaxApplied, + $weeeTaxAppliedAmount, + $includeWeeeFlag, + $priceIncTax, + $calculationPrice, + $expectedRowTotal, + $expectedRowInclTax, + $expectedPrice, + $expectedPriceInclTax + ) { + $observerMock = $this->getMock('Magento\Framework\Object', ['getEvent'], [], '', false); + $eventMock = $this->getMock('Magento\Framework\Event', ['getItem'], [], '', false); + $itemMock = $this->getMock( + 'Magento\Quote\Model\Quote\Item', + [ + 'setRowTotal', 'setRowTotalInclTax', 'setPrice', 'setPriceInclTax', + 'getPriceInclTax', 'getCalculationPrice', 'getRowTotal', 'getRowTotalInclTax', 'getWeeeTaxApplied', + 'getWeeeTaxAppliedRowAmount', 'getWeeeTaxAppliedAmount' + ], + [], + '', + false + ); + + $eventMock->expects($this->once())->method('getItem')->will($this->returnValue($itemMock)); + $observerMock->expects($this->once())->method('getEvent')->will($this->returnValue($eventMock)); + + $this->weeeHelperMock->expects($this->any())->method('isEnabled') + ->will($this->returnValue($helperIsEnabled)); + $this->weeeHelperMock->expects($this->any())->method('getWeeeTaxInclTax') + ->with($itemMock)->will($this->returnValue($weeeTaxInclTax)); + $this->weeeHelperMock->expects($this->any())->method('getRowWeeeTaxInclTax') + ->will($this->returnValue($rowWeeeInclTax)); + $this->weeeHelperMock->expects($this->any())->method('typeOfDisplay') + ->will($this->returnValue($includeWeeeFlag)); + + $weeeTaxApplied = serialize($weeeTaxApplied); + $itemMock->expects($this->any())->method('getPriceInclTax')->will($this->returnValue($priceIncTax)); + $itemMock->expects($this->any())->method('getCalculationPrice')->will($this->returnValue($calculationPrice)); + $itemMock->expects($this->any())->method('getRowTotal')->will($this->returnValue($rowTotal)); + $itemMock->expects($this->any())->method('getRowTotalInclTax')->will($this->returnValue($rowTotalInclTax)); + $itemMock->expects($this->any())->method('getWeeeTaxApplied')->will($this->returnValue($weeeTaxApplied)); + $itemMock->expects($this->any())->method('getWeeeTaxAppliedAmount') + ->will($this->returnValue($weeeTaxAppliedAmount)); + $itemMock->expects($this->any())->method('getWeeeTaxAppliedRowAmount') + ->will($this->returnValue($weeeTaxRowApplied)); + + $itemMock->expects($this->once())->method('setRowTotal')->with($expectedRowTotal) + ->will($this->returnSelf()); + $itemMock->expects($this->once())->method('setRowTotalInclTax')->with($expectedRowInclTax) + ->will($this->returnSelf()); + $itemMock->expects($this->once())->method('setPrice')->with($expectedPrice) + ->will($this->returnSelf()); + $itemMock->expects($this->once())->method('setPriceInclTax')->with($expectedPriceInclTax) + ->will($this->returnSelf()); + + $this->model->processTaxData($observerMock); + } + + /** + * @return array + */ + public function processTaxDataDataProvider() + { + return [ + [ + 'helperIsEnabled' => false, + 'weeeTaxInclTax' => 10, + 'rowTotal' => 17, + 'weeeTaxRowApplied' => 3, + 'rowTotalInclTax' => 11, + 'rowWeeeInclTax' => 14, + 'weeeTaxApplied' => 4, + 'weeeTaxAppliedAmount' => 4, + 'includeWeeeFlag' => false, + 'priceIncTax' => 5, + 'calculationPrice' => 12, + 'expectedRowTotal' => 17, + 'expectedRowInclTax' => 11, + 'expectedPrice' => 12, + 'expectedPriceInclTax' => 5 + ], + [ + 'helperIsEnabled' => true, + 'weeeTaxInclTax' => 10, + 'rowTotal' => 17, + 'weeeTaxRowApplied' => 3, + 'rowTotalInclTax' => 11, + 'rowWeeeInclTax' => 14, + 'weeeTaxApplied' => 4, + 'weeeTaxAppliedAmount' => 4, + 'includeWeeeFlag' => false, + 'priceIncTax' => 5, + 'calculationPrice' => 12, + 'expectedRowTotal' => 17, + 'expectedRowInclTax' => 11, + 'expectedPrice' => 12, + 'expectedPriceInclTax' => 5 + ], + [ + 'helperIsEnabled' => true, + 'weeeTaxInclTax' => 10, + 'rowTotal' => 17, + 'weeeTaxRowApplied' => 3, + 'rowTotalInclTax' => 11, + 'rowWeeeInclTax' => 14, + 'weeeTaxApplied' => 4, + 'weeeTaxAppliedAmount' => 4, + 'includeWeeeFlag' => true, + 'priceIncTax' => 5, + 'calculationPrice' => 12, + 'expectedRowTotal' => 20, + 'expectedRowInclTax' => 25, + 'expectedPrice' => 16, + 'expectedPriceInclTax' => 15 + ] + ]; + } +} diff --git a/app/code/Magento/Weee/Test/Unit/Model/WeeeConfigProviderTest.php b/app/code/Magento/Weee/Test/Unit/Model/WeeeConfigProviderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..548ad82139b34802fadc77310423804350e08924 --- /dev/null +++ b/app/code/Magento/Weee/Test/Unit/Model/WeeeConfigProviderTest.php @@ -0,0 +1,180 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Weee\Test\Unit\Model; + +class WeeeConfigProviderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $weeeHelperMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $weeeConfigMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $storeManagerMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $storeMock; + + /** + * @var \Magento\Weee\Model\WeeeConfigProvider + */ + protected $model; + + protected function setUp() + { + $this->weeeHelperMock = $this->getMock('Magento\Weee\Helper\Data', [], [], '', false); + $this->weeeConfigMock = $this->getMock('Magento\Weee\Model\Config', [], [], '', false); + $this->storeManagerMock = $this->getMock('Magento\Store\Model\StoreManagerInterface'); + $this->storeMock = $this->getMock('Magento\Store\Model\Store', [], [], '', false); + + $this->storeManagerMock->expects($this->any())->method('getStore')->will($this->returnValue($this->storeMock)); + + $this->model = new \Magento\Weee\Model\WeeeConfigProvider( + $this->weeeHelperMock, + $this->storeManagerMock, + $this->weeeConfigMock + ); + } + + /** + * @dataProvider getConfigDataProvider + * @param array $expectedResult + * @param bool $weeeHelperEnabled + * @param bool $displayWeeeDetails + * @param bool $weeeConfigEnabled + * @param bool $includeInSubtotal + */ + public function testGetConfig( + $expectedResult, + $weeeHelperEnabled, + $displayWeeeDetails, + $weeeConfigEnabled, + $includeInSubtotal + ) { + $storeId = 1; + $this->storeMock->expects($this->any())->method('getId')->will($this->returnValue($storeId)); + $this->weeeHelperMock->expects($this->any())->method('isEnabled')->with($storeId) + ->will($this->returnValue($weeeHelperEnabled)); + $this->weeeHelperMock->expects($this->any())->method('typeOfDisplay') + ->will($this->returnValue($displayWeeeDetails)); + + $this->weeeConfigMock->expects($this->any())->method('isEnabled') + ->will($this->returnValue($weeeConfigEnabled)); + $this->weeeConfigMock->expects($this->any())->method('includeInSubtotal') + ->will($this->returnValue($includeInSubtotal)); + + $this->assertEquals($expectedResult, $this->model->getConfig()); + } + + /** + * @return array + */ + public function getConfigDataProvider() + { + return [ + [ + 'expectedResult' => [ + 'isDisplayPriceWithWeeeDetails' => false, + 'isDisplayFinalPrice' => true, + 'isWeeeEnabled' => false, + 'isIncludedInSubtotal' => true, + 'getIncludeWeeeFlag' => true, + ], + 'weeeHelperEnabled' => false, + 'displayWeeeDetails' => true, + 'weeeConfigEnabled' => true, + 'includeInSubtotal' => true, + ], + [ + 'expectedResult' => [ + 'isDisplayPriceWithWeeeDetails' => true, + 'isDisplayFinalPrice' => true, + 'isWeeeEnabled' => true, + 'isIncludedInSubtotal' => true, + 'getIncludeWeeeFlag' => true, + ], + 'weeeHelperEnabled' => true, + 'displayWeeeDetails' => true, + 'weeeConfigEnabled' => true, + 'includeInSubtotal' => true, + ], + [ + 'expectedResult' => [ + 'isDisplayPriceWithWeeeDetails' => false, + 'isDisplayFinalPrice' => false, + 'isWeeeEnabled' => true, + 'isIncludedInSubtotal' => true, + 'getIncludeWeeeFlag' => false, + ], + 'weeeHelperEnabled' => true, + 'displayWeeeDetails' => false, + 'weeeConfigEnabled' => true, + 'includeInSubtotal' => true, + ], + [ + 'expectedResult' => [ + 'isDisplayPriceWithWeeeDetails' => false, + 'isDisplayFinalPrice' => false, + 'isWeeeEnabled' => false, + 'isIncludedInSubtotal' => true, + 'getIncludeWeeeFlag' => false, + ], + 'weeeHelperEnabled' => false, + 'displayWeeeDetails' => false, + 'weeeConfigEnabled' => true, + 'includeInSubtotal' => true, + ], + [ + 'expectedResult' => [ + 'isDisplayPriceWithWeeeDetails' => false, + 'isDisplayFinalPrice' => false, + 'isWeeeEnabled' => false, + 'isIncludedInSubtotal' => false, + 'getIncludeWeeeFlag' => false, + ], + 'weeeHelperEnabled' => false, + 'displayWeeeDetails' => false, + 'weeeConfigEnabled' => false, + 'includeInSubtotal' => true, + ], + [ + 'expectedResult' => [ + 'isDisplayPriceWithWeeeDetails' => false, + 'isDisplayFinalPrice' => false, + 'isWeeeEnabled' => false, + 'isIncludedInSubtotal' => false, + 'getIncludeWeeeFlag' => false, + ], + 'weeeHelperEnabled' => false, + 'displayWeeeDetails' => false, + 'weeeConfigEnabled' => true, + 'includeInSubtotal' => false, + ], + [ + 'expectedResult' => [ + 'isDisplayPriceWithWeeeDetails' => false, + 'isDisplayFinalPrice' => false, + 'isWeeeEnabled' => false, + 'isIncludedInSubtotal' => false, + 'getIncludeWeeeFlag' => false, + ], + 'weeeHelperEnabled' => false, + 'displayWeeeDetails' => false, + 'weeeConfigEnabled' => false, + 'includeInSubtotal' => false, + ], + ]; + } +} diff --git a/app/code/Magento/Weee/view/frontend/layout/checkout_onepage_index.xml b/app/code/Magento/Weee/view/frontend/layout/checkout_onepage_index.xml index e5aa37b3c77ed809a449fa828489f38808d2d3fa..6e3439d0775862400bec88a4cf5885f4005358e5 100644 --- a/app/code/Magento/Weee/view/frontend/layout/checkout_onepage_index.xml +++ b/app/code/Magento/Weee/view/frontend/layout/checkout_onepage_index.xml @@ -5,6 +5,7 @@ * See COPYING.txt for license details. */ --> +<!-- TODO remove this file as soon as enhanced checkout is implemented --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="checkout.root"> @@ -13,50 +14,36 @@ <item name="components" xsi:type="array"> <item name="checkout" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="steps" xsi:type="array"> + <item name="summary" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="review" xsi:type="array"> + <item name="totals" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="columns" xsi:type="array"> + <item name="weee" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/summary/weee</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string">FPT</item> + </item> + </item> + </item> + </item> + <item name="cart_items" xsi:type="array"> + <item name="children" xsi:type="array"> + <item name="details" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="price" xsi:type="array"> - <item name="children" xsi:type="array"> - <item name="unit_incl_tax" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/review/item/price/unit_incl_tax</item> - <item name="displayArea" xsi:type="string">unit_incl_tax</item> - </item> - <item name="unit_excl_tax" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/review/item/price/unit_excl_tax</item> - <item name="displayArea" xsi:type="string">unit_excl_tax</item> - </item> - </item> - </item> <item name="subtotal" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="row_incl_tax" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/review/item/price/row_incl_tax</item> - <item name="displayArea" xsi:type="string">row_incl_tax</item> + <item name="weee_row_incl_tax" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/summary/item/price/row_incl_tax</item> + <item name="displayArea" xsi:type="string">row_incl_tax</item> </item> - <item name="row_excl_tax" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/review/item/price/row_excl_tax</item> + <item name="weee_row_excl_tax" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/summary/item/price/row_excl_tax</item> <item name="displayArea" xsi:type="string">row_excl_tax</item> </item> </item> </item> </item> </item> - <item name="totals" xsi:type="array"> - <item name="children" xsi:type="array"> - <item name="before_grandtotal" xsi:type="array"> - <item name="children" xsi:type="array"> - <item name="weee_total" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Weee/js/view/checkout/review/weee_total</item> - </item> - </item> - </item> - </item> - </item> - </item> </item> </item> diff --git a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/unit_excl_tax.js b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/unit_excl_tax.js deleted file mode 100644 index 484b00bacb94409548202088b0d36b5dce9c113c..0000000000000000000000000000000000000000 --- a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/unit_excl_tax.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'Magento_Weee/js/view/checkout/review/item/price/weee' - ], - function (weee) { - "use strict"; - return weee.extend({ - defaults: { - template: 'Magento_Weee/checkout/review/item/price/unit_excl_tax' - }, - - getFinalUnitDisplayPriceExclTax: function(item) { - var unitExclTax = parseFloat(item.price); - if(!window.checkoutConfig.getIncludeWeeeFlag) { - return unitExclTax + parseFloat(item.weee_tax_applied_amount); - } - return unitExclTax; - } - }); - } -); diff --git a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/unit_incl_tax.js b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/unit_incl_tax.js deleted file mode 100644 index d6e03c37b5e1a9b7c6db4ef86ebd2bb67736a1ce..0000000000000000000000000000000000000000 --- a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/unit_incl_tax.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'Magento_Weee/js/view/checkout/review/item/price/weee' - ], - function (weee) { - "use strict"; - return weee.extend({ - defaults: { - template: 'Magento_Weee/checkout/review/item/price/unit_incl_tax' - }, - getFinalUnitDisplayPriceInclTax: function(item) { - var unitInclTax = parseFloat(item.price_incl_tax); - if(!window.checkoutConfig.getIncludeWeeeFlag) { - return unitInclTax + this.getWeeeTaxInclTax(item); - } - return unitInclTax; - }, - getWeeeTaxInclTax: function(item) { - var weeeTaxAppliedAmounts = JSON.parse(item.weee_tax_applied); - var totalWeeeTaxIncTaxApplied = 0; - weeeTaxAppliedAmounts.forEach(function (weeeTaxAppliedAmount) { - totalWeeeTaxIncTaxApplied+=parseFloat(Math.max(weeeTaxAppliedAmount.amount_incl_tax, 0)); - }); - return totalWeeeTaxIncTaxApplied; - } - }); - } -); diff --git a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/weee_total.js b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/weee_total.js deleted file mode 100644 index 41aec2c8475928ad094bd69f433f7f12fe689020..0000000000000000000000000000000000000000 --- a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/weee_total.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'uiComponent', - 'Magento_Checkout/js/model/quote', - 'Magento_Catalog/js/price-utils' - ], - function (Component,quote, priceUtils) { - "use strict"; - return Component.extend({ - defaults: { - colspan: 3, - displayArea: 'before_grandtotal', - title: 'FPT', - template: 'Magento_Weee/checkout/review/weee_total' - }, - isIncludedInSubtotal: window.checkoutConfig.isIncludedInSubtotal, - totals: quote.getTotals(), - getColspan: function() { - return this.colspan; - }, - getTitle: function() { - return this.title; - }, - getPureValue: function() { - var items = quote.getItems(); - var sum = 0; - for (var i = 0; i < items.length; i++) { - sum += parseFloat(items[i].weee_tax_applied_row_amount); - } - return sum; - }, - getValue: function() { - var items = quote.getItems(); - var sum = 0; - for (var i = 0; i < items.length; i++) { - sum += parseFloat(items[i].weee_tax_applied_row_amount); - } - return priceUtils.formatPrice(sum, quote.getPriceFormat()); - } - }); - } -); diff --git a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/row_excl_tax.js b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_excl_tax.js similarity index 81% rename from app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/row_excl_tax.js rename to app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_excl_tax.js index 000d08a5ca07a481989b64f76aa1376ec9cedac8..07c7f94305e991453c0eeb7d8d51550fd94db966 100644 --- a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/row_excl_tax.js +++ b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_excl_tax.js @@ -6,13 +6,13 @@ /*global define*/ define( [ - 'Magento_Weee/js/view/checkout/review/item/price/weee' + 'Magento_Weee/js/view/checkout/summary/item/price/weee' ], function (weee) { "use strict"; return weee.extend({ defaults: { - template: 'Magento_Weee/checkout/review/item/price/row_excl_tax' + template: 'Magento_Weee/checkout/summary/item/price/row_excl_tax' }, getFinalRowDisplayPriceExclTax: function(item) { diff --git a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/row_incl_tax.js b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_incl_tax.js similarity index 88% rename from app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/row_incl_tax.js rename to app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_incl_tax.js index 6fc8b67643282d0a8bea4cb700baa37b56dbdff4..15aec47fd0f36c377a513757c4f207d05bd71ed0 100644 --- a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/row_incl_tax.js +++ b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/row_incl_tax.js @@ -6,13 +6,13 @@ /*global define*/ define( [ - 'Magento_Weee/js/view/checkout/review/item/price/weee' + 'Magento_Weee/js/view/checkout/summary/item/price/weee' ], function (weee) { "use strict"; return weee.extend({ defaults: { - template: 'Magento_Weee/checkout/review/item/price/row_incl_tax', + template: 'Magento_Weee/checkout/summary/item/price/row_incl_tax', displayArea: 'row_incl_tax' }, getFinalRowDisplayPriceInclTax: function(item) { diff --git a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/weee.js b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/weee.js similarity index 77% rename from app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/weee.js rename to app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/weee.js index f6c146aa688fb67e68d3d82cf383ec3726605ea9..919504bd6270e066a0caa6aacf47506e69ec4e9b 100644 --- a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/review/item/price/weee.js +++ b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/item/price/weee.js @@ -6,11 +6,10 @@ /*global define*/ define( [ - 'uiComponent', - 'Magento_Checkout/js/model/quote', - 'Magento_Catalog/js/price-utils' + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote' ], - function (Component,quote, priceUtils) { + function (Component,quote) { "use strict"; return Component.extend({ @@ -26,9 +25,6 @@ define( } return window.checkoutConfig.isDisplayFinalPrice; }, - getFormattedPrice: function (price) { - return priceUtils.formatPrice(price, quote.getPriceFormat()); - }, getWeeeTaxApplied: function(item) { if (item.weee_tax_applied) { return JSON.parse(item.weee_tax_applied) diff --git a/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/weee.js b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/weee.js new file mode 100644 index 0000000000000000000000000000000000000000..22209e41d2028a98c61b8b3876345ff5e1d33f4b --- /dev/null +++ b/app/code/Magento/Weee/view/frontend/web/js/view/checkout/summary/weee.js @@ -0,0 +1,31 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*browser:true*/ +/*global define*/ +define( + [ + 'Magento_Checkout/js/view/summary/abstract-total', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/totals', + 'Magento_Catalog/js/price-utils' + ], + function (Component,quote, totals) { + "use strict"; + return Component.extend({ + defaults: { + template: 'Magento_Weee/checkout/summary/weee' + }, + isIncludedInSubtotal: window.checkoutConfig.isIncludedInSubtotal, + totals: totals.totals, + getValue: function() { + return this.getFormattedPrice(this.totals()['weee_tax_applied_amount']); + }, + isDisplayed: function() { + return this.isFullMode() && this.isIncludedInSubtotal && + this.totals()['weee_tax_applied_amount'] > 0; + } + }); + } +); diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/row_incl_tax.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/row_incl_tax.html deleted file mode 100644 index bfaa8c3f176722b4e50b1c0e7ff9f0bff45410af..0000000000000000000000000000000000000000 --- a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/row_incl_tax.html +++ /dev/null @@ -1,37 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<!-- ko if: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#subtotal-item-tax-details'+item.item_id}}"> - <span class="price" data-bind="text: getFormattedPrice(item.row_total_incl_tax)"></span> - </span> -<!-- /ko --> -<!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-price"><span class="price" data-bind="text: getFormattedPrice(item.row_total_incl_tax)"></span></span> -<!-- /ko --> - -<!--ko if: getWeeeTaxApplied(item).length > 0--> -<!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item))--> -<span class="cart-tax-info" data-bind ="attr: {'id': 'subtotal-item-tax-details' + item.item_id}" style="display: none;"></span> -<!-- /ko--> -<!-- ko if: (isDisplayPriceWithWeeeDetails(item))--> -<span class="cart-tax-info" data-bind ="attr: {'id': 'subtotal-item-tax-details' + item.item_id}" style="display: none;"> - <!-- ko foreach: getWeeeTaxApplied(item)--> - <span class="weee" data-bind="attr:{'data-label':title}"> - <span class="price" data-bind="text: $parent.getFormattedPrice(row_amount_incl_tax)"></span> - </span> - <!-- /ko--> - </span> -<!-- /ko--> - -<!-- ko if: isDisplayFinalPrice(item)--> - <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#subtotal-item-tax-details'+item.item_id}}"> - <span class="weee" data-bind="attr: {'data-label':$t('Total Incl. Tax')}"> - <span class="price" data-bind="text: getFormattedPrice(getFinalRowDisplayPriceInclTax(item))"></span> - </span> - </span> -<!-- /ko --> -<!-- /ko --> diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/unit_excl_tax.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/unit_excl_tax.html deleted file mode 100644 index eb34f588887cef129456b0c537b5dffc9260bb40..0000000000000000000000000000000000000000 --- a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/unit_excl_tax.html +++ /dev/null @@ -1,40 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<!-- ko if: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-tax-total" data-bind="mageInit:{taxToggle: {itemTaxId : '#eunit-item-tax-details' + item.item_id}}"> - <span class="price" data-bind="text: getFormattedPrice(item.price)"></span> - </span> -<!-- /ko --> -<!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-price"><span class="price" data-bind="text: getFormattedPrice(item.price)"></span></span> -<!-- /ko --> - - -<!--ko if: (getWeeeTaxApplied(item).length > 0)--> - <!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item))--> - <span class="cart-tax-info" data-bind ="attr: {'id': 'eunit-item-tax-details' + item.item_id}" style="display: none;"></span> - <!-- /ko--> - <!-- ko if: (isDisplayPriceWithWeeeDetails(item))--> - <span class="cart-tax-info" data-bind ="attr: {'id': 'eunit-item-tax-details' + item.item_id}" style="display: none;"> - <!-- ko foreach: getWeeeTaxApplied(item)--> - <span class="weee" data-bind="attr:{'data-label':title}"> - <span class="price" data-bind="text: $parent.getFormattedPrice(amount)"></span> - </span> - <!-- /ko--> - </span> - <!-- /ko--> - - - <!-- ko if: isDisplayFinalPrice(item)--> - <span class="cart-tax-total" data-bind="mageInit:{taxToggle: {itemTaxId : '#eunit-item-tax-details' + item.item_id}}"> - <span class="weee" data-bind="attr: {'data-label':$t('Total')}"> - <span class="price" data-bind="text: getFormattedPrice(getFinalUnitDisplayPriceExclTax(item))"></span> - </span> - </span> - <!-- /ko --> -<!-- /ko --> diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/unit_incl_tax.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/unit_incl_tax.html deleted file mode 100644 index 1a67282073225531a6137bd83361a08d60c2287e..0000000000000000000000000000000000000000 --- a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/unit_incl_tax.html +++ /dev/null @@ -1,38 +0,0 @@ -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<!-- ko if: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#unit-item-tax-details'+item.item_id}}"> - <span class="price" data-bind="text: getFormattedPrice(item.price_incl_tax)"></span> - </span> -<!-- /ko --> -<!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-price"><span class="price" data-bind="text: getFormattedPrice(item.price_incl_tax)"></span></span> -<!-- /ko --> - -<!--ko if: (getWeeeTaxApplied(item).length > 0)--> - <!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item))--> - <span class="cart-tax-info" data-bind ="attr: {'id': 'unit-item-tax-details' + item.item_id}" style="display: none;"></span> - <!-- /ko--> - <!-- ko if: (isDisplayPriceWithWeeeDetails(item))--> - <span class="cart-tax-info" data-bind ="attr: {'id': 'unit-item-tax-details' + item.item_id}" style="display: none;"> - <!-- ko foreach: getWeeeTaxApplied(item)--> - <span class="weee" data-bind="attr:{'data-label':title}"> - <span class="price" data-bind="text: $parent.getFormattedPrice(amount_incl_tax)"></span> - </span> - <!-- /ko--> - </span> - <!-- /ko--> - - <!-- ko if: isDisplayFinalPrice(item)--> - <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#unit-item-tax-details'+item.item_id}}"> - <span class="weee" data-bind="attr: {'data-label':$t('Total Incl. Tax')}"> - <span class="price" data-bind="text: getFormattedPrice(getFinalUnitDisplayPriceInclTax(item))"></span> - </span> - </span> - <!-- /ko --> -<!-- /ko --> diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/weee_total.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/review/weee_total.html deleted file mode 100644 index 3e9b25d84db8239da763e6bc4d740bcd6dc947f1..0000000000000000000000000000000000000000 --- a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/weee_total.html +++ /dev/null @@ -1,14 +0,0 @@ -<!-- -/** -* Copyright © 2015 Magento. All rights reserved. -* See COPYING.txt for license details. -*/ ---> -<!-- ko if: isIncludedInSubtotal && getPureValue() > 0 --> -<tr class="totals"> - <th data-bind="text: getTitle(), attr: {'colspan': getColspan()}" class="mark" scope="row"></th> - <td class="amount" data-bind="attr: {'data-th': $t(getTitle()) }"> - <span data-bind="text: getValue()"></span> - </td> -</tr> -<!-- /ko --> \ No newline at end of file diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/row_excl_tax.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_excl_tax.html similarity index 51% rename from app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/row_excl_tax.html rename to app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_excl_tax.html index c1a8590e1fe157967c7490e497ba072389d45399..39e2bfa7815e8d8d5658ae91b0838982ce62636b 100644 --- a/app/code/Magento/Weee/view/frontend/web/template/checkout/review/item/price/row_excl_tax.html +++ b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_excl_tax.html @@ -4,22 +4,22 @@ * See COPYING.txt for license details. */ --> -<!-- ko if: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#esubtotal-item-tax-details'+item.item_id}}"> - <span class="price" data-bind="text: getFormattedPrice(item.row_total)"></span> +<!-- ko if: (isDisplayPriceWithWeeeDetails($parents[2])) --> + <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#esubtotal-item-tax-details'+$parents[2].item_id}}"> + <span class="price" data-bind="text: getFormattedPrice($parents[2].row_total)"></span> </span> <!-- /ko --> -<!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item)) --> - <span class="cart-price"><span class="price" data-bind="text: getFormattedPrice(item.row_total)"></span></span> +<!-- ko ifnot: (isDisplayPriceWithWeeeDetails($parents[2])) --> + <span class="cart-price"><span class="price" data-bind="text: getFormattedPrice($parents[2].row_total)"></span></span> <!-- /ko --> -<!--ko if: (getWeeeTaxApplied(item).length > 0)--> -<!-- ko ifnot: (isDisplayPriceWithWeeeDetails(item))--> -<span class="cart-tax-info" data-bind ="attr: {'id': 'esubtotal-item-tax-details' + item.item_id}" style="display: none;"></span> +<!--ko if: (getWeeeTaxApplied($parents[2]).length > 0)--> +<!-- ko ifnot: (isDisplayPriceWithWeeeDetails($parents[2]))--> +<span class="cart-tax-info" data-bind ="attr: {'id': 'esubtotal-item-tax-details' + $parents[2].item_id}" style="display: none;"></span> <!-- /ko--> -<!-- ko if: (isDisplayPriceWithWeeeDetails(item))--> -<span class="cart-tax-info" data-bind ="attr: {'id': 'esubtotal-item-tax-details' + item.item_id}" style="display: none;"> - <!-- ko foreach: getWeeeTaxApplied(item)--> +<!-- ko if: (isDisplayPriceWithWeeeDetails($parents[2]))--> +<span class="cart-tax-info" data-bind ="attr: {'id': 'esubtotal-item-tax-details' + $parents[2].item_id}" style="display: none;"> + <!-- ko foreach: getWeeeTaxApplied($parents[2])--> <span class="weee" data-bind="attr:{'data-label':title}"> <span class="price" data-bind="text: $parent.getFormattedPrice(row_amount)"></span> </span> @@ -27,10 +27,10 @@ </span> <!-- /ko--> -<!-- ko if: isDisplayFinalPrice(item)--> - <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#esubtotal-item-tax-details'+item.item_id}}"> +<!-- ko if: isDisplayFinalPrice($parents[2])--> + <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#esubtotal-item-tax-details'+$parents[2].item_id}}"> <span class="weee" data-bind="attr: {'data-label':$t('Total')}"> - <span class="price" data-bind="text: getFormattedPrice(getFinalRowDisplayPriceExclTax(item))"> + <span class="price" data-bind="text: getFormattedPrice(getFinalRowDisplayPriceExclTax($parents[2]))"> </span> </span> diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_incl_tax.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_incl_tax.html new file mode 100644 index 0000000000000000000000000000000000000000..562bd3293cf960a41046ebb132d3258c8e5a1651 --- /dev/null +++ b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_incl_tax.html @@ -0,0 +1,37 @@ +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- ko if: (isDisplayPriceWithWeeeDetails($parents[2])) --> + <span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#subtotal-item-tax-details'+$parents[2].item_id}}"> + <span class="price" data-bind="text: getFormattedPrice($parents[2].row_total_incl_tax)"></span> + </span> +<!-- /ko --> +<!-- ko ifnot: (isDisplayPriceWithWeeeDetails($parents[2])) --> +<span class="cart-price"><span class="price" data-bind="text: getFormattedPrice($parents[2].row_total_incl_tax)"></span></span> +<!-- /ko --> + +<!--ko if: getWeeeTaxApplied($parents[2]).length > 0--> +<!-- ko ifnot: (isDisplayPriceWithWeeeDetails($parents[2]))--> +<span class="cart-tax-info" data-bind ="attr: {'id': 'subtotal-item-tax-details' + $parents[2].item_id}" style="display: none;"></span> +<!-- /ko--> +<!-- ko if: (isDisplayPriceWithWeeeDetails($parents[2]))--> +<span class="cart-tax-info" data-bind ="attr: {'id': 'subtotal-item-tax-details' + $parents[2].item_id}" style="display: none;"> + <!-- ko foreach: getWeeeTaxApplied($parents[2])--> + <span class="weee" data-bind="attr:{'data-label':title}"> + <span class="price" data-bind="text: $parent.getFormattedPrice(row_amount_incl_tax)"></span> + </span> + <!-- /ko--> + </span> +<!-- /ko--> + +<!-- ko if: isDisplayFinalPrice($parents[2])--> +<span class="cart-tax-total" data-bind="mageInit: {taxToggle: {itemTaxId : '#subtotal-item-tax-details'+$parents[2].item_id}}"> + <span class="weee" data-bind="attr: {'data-label':$t('Total incl. tax')}"> + <span class="price" data-bind="text: getFormattedPrice(getFinalRowDisplayPriceInclTax($parents[2]))"></span> + </span> + </span> +<!-- /ko --> +<!-- /ko --> diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/weee.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/weee.html new file mode 100644 index 0000000000000000000000000000000000000000..7a3696a829ef86c82efc2a53342c25cadbdb451e --- /dev/null +++ b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/weee.html @@ -0,0 +1,14 @@ +<!-- +/** +* Copyright © 2015 Magento. All rights reserved. +* See COPYING.txt for license details. +*/ +--> +<!-- ko if: isDisplayed() --> +<tr class="totals"> + <th data-bind="text: title" class="mark" scope="row"></th> + <td class="amount" data-bind="attr: {'data-th': $t(title) }"> + <span data-bind="text: getValue()"></span> + </td> +</tr> +<!-- /ko --> \ No newline at end of file diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js index 112f9406bdaf4e664e57478393a6b73409098119..2ed8935a30cf8249df7721e61773a5a955d2d3ad 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js @@ -32,7 +32,8 @@ define([ this._on(events); }, _updateWishlistData: function(event) { - var dataToAdd = {}; + var dataToAdd = {}, + isFileUploaded = false; if (event.handleObj.selector == this.options.qtyInfo) { this._updateAddToWishlistButton({}); event.stopPropagation(); @@ -40,15 +41,22 @@ define([ } var self = this; $(event.handleObj.selector).each(function(index, element){ - if ($(element).attr('type') == 'text') { + if ($(element).is('input[type=text]') + || $(element).is('input[type=checkbox]:checked') + || $(element).is('input[type=radio]:checked') + || $('#' + element.id + ' option:selected').length + || $(element).is('textarea') + ) { dataToAdd = $.extend({}, dataToAdd, self._getElementData(element)); return; } - if ($(element).is(':checked') || $(element).find(':checked').length) { - dataToAdd = $.extend({}, dataToAdd, self._getElementData(element)); + if ($(element).is('input[type=file]') && $(element).val()) { + isFileUploaded = true; } }); - + if (isFileUploaded) { + this.bindFormSubmit(); + } this._updateAddToWishlistButton(dataToAdd); event.stopPropagation(); }, @@ -90,7 +98,9 @@ define([ data[elementName + '[' + option + ']'] = option; }); } else { - data[elementName] = elementValue; + if (elementValue) { + data[elementName] = elementValue; + } } return data; }, @@ -99,6 +109,23 @@ define([ $.each(dataToRemove, function(key, value) { delete params.data[key]; }); + }, + bindFormSubmit: function() { + var self = this; + $('[data-action="add-to-wishlist"]').on('click', function(event) { + event.stopPropagation(); + event.preventDefault(); + + var element = $('input[type=file]' + self.options.customOptionsInfo), + params = $(event.currentTarget).data('post'), + form = $(element).closest('form'), + action = params.action; + if (params.data.uenc) { + action += 'uenc/' + params.data.uenc; + } + + $(form).attr('action', action).submit(); + }); } }); diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less index 8795421c0d241fc95cdaf6a43e597fdd2fb8f13e..85932830410a8ee3ef47bc3eabf105116270a9cc 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less @@ -5,448 +5,4 @@ @import 'module/_cart.less'; @import 'module/_minicart.less'; - -@desktop-form-field-vertical-indent: 29px; - -// -// Common -// _____________________________________________ - -& when (@media-common = true) { - - // - // One Page Checkout - // --------------------------------------------- - - .opc-wrapper:extend(.abs-add-box-sizing all) { - .css(padding-bottom, @indent__xl); - > .opc:extend(.abs-reset-list all) { - } - .section { - &.allow .step-title { - cursor: pointer; - } - &.active { - .step { - &-title { - .css(color, @primary__color__darker); - cursor: default; - } - &-content { - display: block; - } - } - } - } - .step { - &-title { - border-bottom: @border-width__base solid @border-color__base; - .css(color, @primary__color__lighter); - line-height: 50px; - h2, - .number { - display: inline-block; - .heading(h3); - } - .number:after { - content: '.'; - } - } - &-content { - display: none; - padding: @indent__base @indent__s; - position: relative; - .addresses .control { - margin: @indent__base 0; - } - .fieldset { - margin-bottom: 0; - &.login { - .form-hasrequired(bottom); - &:after { - margin-top: 35px; - text-align: center; - } - } - > .field { - margin: @form-field__vertical-indent 0 0; - } - &.address { - .field:first-of-type:not(.additional) { - margin: 0; - } - } - .legend.payments-title:extend(.abs-visually-hidden all) { - } - } - .methods-shipping { - .item-content { - .fieldset { - > .legend:extend(.abs-visually-hidden all) { - } - > .legend + br:extend(.abs-no-display all) { - } - > .field { - margin: @indent__base 0 0; - &:before { - display: none; - } - .control { - display: inline-block; - } - } - br + .field { - margin: 0; - } - } - } - } - .form { - .form-hasrequired(bottom); - &:after { - text-align: center; - } - .field:not(:first-child) { - margin: @indent__base 0 0; - } - > .field.choice { - margin: @form-field__vertical-indent 0 0; - } - .field { - &.month { - padding-right: @indent__s; - } - &.year { - margin-top: 0; - } - } - } - .form:not(.login), - .order-review { - .action.primary:extend(.abs-button-l all) { - } - } - .actions { - margin-top: @indent__base; - } - .field.street { - .field.additional { - .label:extend(.abs-visually-hidden all) { - } - } - } - } - } - - .opc-payment-additional { - margin: 0 0 @indent__xs; - + .opc-payment { - margin: @indent__base 0 0; - } - } - - // - // Order review - // --------------------------------------------- - - .order-review { - .fieldset > .field > .label { - font-weight: @font-weight__regular; - } - .product-item-name { - margin: 0; - } - } - - .data.table:extend(.abs-product-options-list all) { - .col { - &.price, - &.qty { - text-align: center; - white-space: nowrap; - } - } - .item-options:extend(.abs-add-clearfix all) { - font-size: @font-size__s; - margin: @indent__s 0 0; - } - .cart-price:extend(.abs-checkout-cart-price all) { - } - } - - .action.primary.checkout { - margin: 0 0 @indent__base; - } - - .hidden:extend(.abs-no-display all) { - } - - // - // Customer login - // --------------------------------------------- - - .login-wrapper { - .block { - .block-title:extend(.abs-login-block-title all) { - } - .fieldset.guest { - margin-top: @indent__base; - } - .field.choice { - margin-bottom: @indent__s; - } - } - } - - .actions-toolbar { - margin: @indent__xl 0 0; - } - } - - // - // Shipping methods - // --------------------------------------------- - - .methods-shipping { - .item-title:extend(.abs-methods-shipping-title all) { - } - .item-content:extend(.abs-adjustment-incl-excl-tax all) { - margin: 0 0 @indent__xl; - .price { - font-weight: @font-weight__bold; - } - .field.choice { - margin: 0 0 @indent__s; - .control { - float: left; - } - .label { - display: block; - overflow: hidden; - } - } - } - .price-box { - margin-bottom: @indent__xs; - margin-left: @indent__xl; - margin-top: @indent__s; - .label + .price { - font-weight: @font-weight__bold; - } - } - img { - vertical-align: middle; - } - } - - // - // Payment methods - // --------------------------------------------- - - .methods-payment { - .item { - &-title { - font-weight: @font-weight__regular; - } - &-content { - margin: 0 0 0 @indent__base; - .label { - font-weight: @font-weight__regular; - } - } - } - .fieldset { - padding: 15px 0 @indent__m; - } - .fieldset & { - .item-content > .fieldset > .field:first-child { - margin-top: 0; - } - } - .redirect { - .font-size(@font-size__s); - padding: 0 0 15px; - } - img { - margin-right: @indent__xs; - vertical-align: middle; - } - } - - .cart-tax-info + .cart-tax-total { - display: block; - } - - // - // Checkout Progress - // --------------------------------------------- - - .opc-block-progress:extend(.abs-add-box-sizing all) { - margin-bottom: @indent__l; - > .title { - .css(background, @sidebar__background-color); - .heading(h3); - margin: 0; - padding: 15px 15px @indent__base; - strong { - font-weight: @font-weight__regular; - } - } - > .content { - .css(background, @sidebar__background-color); - padding: 0 15px @indent__xs; - .item-content.complete { - margin: 0 0 15px; - overflow: hidden; - } - .action, - .payment-method .title { - font-weight: @font-weight__regular; - } - .data.table { - font-size: @font-size__s; - } - } - .payment-method { - > .title { - font-weight: @font-weight__light; - } - > .content { - margin: 0 0 @indent__s; - &:last-child { - margin-bottom: 0; - } - } - .items-cards { - margin: 0; - > .content { - margin: 0; - } - } - .data.table { - th { - padding: @indent__xs @indent__s @indent__xs 0; - } - td { - padding: @indent__xs 0; - } - } - } - } - - // - // Checkout Success - // --------------------------------------------- - - .checkout-onepage-success { - .page-title-wrapper { - .print:extend(.abs-no-display all) { - } - } - } - - .checkout-success { - .actions-toolbar { - margin-top: @indent__xl; - } - } - - .checkout-onepage-index { - .nav-toggle:extend(.abs-no-display all) { - } - .logo { - margin-left: 0; - } - } -} - -// -// Mobile -// _____________________________________________ - -.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { - .opc-wrapper { - table.data.table:extend(.abs-checkout-order-review all) { - } - } -} - -// -// Desktop -// _____________________________________________ - -.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) { - .checkout-onepage-index .column.main:extend(.abs-add-clearfix-desktop-s all) { - } - - .opc-wrapper:extend(.abs-add-box-sizing-desktop-s all) { - .layout-column(2, 2, @layout-column-checkout__width-main); - .step-content { - padding: @indent__base 18px @indent__xl; - .addresses .control { - margin-bottom: @desktop-form-field-vertical-indent; - } - .form { - &:after { - text-align: right; - } - &:not(.login) { - .actions-toolbar:extend(.abs-reset-left-margin-desktop-s all) { - } - } - > .field.choice, - .fieldset > .field { - margin: @desktop-form-field-vertical-indent 0 0; - } - .fieldset.address { - .field:first-of-type:not(.additional) { - margin: 0; - } - } - } - .fieldset.login:after:extend(.abs-margin-for-forms-desktop-s all) { - text-align: left; - } - } - } - - .opc-block-progress:extend(.abs-add-box-sizing-desktop-s all) { - .layout-column(2, 1, @layout-column-checkout__width-left); - padding-right: @layout-column-main__sidebar-offset; - } - - .login-wrapper:extend(.abs-add-clearfix-desktop-s all) { - .block:extend(.abs-blocks-2columns-s all) { - } - .field.choice:not(.persistent) { - &:before { - display: none; - } - } - .fieldset.login { - .actions:extend(.abs-margin-for-forms-desktop-s all) { - } - } - } - - // - // Checkout success - // --------------------------------------------- - - .checkout-onepage-success { - .page-title-wrapper { - .print { - display: inline-block; - .font-size(14); - margin-left: @indent__xl; - } - } - } - - .table-order-review { - .col.subtotal, - .amount { - text-align: right; - } - } -} +@import 'module/_checkout.less'; diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less index 089a66bff442b12dda09f922093d1e215abc9e43..fa4e5ad9ad23c9e319d9291c51799ce02bb1364c 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less @@ -9,315 +9,236 @@ & when (@media-common = true) { - // - // Shopping cart - // --------------------------------------------- + // + // Shopping cart + // --------------------------------------------- - .cart { - // Summary block - &-summary { - &:extend(.abs-add-box-sizing all); - .css(background, @sidebar__background-color); - margin-bottom: @indent__m; - padding: 1px 15px @indent__m; - > .title { - display: block; - .heading(h3); - } - .block { - margin-bottom: 0; - > .title { - border-top: @border-width__base solid @border-color__base; - cursor: pointer; - font-weight: @font-weight__semibold; - .icon-font( - @_icon-font-content: @icon-down, - @_icon-font-size: 30px, - @_icon-font-position: after, - @_icon-font-display: block - ); - margin-bottom: 0; - overflow: hidden; - padding: 7px @indent__base 7px @indent__xs; - position: relative; - &:after { - position: absolute; - right: 0; - top: -5px; - } - strong { - .column.main & { - .font-size(18); - font-weight: @font-weight__regular; - } - } - } - > .content { - display: none; - } - &.active { - > .title { - .icon-font-symbol( - @_icon-font-content: @icon-prev, - @_icon-font-position: after - ); - } - > .content { - display: block; - } - } - .item-options { - margin-left: 0; - } - .fieldset { - margin: 15px 0 @indent__m @indent__xs; - .field { - margin: 0 0 @indent__s; - &.note { - font-size: @font-size__s; - } - } - } - .fieldset { - .methods { - .field { - > .label { - display: inline; - } - } - } - } - .fieldset.estimate { - > .legend, - > .legend + br { - &:extend(.abs-no-display all); - } - } - } - .actions-toolbar { - > .primary { - button { - &:extend(.abs-revert-secondary-color all); - } - } - } - &:extend(.abs-adjustment-incl-excl-tax all); + .cart { + // Summary block + &-summary { + &:extend(.abs-add-box-sizing all); + .css(background, @sidebar__background-color); + margin-bottom: @indent__m; + padding: 1px 15px @indent__m; + > .title { + display: block; + .heading(h3); + } + .block { + margin-bottom: 0; + > .title { + border-top: @border-width__base solid @border-color__base; + cursor: pointer; + font-weight: @font-weight__semibold; + .icon-font( + @_icon-font-content: @icon-down, + @_icon-font-size: 30px, + @_icon-font-position: after, + @_icon-font-display: block + ); + margin-bottom: 0; + overflow: hidden; + padding: 7px @indent__base 7px @indent__xs; + position: relative; + &:after { + position: absolute; + right: 0; + top: -5px; + } + strong { + .column.main & { + .font-size(18); + font-weight: @font-weight__regular; + } + } } - - // Totals block - &-totals { - border-top: 1px solid @border-color__base; - padding-top: 10px; - .table-wrapper { - overflow: inherit; - } - .mark { - font-weight: @font-weight__regular; - padding-left: 4px; - strong { - font-weight: @font-weight__regular; - } - } - .amount { - padding-right: 4px; - text-align: right; - strong { - font-weight: @font-weight__regular; - } - } - .grand:last-child { - .mark, - .amount { - padding-top: @indent__base; - } - .amount { - padding-right: 4px; - text-align: right; - strong { - font-weight: @font-weight__bold; - } - } - } - .msrp { - margin-bottom: @indent__s; - } - .totals-tax { - &-summary { - .mark, - .amount { - border-bottom: @border-width__base solid @border-color__base; - border-top: @border-width__base solid @border-color__base; - cursor: pointer; - } - .amount .price { - .icon-font( - @icon-down, - @_icon-font-size: 30px, - @_icon-font-text-hide: true, - @_icon-font-position: after, - @_icon-font-display: block - ); - padding-right: @indent__m; - position: relative; - &:after { - position: absolute; - right: -5px; - top: -12px; - } - } - &.expanded { - .mark, - .amount { - border-bottom: 0; - } - .amount .price { - .icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after - ); - } - } - } - &-details { - border-bottom: @border-width__base solid @border-color__base; - display: none; - &.shown { - display: table-row; - } - } - } - .table-wrapper { - margin-bottom: 0; - } - .table-caption { - &:extend(.abs-no-display all); - } + > .content { + display: none; } + &.active { + > .title { + .icon-font-symbol( + @_icon-font-content: @icon-prev, + @_icon-font-position: after + ); + } + > .content { + display: block; + } + } + .item-options { + margin-left: 0; + } + .fieldset { + margin: 15px 0 @indent__m @indent__xs; + .field { + margin: 0 0 @indent__s; + &.note { + font-size: @font-size__s; + } + } + } + .fieldset { + .methods { + .field { + > .label { + display: inline; + } + } + } + } + .fieldset.estimate { + > .legend, + > .legend + br { + &:extend(.abs-no-display all); + } + } + } + .actions-toolbar { + > .primary { + button { + &:extend(.abs-revert-secondary-color all); + } + } + } + &:extend(.abs-adjustment-incl-excl-tax all); + } - // Products table - &.table-wrapper { - .items { - thead + .item { - border-top: @border-width__base solid @border-color__base; - } - > .item { - border-bottom: @border-width__base solid @border-color__base; - position: relative; - } - } - .col { - padding-top: 20px; - &.qty { - .input-text { - margin-top: -5px; - &:extend(.abs-input-qty all); - } - .label { - &:extend(.abs-visually-hidden all); - } - } - } - .item { - &-actions td { - padding-bottom: @indent__s; - text-align: center; - white-space: normal; - } - .col { - &.item { - display: block; - min-height: 75px; - padding: @indent__m 0 @indent__s 75px; - position: relative; - } - } - } - .actions-toolbar { - &:extend(.abs-add-clearfix all); - > .action { - &:extend(button all); - .link-as-button(); - margin-bottom: @indent__s; - margin-right: @indent__s; - &:last-child { - margin-right: 0; - } - } - } - .action { - &.help.map { - &:extend(.abs-action-button-as-link all); - font-weight: @font-weight__regular; - } - } - .product { - &-item-photo { - display: block; - left: 0; - max-width: 60px; - padding: 0; - position: absolute; - top: 15px; - width: 100%; - } - &-item-details { - white-space: normal; - } - &-item-name { - display: inline-block; - font-weight: @font-weight__regular; - margin-top: -6px; - } - } - .gift-registry-name-label { - &:after { - content: ':'; - } - } - // Product options - .item-options { - font-size: @font-size__s; - margin-bottom: @indent__s; - &:extend(.abs-product-options-list all); - &:extend(.abs-add-clearfix all); - } - - .product-item-name + .item-options { - margin-top: @indent__s; - } + // Totals block + &-totals { + border-top: 1px solid @border-color__base; + padding-top: 10px; + &:extend(.abs-sidebar-totals all); + .table-wrapper { + margin-bottom: 0; + overflow: inherit; + } + } - .product-image-wrapper { - &:extend(.abs-reset-image-wrapper all); - } - .action.configure { - display: inline-block; - margin: 0 0 @indent__base; - } + // Products table + &.table-wrapper { + .items { + thead + .item { + border-top: @border-width__base solid @border-color__base; } - &-container { - .form-cart { - &:extend(.abs-shopping-cart-items all); - } - .checkout-methods-items { - margin-top: @indent__base; - &:extend(.abs-reset-list all); - text-align: center; - .action.primary { - &:extend(.abs-button-l all); - margin-bottom: @indent__s; - width: 100%; - } - } + > .item { + border-bottom: @border-width__base solid @border-color__base; + position: relative; } - } + } + .col { + padding-top: 20px; + &.qty { + .input-text { + margin-top: -5px; + &:extend(.abs-input-qty all); + } + .label { + &:extend(.abs-visually-hidden all); + } + } + } + .item { + &-actions td { + padding-bottom: @indent__s; + text-align: center; + white-space: normal; + } + .col { + &.item { + display: block; + min-height: 75px; + padding: @indent__m 0 @indent__s 75px; + position: relative; + } + } + } + .actions-toolbar { + &:extend(.abs-add-clearfix all); + > .action { + &:extend(button all); + .link-as-button(); + margin-bottom: @indent__s; + margin-right: @indent__s; + &:last-child { + margin-right: 0; + } + } + } + .action { + &.help.map { + &:extend(.abs-action-button-as-link all); + font-weight: @font-weight__regular; + } + } + .product { + &-item-photo { + display: block; + left: 0; + max-width: 60px; + padding: 0; + position: absolute; + top: 15px; + width: 100%; + } + &-item-details { + white-space: normal; + } + &-item-name { + display: inline-block; + font-weight: @font-weight__regular; + margin-top: -6px; + } + } + .gift-registry-name-label { + &:after { + content: ':'; + } + } + // Product options + .item-options { + font-size: @font-size__s; + margin-bottom: @indent__s; + &:extend(.abs-product-options-list all); + &:extend(.abs-add-clearfix all); + } - // - // Cross sell - // --------------------------------------------- + .product-item-name + .item-options { + margin-top: @indent__s; + } - .block.crosssell { - margin-top: 70px; + .product-image-wrapper { + &:extend(.abs-reset-image-wrapper all); + } + .action.configure { + display: inline-block; + margin: 0 0 @indent__base; + } + } + &-container { + .form-cart { + &:extend(.abs-shopping-cart-items all); + } + .checkout-methods-items { + margin-top: @indent__base; + &:extend(.abs-reset-list all); + text-align: center; + .action.primary { + &:extend(.abs-button-l all); + margin-bottom: @indent__s; + width: 100%; + } + } } + } + + // + // Cross sell + // --------------------------------------------- + + .block.crosssell { + margin-top: 70px; + } } // @@ -325,48 +246,48 @@ // _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { - .cart { - &.table-wrapper { - thead { - .col:not(.item) { - display: none; - } - } - .col { - &.qty, - &.price, - &.subtotal, - &.msrp { - box-sizing: border-box; - display: block; - float: left; - text-align: center; - white-space: nowrap; - width: 33%; - &:before { - content: attr(data-th) ':'; - display: block; - font-weight: @font-weight__bold; - padding-bottom: 10px; - } - } - &.msrp { - white-space: normal; - } - } - .item .col.item { - padding-bottom: 0; - } + .cart { + &.table-wrapper { + thead { + .col:not(.item) { + display: none; } - &-container { - .form-cart { - &:extend(.abs-shopping-cart-items-mobile all); - } + } + .col { + &.qty, + &.price, + &.subtotal, + &.msrp { + box-sizing: border-box; + display: block; + float: left; + text-align: center; + white-space: nowrap; + width: 33%; + &:before { + content: attr(data-th) ':'; + display: block; + font-weight: @font-weight__bold; + padding-bottom: 10px; + } } - &.table-wrapper { - overflow: inherit; + &.msrp { + white-space: normal; } + } + .item .col.item { + padding-bottom: 0; + } + } + &-container { + .form-cart { + &:extend(.abs-shopping-cart-items-mobile all); + } } + &.table-wrapper { + overflow: inherit; + } + } } // @@ -374,69 +295,69 @@ // _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { - .cart { - &-container { - &:extend(.abs-add-clearfix-desktop all); - .form-cart { - &:extend(.abs-shopping-cart-items-desktop all); - } - .widget { - float: left; - } + .cart { + &-container { + &:extend(.abs-add-clearfix-desktop all); + .form-cart { + &:extend(.abs-shopping-cart-items-desktop all); + } + .widget { + float: left; + } + } + &-summary { + float: right; + position: relative; + width: 23%; + .actions-toolbar { + .column.main & { + &:extend(.abs-reset-left-margin-desktop all); + > .secondary { + float: none; + } } - &-summary { - float: right; - position: relative; - width: 23%; - .actions-toolbar { - .column.main & { - &:extend(.abs-reset-left-margin-desktop all); - > .secondary { - float: none; - } - } - } - .block { - .fieldset { - .field { - .form-field-type-revert(@_type: block); - margin: 0 0 @indent__s; - } - } - } + } + .block { + .fieldset { + .field { + .form-field-type-revert(@_type: block); + margin: 0 0 @indent__s; + } } + } + } - &.table-wrapper { - .item { - .col { - &.item { - padding: 27px 8px @indent__s; - } - } - &-actions td { - text-align: right; - } - } - .product { - &-item-photo { - display: table-cell; - max-width: 100%; - padding-right: @indent__base; - position: static; - vertical-align: top; - width: 1%; - } - &-item-details { - display: table-cell; - vertical-align: top; - white-space: normal; - width: 99%; - } - } - .item-actions .actions-toolbar { - text-align: left; - &:extend(.abs-reset-left-margin-desktop all); - } + &.table-wrapper { + .item { + .col { + &.item { + padding: 27px 8px @indent__s; + } + } + &-actions td { + text-align: right; + } + } + .product { + &-item-photo { + display: table-cell; + max-width: 100%; + padding-right: @indent__base; + position: static; + vertical-align: top; + width: 1%; + } + &-item-details { + display: table-cell; + vertical-align: top; + white-space: normal; + width: 99%; } + } + .item-actions .actions-toolbar { + text-align: left; + &:extend(.abs-reset-left-margin-desktop all); + } } + } } diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_checkout.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_checkout.less new file mode 100644 index 0000000000000000000000000000000000000000..db93ffc7fe3f173d56b45df4318ea789099a0b04 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_checkout.less @@ -0,0 +1,26 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Page components +// --------------------------------------------- + +@import 'checkout/_checkout.less'; +@import 'checkout/_estimated-total.less'; +@import 'checkout/_progress-bar.less'; +@import 'checkout/_fields.less'; +@import 'checkout/_modals.less'; +@import 'checkout/_tooltip.less'; +@import 'checkout/_shipping.less'; +@import 'checkout/_shipping-policy.less'; + +@import 'checkout/_sidebar.less'; +@import 'checkout/_sidebar-shipping-information.less'; +@import 'checkout/_order-summary.less'; +@import 'checkout/_authentication.less'; + +@import 'checkout/_payments.less'; +@import 'checkout/_payment-options.less'; +@import 'checkout/_checkout-agreements.less'; diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less index 535a47ff7f9ee5ddad63365a0f0f07f37b1208c9..317c57334f11c36998d524588599196c5d632184 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less @@ -5,93 +5,93 @@ // // Variables -// --------------------------------------------- +// _____________________________________________ @minicart__border-color: @color-gray80; @minicart__padding-horizontal: @indent__base; // // Common -// --------------------------------------------- +// _____________________________________________ & when (@media-common = true) { -// -// Minicart -// --------------------------------------------- + // + // Minicart + // --------------------------------------------- -.block-minicart { - .items-total { - float: left; - margin: 0 @indent__s; - .count { - font-weight: @font-weight__bold; + .block-minicart { + .items-total { + float: left; + margin: 0 @indent__s; + .count { + font-weight: @font-weight__bold; + } } - } - .subtotal { - margin: 0 @indent__s; - text-align: right; - .label { - &:extend(.abs-colon all); + .subtotal { + margin: 0 @indent__s; + text-align: right; + .label { + &:extend(.abs-colon all); + } } - } - .amount { - .price-wrapper { - &:first-child { - .price { - font-size: @font-size__l; - font-weight: @font-weight__bold; + .amount { + .price-wrapper { + &:first-child { + .price { + font-size: @font-size__l; + font-weight: @font-weight__bold; + } } } } - } - .subtitle { - display: none; - } - .subtitle { - &.empty { - display: block; - padding: @indent__l 0 @indent__base; - text-align: center; - font-size: 14px; + .subtitle { + display: none; } - } - .text { - &.empty { - text-align: center; + .subtitle { + &.empty { + display: block; + font-size: 14px; + padding: @indent__l 0 @indent__base; + text-align: center; + } } - } - .block-content { - > .actions { - margin-top: 15px; - text-align: center; - > .primary { - margin: 0 @indent__s 15px; - .action { - &.primary { - &:extend(.abs-button-l all); - display: block; - width: 100%; - margin-bottom: 15px; - &:last-child { - margin-bottom: 0; + .text { + &.empty { + text-align: center; + } + } + .block-content { + > .actions { + margin-top: 15px; + text-align: center; + > .primary { + margin: 0 @indent__s 15px; + .action { + &.primary { + &:extend(.abs-button-l all); + display: block; + margin-bottom: 15px; + width: 100%; + &:last-child { + margin-bottom: 0; + } } } } } } + .block-category-link, + .block-product-link, + .block-cms-link, + .block-banners { + margin: 15px 0 0; + text-align: center; + } } - .block-category-link, - .block-product-link, - .block-cms-link, - .block-banners { - margin: 15px 0 0; - text-align: center; - } -} -.minicart-wrapper { - .dropdown( + .minicart-wrapper { + .dropdown( @_toggle-selector: ~".action.showcart", @_options-selector: ~".block-minicart", @_dropdown-toggle-icon-content: @icon-cart, @@ -104,200 +104,229 @@ @_icon-font-color: @minicart-icons-color, @_icon-font-color-hover: @minicart-icons-color-hover, @_icon-font-color-active: @minicart-icons-color - ); - float: right; - .block-minicart { - .css(padding, 25px @minicart__padding-horizontal); - right: 0; - width: 320px; - .block-title { - display: none; - } - &:after { - left: auto; - right: 25px; - } - &:before { - left: auto; - right: 26px; + ); + float: right; + .block-minicart { + .css(padding, 25px @minicart__padding-horizontal); + right: 0; + width: 320px; + .block-title { + display: none; + } + &:after { + left: auto; + right: 25px; + } + &:before { + left: auto; + right: 26px; + } } - } - .product.actions { - text-align: right; - > .primary, - > .secondary { - display: inline; + .product.actions { + text-align: right; + > .primary, > .secondary { + display: inline; + } } - } - .action { - &.close { - width: 40px; - height: 40px; - top: 0; - right: 0; - position: absolute; - .button-reset(); - .button-icon( + .action { + &.close { + .button-icon( @icon-remove, @_icon-font-size: 32px, @_icon-font-line-height: 32px, @_icon-font-text-hide: true - ); - } - &.showcart { - .text { - &:extend(.abs-visually-hidden all); + ); + .button-reset(); + height: 40px; + position: absolute; + right: 0; + top: 0; + width: 40px; } - white-space: nowrap; - .counter.qty { - &.empty { - display: none; + &.showcart { + white-space: nowrap; + .text { + &:extend(.abs-visually-hidden all); + } + .counter.qty { + border-radius: 2px; + clip: none; + .css(color, @page__background-color); + .css(background, @active__color); + display: inline-block; + height: 24px; + line-height: 24px; + margin: 3px 0 0; + min-width: 18px; + overflow: hidden; + padding: 0 3px; + text-align: center; + white-space: normal; + &.empty { + &:extend(.abs-no-display all); + } + } + .counter-label { + &:extend(.abs-visually-hidden all); } - .css(background, @active__color); - border-radius: 2px; - .css(color, @page__background-color); - clip: none; - display: inline-block; - height: 24px; - line-height: 24px; - min-width: 18px; - margin: 3px 0 0; - padding: 0 3px; - overflow: hidden; - text-align: center; - white-space: normal; - } - .counter-label { - &:extend(.abs-visually-hidden all); } } + .minicart-widgets { + margin-top: 15px; + } } - .minicart-widgets { - margin-top: 15px; - } -} -.minicart-items-wrapper { - .css(border, 1px solid @minicart__border-color); - .css(margin, 0 -@minicart__padding-horizontal); - border-left: 0; - border-right: 0; - overflow-x: auto; - padding: 15px; -} + .minicart-items-wrapper { + border-left: 0; + border-right: 0; + .css(margin, 0 -@minicart__padding-horizontal); + .css(border, 1px solid @minicart__border-color); + overflow-x: auto; + padding: 15px; + } -.minicart-items { - .list-reset-styles(0, 0); - .item { - &:not(:first-child) { - .css(border-top, 1px solid @minicart__border-color); - } - padding: @indent__base 0; - &:first-child { - padding-top: 0; + .minicart-items { + .list-reset-styles(0, 0); + .product-item { + padding: @indent__base 0; + &:not(:first-child) { + .css(border-top, 1px solid @minicart__border-color); + } + &:first-child { + padding-top: 0; + } + > .product { + &:extend(.abs-add-clearfix all); + } } - > .product { - &:extend(.abs-add-clearfix all); + .product-image-wrapper { + &:extend(.abs-reset-image-wrapper all); } - } - .product-image-wrapper { - &:extend(.abs-reset-image-wrapper all); - } - .product-item-pricing { - .label { - display: inline-block; - width: 4.5rem; - } - } - .price-minicart { - margin-bottom: @indent__xs; - } - .product-item-photo { - float: left; - } - .product-item-name { - font-weight: @font-weight__regular; - margin: 0 0 @indent__s; - a { - .css(color, @link__color); + .product-item-pricing { + .label { + display: inline-block; + width: 4.5rem; + } } - } - .product-item-details { - padding-left: 88px; - .price { - font-weight: @font-weight__bold; + .price-minicart { + margin-bottom: @indent__xs; } - .price-including-tax, - .price-excluding-tax { - margin: @indent__xs 0; + .product { + > .product-item-photo, + > .product-image-container { + float: left; + } + .toggle { + .icon-font( + @_icon-font-content: @icon-down, + @_icon-font-size: 28px, + @_icon-font-line-height: 16px, + @_icon-font-text-hide: false, + @_icon-font-position: after, + @_icon-font-display: block + ); + cursor: pointer; + position: relative; + &:after { + position: static; + right: @indent__base; + top: 0; + } + } + &.active { + > .toggle { + .icon-font-symbol( + @_icon-font-content: @icon-up, + @_icon-font-position: after + ); + } + } } - .weee[data-label] { - .font-size(11); - .label { - &:extend(.abs-no-display all); + .product-item-name { + font-weight: @font-weight__regular; + margin: 0 0 @indent__s; + a { + .css(color, @link__color); } } - .details-qty { - margin-top: @indent__s; + .product-item-details { + padding-left: 88px; + .price { + font-weight: @font-weight__bold; + } + .price-including-tax, + .price-excluding-tax { + margin: @indent__xs 0 0; + } + .weee[data-label] { + .font-size(11); + .label { + &:extend(.abs-no-display all); + } + } + .details-qty { + margin-top: @indent__s; + } } - } - .product.options { - .tooltip.toggle { - .icon-font( + .product.options { + .tooltip.toggle { + .icon-font( @icon-down, @_icon-font-size: 28px, @_icon-font-line-height: 28px, @_icon-font-text-hide: true, @_icon-font-margin: -3px 0 0 7px, @_icon-font-position: after - ); - .details { - display: none; + ); + .details { + display: none; + } } } - } - .details-qty, - .price-minicart { - .label { - &:extend(.abs-colon all); + .details-qty, + .price-minicart { + .label { + &:extend(.abs-colon all); + } + } + .item-qty { + margin-right: @indent__s; + text-align: center; + width: 40px; + } + .item-update { + .font-size(11); + vertical-align: top; + } + .subtitle { + &:extend(.abs-no-display all); + } + .action { + &.edit, + &.delete { + .icon-font( + @icon-settings, + @_icon-font-size: 28px, + @_icon-font-line-height: 28px, + @_icon-font-text-hide: true, + @_icon-font-color: @color-gray19, + @_icon-font-color-hover: @color-gray19, + @_icon-font-color-active: @color-gray19 + ); + } + &.delete { + .icon-font-symbol( + @_icon-font-content: @icon-trash + ); + } } } - .item-qty { - width: 40px; - text-align: center; - margin-right: @indent__s; - } - .item-update { - vertical-align: top; - .font-size(11); - } - .action { - &.edit, - &.delete { - .icon-font( - @icon-settings, - @_icon-font-size: 28px, - @_icon-font-line-height: 28px, - @_icon-font-text-hide: true, - @_icon-font-color: @color-gray19, - @_icon-font-color-hover: @color-gray19, - @_icon-font-color-active: @color-gray19 - ); - } - &.delete { - .icon-font-symbol( - @_icon-font-content: @icon-trash - ); - } - } -} - } // // Mobile -// --------------------------------------------- +// _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__xs) { .minicart-wrapper .block-minicart { @@ -313,7 +342,7 @@ // // Desktop -// --------------------------------------------- +// _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .minicart-wrapper { diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less new file mode 100644 index 0000000000000000000000000000000000000000..26c1ac83c04217bc2ad84483a5ec3b608cecf4ae --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less @@ -0,0 +1,196 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@block-auth__dropdown__padding: @indent__m; +@block-auth__dropdown__background-color: @color-white; +@block-auth__or-label__size: 36px; +@block-auth__width: 0; +@block-auth__border: 1px solid @color-gray-light3; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .authentication-dropdown { + box-sizing: border-box; + .modal-inner-wrap { + padding: @block-auth__dropdown__padding; + } + } + .authentication-wrapper { + float: right; + margin-top: -1.5*@indent__xl; + max-width: 50%; + position: relative; + z-index: 1; + ._has-auth-shown & { + z-index: @modal__z-index; + } + } + .action-auth-toggle { + &:extend(.abs-action-button-as-link all); + } + .block-authentication { + .block-title { + .font-size(@h3__font-size); + border-bottom: 0; + margin-bottom: @indent__m; + strong { + font-weight: @font-weight__light; + } + } + .field { + .label { + font-weight: @font-weight__regular; + } + } + .actions-toolbar { + margin-bottom: @indent__xs; + > .secondary { + padding-top: @indent__m; + text-align: left; + } + } + .action.action-register, + .action.action-login { + &:extend(.abs-button-l all); + } + .block[class] { + margin: 0; + ul { + list-style: none; + padding-left: @indent__s; + } + .field { + .control, + .label { + float: none; + width: auto; + } + } + & + .block { + border-top: 1px solid @color-gray-light5; + margin-top: @indent__xl; + padding-top: @indent__xl; + position: relative; + &::before { + .css(height, @block-auth__or-label__size); + .css(line-height, @block-auth__or-label__size - 2px); + .css(margin, -(@block-auth__or-label__size/2 + 1px) 0 0 -(@block-auth__or-label__size / 2)); + .css(min-width, @block-auth__or-label__size); + background: @color-white; + border-radius: 50%; + border: 1px solid @color-gray-light5; + box-sizing: border-box; + color: @color-gray-light5; + content: attr(data-label); + display: inline-block; + left: 50%; + letter-spacing: normal; + padding: 0 .2rem; + position: absolute; + text-align: center; + text-transform: uppercase; + top: 0; + } + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .authentication-dropdown { + .css(background-color, @block-auth__dropdown__background-color); + .css(border, @block-auth__border); + position: absolute; + text-align: left; + top: 100%; + transform-origin: 0 0; + transform: scale(1,0); + transition: transform linear .1s, visibility 0s linear .1s; + visibility: hidden; + width: 100%; + &._show { + .css(z-index, @dropdown-list__z-index); + transform: scale(1,1); + transition: transform linear .1s, visibility 0s linear 0s; + visibility: visible; + } + } + .authentication-wrapper { + .column-width(@checkout-sidebar__columns); + text-align: right; + } + .block-authentication { + .block-title { + .font-size(@h2__font-size); + border-bottom: 0; + margin-bottom: @indent__m; + } + .actions-toolbar { + > .primary { + display: inline; + float: right; + margin-right: 0; + .action { + margin-right: 0; + } + } + > .secondary { + float: left; + margin-right: 2rem; + padding-top: 1rem; + } + } + } + .popup-authentication { + .modal-inner-wrap { + min-width: @screen__m; + width: 60%; + } + .block-authentication { + .vendor-prefix-display(flex); + .vendor-prefix-flex-direction(row); + border-top: 1px solid @color-gray-light5; + } + .block[class], + .form-login, + .fieldset, + .block-content { + .vendor-prefix-display(flex); + .vendor-prefix-flex-direction(column); + .vendor-prefix-flex-grow(1); + } + .block[class] { + box-sizing: border-box; + float: left; + padding: @indent__s @indent__l 0 0; + width: 50%; + & + .block { + border-left: 1px solid @color-gray-light5; + border-top: 0; + margin: 0; + padding: @indent__s 0 0 @indent__xl; + &::before { + left: 0; + top: 50%; + } + } + } + .actions-toolbar { + margin-bottom: 0; + margin-top: auto; + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout-agreements.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout-agreements.less new file mode 100644 index 0000000000000000000000000000000000000000..02fbbeb1faa431e4056b78be1daf0cd0c90cffdd --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout-agreements.less @@ -0,0 +1,34 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .checkout-agreements-block { + margin-bottom: @indent__base; + + .action-show { + &:extend(.abs-action-button-as-link all); + vertical-align: baseline; + } + } + + // Checkout Agreements in popup + .checkout-agreements-items { + &:extend(.abs-reset-list all); + padding-bottom: @indent__l; + + .checkout-agreements-item { + margin-bottom: @indent__base; + } + + .checkout-agreements-item-title { + &:extend(.abs-checkout-title all); + border-bottom: 0; + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less new file mode 100644 index 0000000000000000000000000000000000000000..6fcaedd24084e3c230ab32cb01186949bfc06b0e --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less @@ -0,0 +1,86 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-wrapper__margin: @indent__base; +@checkout-wrapper__columns: 8; + +@checkout-step-title__border: @border-width__base solid @color-gray80; +@checkout-step-title__font-size: 26px; +@checkout-step-title__font-weight: @font-weight__light; +@checkout-step-title__margin-bottom: 28px; +@checkout-step-title__padding: @indent__s; + +@checkout-step-title-mobile__font-size: 18px; +@checkout-step-title-mobile__margin-bottom: @indent__base; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + .checkout-container { + &:extend(.abs-add-clearfix all); + .css(margin, 0 0 @checkout-wrapper__margin); + } + + .opc-wrapper { + .css(margin, 0 0 @checkout-wrapper__margin); + + .opc { + &:extend(.abs-reset-list all); + } + + .step-title { + &:extend(.abs-checkout-title all); + .css(margin, 0 0 @checkout-step-title__margin-bottom); + } + + .step-content { + margin: 0 0 @indent__xl; + } + } + + .checkout-onepage-index { + .nav-sections, + .nav-toggle { + display: none; + } + .logo { + margin-left: 0; + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { + .opc-wrapper { + .step-title { + .css(font-size, @checkout-step-title-mobile__font-size); + .css(margin-bottom, @checkout-step-title-mobile__margin-bottom); + border-bottom: 0; + padding-bottom: 0; + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .opc-wrapper { + &:extend(.abs-add-box-sizing-desktop-m all); + .layout-column(2, 1, @checkout-wrapper__columns); + padding-right: @indent__l; + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less new file mode 100644 index 0000000000000000000000000000000000000000..5119231620d6ee172e9906402baedc181b3f77fd --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less @@ -0,0 +1,54 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // + // Checkout Estimated Total + // --------------------------------------------- + + .opc-estimated-wrapper { + &:extend(.abs-add-clearfix all); + &:extend(.abs-no-display-desktop all); + .css(border-bottom, @border-width__base solid @color-gray80); + margin: 0 0 15px; + padding: 18px 15px; + + .estimated-block { + .css(font-size, @checkout-step-title-mobile__font-size); + .css(font-weight, @font-weight__bold); + float: left; + + .estimated-label { + margin: 0 0 @indent__xs; + display: block; + } + } + + .minicart-wrapper { + .action { + &.showcart { + &:before { + .css(color, @primary__color); + } + } + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) { + .opc-estimated-wrapper { + display: none; + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_fields.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_fields.less new file mode 100644 index 0000000000000000000000000000000000000000..17fd35ed14fc6f2229338e1bd568d7ee0dcdfdde --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_fields.less @@ -0,0 +1,33 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-field-validation__border-color: @form-element-validation__border-error; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .field { + .control { + &._with-tooltip { + &:extend(.abs-field-tooltip all); + } + } + &._error { + .control { + input, + select, + textarea { + .css(border-color, @checkout-field-validation__border-color); + } + } + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_modals.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_modals.less new file mode 100644 index 0000000000000000000000000000000000000000..a11423841e94f407b735e34095037f10978ce784 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_modals.less @@ -0,0 +1,61 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-modal-popup__width: 800px; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .checkout-onepage-index { + .modal-popup { + .field-tooltip { + .field-tooltip-content { + &:extend(.abs-checkout-tooltip-content-position-top all); + } + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .checkout-onepage-index { + .modal-popup { + .form-shipping-address { + .css(max-width, @checkout-shipping-address__max-width); + } + .modal-footer { + .action-save-address { + float: right; + margin: 0 0 0 @indent__s; + } + .action-hide-popup { + &:extend(.abs-action-button-as-link all); + } + } + } + } +} + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) { + .checkout-onepage-index { + .modal-popup { + .modal-inner-wrap { + .css(margin-left, -(@checkout-modal-popup__width/2)); + .css(width, @checkout-modal-popup__width); + left: 50%; + } + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_order-summary.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_order-summary.less new file mode 100644 index 0000000000000000000000000000000000000000..0cc46910745bc2c366c049f1fa689ca0c6a7c0e5 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_order-summary.less @@ -0,0 +1,171 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-summary__background-color: @color-white-smoke; +@checkout-summary__padding: 22px @indent__l; + +@checkout-summary-title__margin: @indent__s; +@checkout-summary-mark-value__color: @color-gray60; + +@checkout-summary-items__max-height: 370px; +@checkout-summary-items__padding: 15px; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // + // Order Summary + // --------------------------------------------- + + .opc-block-summary { + &:extend(.abs-add-box-sizing all); + .css(background, @checkout-summary__background-color); + .css(padding, @checkout-summary__padding); + margin: 0 0 @indent__base; + + > .title { + &:extend(.abs-checkout-title all); + display: block; + } + + // Totals table + .table-totals { + &:extend(.abs-sidebar-totals all); + } + + .mark { + .value { + .css(color, @checkout-summary-mark-value__color); + display: block; + } + } + + .grand.incl { + & + .grand.excl { + .mark, + .amount { + border-top: 0; + .font-size(14); + padding-top: 0; + strong { + font-weight: @font-weight__regular; + } + } + } + } + + .not-calculated { + font-style: italic; + } + + // + // Items list + // --------------------------------------------- + + // Block title + .items-in-cart { + > .title { + border-bottom: @border-width__base solid @border-color__base; + .css(padding, @indent__s @indent__xl @indent__s 0); + cursor: pointer; + .icon-font( + @icon-down, + @_icon-font-size: 30px, + @_icon-font-line-height: 12px, + @_icon-font-text-hide: true, + @_icon-font-margin: 3px 0 0, + @_icon-font-position: after, + @_icon-font-display: block + ); + margin-bottom: 0; + position: relative; + &:after { + position: absolute; + right: 0; + top: @indent__s; + } + strong { + .font-size(18); + font-weight: @font-weight__light; + margin: 0; + } + } + &.active { + > .title { + .icon-font-symbol( + @_icon-font-content: @icon-up, + @_icon-font-position: after + ); + } + } + .product { + position: relative; + } + } + + // Cart items + .minicart-items-wrapper { + .css(margin, 0 -(@checkout-summary-items__padding) 0 0); + .css(max-height, @checkout-summary-items__max-height); + .css(padding, @checkout-summary-items__padding @checkout-summary-items__padding 0 0); + border: 0; + } + .column.main & { + .product-item { + margin: 0; + padding-left: 0; + } + } + .product-item { + .product-item-inner { + display: table; + margin: 0 0 @indent__s; + width: 100%; + } + .product-item-name-block { + display: table-cell; + padding-right: @indent__xs; + text-align: left; + } + .subtotal { + display: table-cell; + text-align: right; + } + .price { + .font-size(16); + font-weight: @font-weight__regular; + } + .price-including-tax { + & + .price-excluding-tax { + margin: 0; + .price { + .font-size(10); + } + } + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .opc-summary-wrapper { + .modal-header { + .action-close { + display: none; + } + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less new file mode 100644 index 0000000000000000000000000000000000000000..c9741c735bbf296c192f285242f05704190b1515 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less @@ -0,0 +1,139 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-payment-option-title__border: @checkout-payment-method-title__border; +@checkout-payment-option-title__color: @link__color; +@checkout-payment-option-title__padding: @checkout-payment-method-title__padding; +@checkout-payment-option-title-mobile__padding: @checkout-payment-method-title-mobile__padding; + +@checkout-payment-option-title-icon__font-size: 32px; +@checkout-payment-option-title-icon__line-height: 16px; +@checkout-payment-option-title-icon__margin: 0; +@checkout-payment-option-title-icon__color: @minicart-icons-color; +@checkout-payment-option-title-icon__hover__color: @primary__color; + +@checkout-payment-option-content__padding__xl: @checkout-payment-method-content__padding__xl; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .checkout-payment-method { + .payment-option { + &._active { + .payment-option-title { + .action-toggle { + &:after { + content: @icon-up; + } + } + } + } + &._collapsible { + .payment-option-title { + cursor: pointer; + } + .payment-option-content { + display: none; + } + } + } + + .payment-option-title { + .css(border-top, @checkout-payment-option-title__border); + .css(padding, @checkout-payment-option-title__padding 0); + + .action-toggle { + .css(color, @checkout-payment-option-title__color); + .icon-font( + @icon-down, + @_icon-font-size: @checkout-payment-option-title-icon__font-size, + @_icon-font-line-height: @checkout-payment-option-title-icon__line-height, + @_icon-font-color: @checkout-payment-option-title-icon__color, + @_icon-font-color-hover: @checkout-payment-option-title-icon__hover__color, + @_icon-font-color-active: @checkout-payment-option-title-icon__color, + @_icon-font-margin: @checkout-payment-option-title-icon__margin, + @_icon-font-position: after + ); + } + } + + .payment-option-content { + .css(padding, 0 0 @indent__base @checkout-payment-option-content__padding__xl); + } + + .payment-option-inner { + margin: 0 0 @indent__base; + } + + .credit-card-types { + padding: 0; + .item { + display: inline-block; + list-style: none; + margin: 0 @indent__xs 0 0; + &._active { + font-weight: @font-weight__bold; + img { + -webkit-filter: grayscale(0%); + filter: grayscale(0%); + filter: none; + } + } + } + img { + -webkit-filter: grayscale(100%); // For Webkit browsers + -webkit-transition: all .6s ease; // Fade to color for Chrome and Safari + filter: grayscale(100%); + filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale"); // Firefox 10+, Firefox on Android + filter: gray; // For IE 6 - 9 + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { + .checkout-payment-method { + .payment-option { + .css(margin, 0 -(@checkout-payment-option-title-mobile__padding)); + + .payment-option-title { + .css(padding, @checkout-payment-option-title-mobile__padding) + } + + .payment-option-content { + .css(padding, 0 @checkout-payment-option-title-mobile__padding @indent__base); + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .checkout-payment-method { + .payment-option-title { + .css(padding-left, @checkout-payment-option-content__padding__xl); + } + .payment-option-content { + .payment-option-inner { + + .actions-toolbar { + margin-left: 0; + } + } + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less new file mode 100644 index 0000000000000000000000000000000000000000..b880027e5493df788807dbbeabfaa94d0c36fb0b --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less @@ -0,0 +1,198 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-payment-method-title__border: @checkout-shipping-method__border; +@checkout-payment-method-title__padding: @checkout-shipping-method__padding; +@checkout-payment-method-title-mobile__padding: 15px; + +@checkout-payment-method-content__padding__xl: 22px; + +@checkout-billing-address-details__line-height: 27px; +@checkout-billing-address-details__padding: 0 0 0 23px; +@checkout-billing-address-form__max-width: @checkout-shipping-address__max-width; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .checkout-payment-method { + .step-title { + margin-bottom: 0; + } + .payment-method { + &:first-child { + .payment-method-title { + border-top: 0; + } + } + &._active { + .payment-method-content { + display: block; + } + } + .action { + &.primary { + &:extend(.abs-button-l all); + } + } + } + + .payment-method-title { + .css(border-top, @checkout-payment-method-title__border); + .css(padding, @checkout-payment-method-title__padding 0); + margin: 0; + + .payment-icon { + display: inline-block; + margin-right: @indent__xs; + vertical-align: middle; + } + + .action-help { + display: inline-block; + margin-left: @indent__xs; + } + } + + .payment-method-content { + display: none; + .css(padding, 0 0 @indent__base @checkout-payment-method-content__padding__xl); + .fieldset { + &:not(:last-child) { + margin: 0 0 @indent__base; + } + > .field { + margin: 0 0 @indent__base; + } + } + } + + .field-select-billing, + .billing-address-form { + .css(max-width, @checkout-billing-address-form__max-width); + } + + .billing-address-same-as-shipping-block { + margin: 0 0 @indent__s; + } + + .payment-method-billing-address { + margin: 0 0 @indent__base; + + .primary { + .action-update { + margin-right: 0; + } + } + + .action-cancel { + &:extend(.abs-action-button-as-link all); + } + + .billing-address-details { + .css(line-height, @checkout-billing-address-details__line-height); + .css(padding, @checkout-billing-address-details__padding); + + .action-edit-address { + &:extend(.abs-action-button-as-link all); + } + } + } + + .payment-method-note { + & + .payment-method-billing-address { + margin-top: @indent__base; + } + } + + .field-select-billing { + > .label { + &:extend(.abs-visually-hidden all); + } + } + .payment-method-iframe { + background-color: transparent; + display: none; + width: 100%; + } + .no-payments-block { + margin: @indent__base 0; + } + .ccard { + .legend { + &:extend(.abs-visually-hidden all); + } + .year { + padding-left: @indent__l; + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { + .checkout-payment-method { + .payment-methods { + .css(margin, 0 -(@checkout-payment-method-title-mobile__padding)); + } + + .payment-method-title { + .css(padding, @checkout-payment-method-title-mobile__padding) + } + + .payment-method-content { + .css(padding, 0 @checkout-payment-method-title-mobile__padding @indent__base); + } + + .payment-method-billing-address { + .action-cancel { + margin-top: @indent__s; + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .checkout-payment-method { + .payment-methods { + .actions-toolbar { + .primary { + float: right; + margin: 0; + } + } + } + .fieldset { + > .field-select-billing { + > .control { + float: none; + width: 100%; + } + } + } + } + .payment-method-billing-address { + .action-update { + float: right; + } + .actions-toolbar { + .action-cancel { + margin: 6px @indent__base 0 0; + } + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less new file mode 100644 index 0000000000000000000000000000000000000000..386889c75d410cd854fbced42f136d0ce4bb0dd8 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less @@ -0,0 +1,169 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-progress-bar__font-size: 18px; +@checkout-progress-bar__font-weight: @font-weight__light; +@checkout-progress-bar__margin: @indent__base; + +@checkout-progress-bar-item__background-color: @color-gray-middle1; +@checkout-progress-bar-item__border-radius: 6px; +@checkout-progress-bar-item__color: @primary__color; +@checkout-progress-bar-item__margin: @indent__s; +@checkout-progress-bar-item__width: 185px; +@checkout-progress-bar-item__active__background-color: @color-orange-red1; +@checkout-progress-bar-item__complete__color: @link__color; + +@checkout-progress-bar-item-element__height: @checkout-progress-bar-item-element__width; +@checkout-progress-bar-item-element__width: 38px; + +@checkout-progress-bar-item-element-inner__background-color: @page__background-color; +@checkout-progress-bar-item-element-inner__color: @checkout-progress-bar-item__color; +@checkout-progress-bar-item-element-inner__height: @checkout-progress-bar-item-element-inner__width; +@checkout-progress-bar-item-element-inner__width: @checkout-progress-bar-item-element__width - (@checkout-progress-bar-item-element-outer-radius__width * 2); +@checkout-progress-bar-item-element-inner__active__content: @icon-checkmark; +@checkout-progress-bar-item-element-inner__active__font-size: 28px; +@checkout-progress-bar-item-element-inner__active__line-height: 1; + +@checkout-progress-bar-item-element-outer-radius__width: 6px; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // + // Checkout Progress Bar + // --------------------------------------------- + + .opc-progress-bar { + &:extend(.abs-reset-list all); + .css(margin, 0 0 @checkout-progress-bar__margin); + counter-reset: i; + font-size: 0; + } + .opc-progress-bar-item { + .css(margin, 0 0 @checkout-progress-bar-item__margin); + display: inline-block; + position: relative; + text-align: center; + vertical-align: top; + width: 50%; + + &:before { // Horizontal line + .css(background, @checkout-progress-bar-item__background-color); + .css(top, @checkout-progress-bar-item-element__width/2); + content: ''; + height: 7px; + left: 0; + position: absolute; + width: 100%; + } + + &:first-child { + &:before { + .css(border-radius, @checkout-progress-bar-item__border-radius 0 0 @checkout-progress-bar-item__border-radius); + } + } + + &:last-child { + &:before { + .css(border-radius, 0 @checkout-progress-bar-item__border-radius @checkout-progress-bar-item__border-radius 0); + } + } + + > span { + display: inline-block; + padding-top: 45px; + width: 100%; + word-wrap: break-word; + + .typography( + @_color: @checkout-progress-bar-item__background-color, + @_font-family: false, + @_font-size: @checkout-progress-bar__font-size, + @_font-style: false, + @_font-weight: @checkout-progress-bar__font-weight, + @_line-height: false + ); + + &:before, // Item element + &:after { + .css(background, @checkout-progress-bar-item__background-color); + .css(height, @checkout-progress-bar-item-element__height); + .css(margin-left, -(@checkout-progress-bar-item-element__width/2)); + .css(width, @checkout-progress-bar-item-element__width); + border-radius: 50%; + content: ''; + left: 50%; + position: absolute; + top: 0; + } + + &:after { // Item element inner + .css(background, @checkout-progress-bar-item-element-inner__background-color); + .css(height, @checkout-progress-bar-item-element-inner__height); + .css(margin-left, -(@checkout-progress-bar-item-element-inner__width/2)); + .css(top, @checkout-progress-bar-item-element-outer-radius__width); + .css(width, @checkout-progress-bar-item-element-inner__width); + content: counter(i); + counter-increment: i; + .typography( + @_color: @checkout-progress-bar-item-element-inner__color, + @_font-family: false, + @_font-size: @checkout-progress-bar__font-size, + @_font-style: false, + @_font-weight: @font-weight__semibold, + @_line-height: false + ); + } + } + + &._active { + &:before { + background: @checkout-progress-bar-item__active__background-color; + } + > span { + .css(color, @checkout-progress-bar-item__color); + &:before { + .css(background, @checkout-progress-bar-item__active__background-color); + } + &:after { + .css(content, @checkout-progress-bar-item-element-inner__active__content); + .css(font-family, @icons__font-name); + .css(line-height, @checkout-progress-bar-item-element-inner__active__line-height); + .font-size(@checkout-progress-bar-item-element-inner__active__font-size); + } + } + } + + &._complete { + cursor: pointer; + > span { + .css(color, @checkout-progress-bar-item__color); + &:after { + .css(content, @checkout-progress-bar-item-element-inner__active__content); + .css(font-family, @icons__font-name); + .css(line-height, @checkout-progress-bar-item-element-inner__active__line-height); + .font-size(@checkout-progress-bar-item-element-inner__active__font-size); + } + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .opc-progress-bar-item { + .css(width, @checkout-progress-bar-item__width); + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping-policy.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping-policy.less new file mode 100644 index 0000000000000000000000000000000000000000..adb28706810e8c0f90b112c38936cfe1fc5a9a73 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping-policy.less @@ -0,0 +1,67 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-shipping-policy-action__color: @link__color; +@checkout-shipping-policy-tooltip__width: 420px; +@checkout-shipping-policy-tooltip-mobile__width: 300px; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .checkout-shipping-method { + position: relative; + } + + .shipping-policy-block { + &.field-tooltip { + top: 12px; + + .field-tooltip-action { + .css(color, @checkout-shipping-policy-action__color); + cursor: pointer; + &:before { + display: none; + } + } + + .field-tooltip-content { + &:extend(.abs-add-box-sizing all); + &:extend(.abs-checkout-tooltip-content-position-top all); + .css(width, @checkout-shipping-policy-tooltip__width); + top: @indent__l; + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { + .shipping-policy-block { + &.field-tooltip { + margin-bottom: @indent__base; + position: relative; + right: auto; + top: auto; + + .field-tooltip-content { + .css(width, @checkout-shipping-policy-tooltip-mobile__width); + right: auto; + &:before, + &:after { + right: auto; + } + } + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less new file mode 100644 index 0000000000000000000000000000000000000000..3b052c7401101077be3125a7b522953a515acb3b --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less @@ -0,0 +1,321 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-shipping-address__max-width: 600px; + +@checkout-shipping-item-icon__background-color: @checkout-shipping-item__active__border-color; +@checkout-shipping-item-icon__color: @color-white; +@checkout-shipping-item-icon__content: @icon-checkmark; + +@checkout-shipping-item__border: 2px solid transparent; +@checkout-shipping-item__line-height: 30px; +@checkout-shipping-item__margin: 0 0 @indent__base; +@checkout-shipping-item__padding: @indent__base (@indent__l + 5px) @indent__base @indent__base; +@checkout-shipping-item__transition: .3s border-color; +@checkout-shipping-item__width: 100%/3; +@checkout-shipping-item-tablet__width: 100%/2; +@checkout-shipping-item-mobile__width: 100%; +@checkout-shipping-item__active__border-color: @color-orange-red1; + +@checkout-shipping-item-icon__selected__height: 27px; +@checkout-shipping-item-icon__selected__width: 29px; + +@checkout-shipping-item-mobile__padding: 0 0 15px; +@checkout-shipping-item-mobile__margin: @checkout-shipping-item-mobile__padding; +@checkout-shipping-item-mobile__active__padding: 15px (@indent__l + 5px) 15px 18px; + +@checkout-shipping-item-before__border-color: @color-gray80; +@checkout-shipping-item-before__height: calc(~"100% - 20px"); + +@checkout-shipping-method__border: @checkout-step-title__border; +@checkout-shipping-method__padding: @indent__base; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + .opc-wrapper { + + // + // Shipping Address + // --------------------------------------------- + + .form-login, + .form-shipping-address { + margin-bottom: @indent__base; + + .fieldset { + .field { + .label { + font-weight: @font-weight__regular; + } + } + .note { + font-size: @font-size__base; + margin-top: @indent__s; + } + } + } + + .shipping-address-items { + font-size: 0; + } + + .shipping-address-item { + &:extend(.abs-add-box-sizing all); + .css(border, @checkout-shipping-item__border); + .css(line-height, @checkout-shipping-item__line-height); + .css(margin, @checkout-shipping-item__margin); + .css(padding, @checkout-shipping-item__padding); + .css(transition, @checkout-shipping-item__transition); + .css(width, @checkout-shipping-item-tablet__width); + display: inline-block; + font-size: @font-size__base; + position: relative; + vertical-align: top; + word-wrap: break-word; + + &.selected-item { + .css(border-color, @checkout-shipping-item__active__border-color); + + &:after { + .css(background, @checkout-shipping-item-icon__background-color); + .css(color, @checkout-shipping-item-icon__color); + .css(content, @checkout-shipping-item-icon__content); + .css(font-family, @icons__font-name); + .css(height, @checkout-shipping-item-icon__selected__height); + .css(width, @checkout-shipping-item-icon__selected__width); + font-size: 27px; + line-height: 21px; + padding-top: 2px; + position: absolute; + right: 0; + text-align: center; + top: 0; + } + + .action-select-shipping-item { + &:extend(.abs-no-display-s all); + visibility: hidden; + } + } + } + + .field { + &.addresses { + &:extend(.abs-add-clearfix all); + } + } + + .action-show-popup { + margin: 0 0 @indent__base; + > span { + &:before { + content: '+'; + padding-right: @indent__xs; + } + } + } + + .action-select-shipping-item { + float: right; + margin: @indent__base 0 0; + } + + .edit-address-link { + &:extend(.abs-action-button-as-link all); + display: block; + float: left; + margin: 26px 5px 0 0; + } + } + + // + // Shipping Methods + // --------------------------------------------- + + .checkout-shipping-method { + .step-title { + margin-bottom: 0; + } + .no-quotes-block { + margin: @indent__base 0; + } + } + + .methods-shipping { + .actions-toolbar { + .action { + &.primary { + &:extend(.abs-button-l all); + margin: @indent__base 0 0; + } + } + } + } + + .table-checkout-shipping-method { + thead { + th { + display: none; + } + } + tbody { + td { + .css(border-top, @checkout-shipping-method__border); + .css(padding-bottom, @checkout-shipping-method__padding); + .css(padding-top, @checkout-shipping-method__padding); + &:first-child { + padding-left: 0; + padding-right: 0; + width: 20px; + } + } + + tr { + &:first-child { + td { + border-top: none; + } + } + } + .row-error { + td { + border-top: none; + padding-bottom: @indent__s; + padding-top: 0; + } + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { + .opc-wrapper { + .form-login { + .css(border-bottom, 1px solid @checkout-shipping-item-before__border-color); + .css(margin, @checkout-shipping-item-mobile__padding); + .css(padding, @checkout-shipping-item-mobile__padding); + } + .shipping-address-item { + .css(border-bottom, 1px solid @checkout-shipping-item-before__border-color); + .css(margin, @checkout-shipping-item-mobile__margin); + .css(padding, @checkout-shipping-item-mobile__padding); + width: 100%; + &.selected-item { + .css(padding, @checkout-shipping-item-mobile__active__padding); + border-bottom-width: 2px; + + .edit-address-link { + .css(right, @checkout-shipping-item-icon__selected__width + @indent__s); + } + } + } + + .action-select-shipping-item { + float: none; + margin-top: @indent__s; + width: 100%; + } + + .action-show-popup { + width: 100%; + } + + .edit-address-link { + .icon-font( + @icon-settings, + @_icon-font-size: 28px, + @_icon-font-line-height: 28px, + @_icon-font-text-hide: true, + @_icon-font-color: @color-gray19, + @_icon-font-color-hover: @color-gray19, + @_icon-font-color-active: @color-gray19 + ); + margin: 0; + position: absolute; + right: 0; + top: 1px; + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .checkout-shipping-method { + .actions-toolbar { + > .primary { + float: right; + } + .action { + &.primary { + margin: 0; + } + } + } + } + + .opc-wrapper { + .form-login, + .form-shipping-address { + .css(max-width, @checkout-shipping-address__max-width); + } + } + .table-checkout-shipping-method { + width: auto; + } +} + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) { + .opc-wrapper { + .shipping-address-item { + .css(width, @checkout-shipping-item__width); + + &:before { + .css(background, @checkout-shipping-item-before__border-color); + .css(height, @checkout-shipping-item-before__height); + content: ''; + left: 0; + position: absolute; + top: 0; + width: 1px; + } + + &:nth-child(3n+1) { + &:before { + display: none; + } + } + + &.selected-item { + &:before { + display: none; + } + + + .shipping-address-item { + &:before { + display: none; + } + } + } + } + } + .table-checkout-shipping-method { + min-width: 500px; + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar-shipping-information.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar-shipping-information.less new file mode 100644 index 0000000000000000000000000000000000000000..ed940f5fd3c4b45ee959dbfa48335ae02c642a7c --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar-shipping-information.less @@ -0,0 +1,69 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-sidebar-shipping-information__padding: @indent__l; +@checkout-sidebar-shipping-information__line-height: @checkout-billing-address-details__line-height; + +@checkout-sidebar-shipping-information-edit-icon__color: @minicart-icons-color; +@checkout-sidebar-shipping-information-edit-icon__content: @icon-settings; +@checkout-sidebar-shipping-information-edit-icon__font-size: 28px; +@checkout-sidebar-shipping-information-edit-icon__line-height: 28px; +@checkout-sidebar-shipping-information-edit-icon__top: 2px; +@checkout-sidebar-shipping-information-edit-icon__hover__color: @primary__color; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // + // Shipping Information + // --------------------------------------------- + + .opc-block-shipping-information { + .css(padding, 0 @checkout-sidebar-shipping-information__padding); + + .shipping-information-title { + &:extend(.abs-checkout-title all); + .css(border-bottom, @checkout-step-title__border); + margin: 0 0 @indent__base; + position: relative; + + .action-edit { + &:extend(.abs-action-button-as-link all); + .css(top, @checkout-sidebar-shipping-information-edit-icon__top); + .icon-font( + @checkout-sidebar-shipping-information-edit-icon__content, + @_icon-font-size: @checkout-sidebar-shipping-information-edit-icon__font-size, + @_icon-font-line-height: @checkout-sidebar-shipping-information-edit-icon__line-height, + @_icon-font-text-hide: true, + @_icon-font-color: @checkout-sidebar-shipping-information-edit-icon__color, + @_icon-font-color-hover: @checkout-sidebar-shipping-information-edit-icon__hover__color, + @_icon-font-color-active: @checkout-sidebar-shipping-information-edit-icon__color + ); + margin: 0; + position: absolute; + right: 0; + } + } + + .shipping-information-content { + .css(line-height, @checkout-sidebar-shipping-information__line-height); + .actions-toolbar { + margin-left: 0; + } + } + + .ship-to, + .ship-via { + margin: 0 0 @indent__base; + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar.less new file mode 100644 index 0000000000000000000000000000000000000000..83934eaf6aab5185021cf59db52d2ea4f7c69c9a --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar.less @@ -0,0 +1,23 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-sidebar__margin: @indent__base; +@checkout-sidebar__margin__xl: 46px; +@checkout-sidebar__columns: 4; + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .opc-sidebar { + .css(margin, @checkout-sidebar__margin__xl 0 @checkout-sidebar__margin); + .layout-column(2, 2, @checkout-sidebar__columns); + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less new file mode 100644 index 0000000000000000000000000000000000000000..d867cc3387355f400f35932bbad34242d21c4c06 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less @@ -0,0 +1,137 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-tooltip__hover__z-index: @tooltip__z-index; +@checkout-tooltip-breakpoint__screen-m: @modal-popup-breakpoint-screen__m; + +@checkout-tooltip-icon-arrow__font-size: 10px; +@checkout-tooltip-icon-arrow__left: -( @checkout-tooltip-content__padding + @checkout-tooltip-icon-arrow__font-size - @checkout-tooltip-content__border-width); + +@checkout-tooltip-icon__color: @color-gray-light2; +@checkout-tooltip-icon__content: @icon-help; +@checkout-tooltip-icon__font-size: 24px; +@checkout-tooltip-icon__hover__color: @primary__color; + +@checkout-tooltip-content__background-color: @color-gray-light01; +@checkout-tooltip-content__border-color: @color-gray60; +@checkout-tooltip-content__border-width: 1px; +@checkout-tooltip-content__font-size: @font-size__base; +@checkout-tooltip-content__padding: 12px; +@checkout-tooltip-content__width: 270px; +@checkout-tooltip-content__active__border-color: darken(@checkout-tooltip-content__border-color, 20%); + +@checkout-tooltip-content-mobile-popup__width: 200px; +@checkout-tooltip-content-mobile__right: -(@indent__s); +@checkout-tooltip-content-mobile__top: 30px + @checkout-tooltip-icon-arrow__font-size; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + .field-tooltip { + position: absolute; + right: 0; + top: 1px; + + &:hover { + .css(z-index, @checkout-tooltip__hover__z-index); + cursor: pointer; + .field-tooltip-content { + display: block; + } + .field-tooltip-action { + &:before { + .css(color, @checkout-tooltip-icon__hover__color); + } + } + } + + .field-tooltip-action { + .icon-font( + @checkout-tooltip-icon__content, + @_icon-font-size: @checkout-tooltip-icon__font-size, + @_icon-font-text-hide: true, + @_icon-font-color: @checkout-tooltip-icon__color, + @_icon-font-color-hover: @checkout-tooltip-icon__hover__color, + @_icon-font-color-active: false + ); + &:focus { + &:before { + .css(color, @checkout-tooltip-icon__hover__color); + } + + .field-tooltip-content { + display: block; + } + } + } + + .field-tooltip-content { + .css(background, @checkout-tooltip-content__background-color); + .css(border, @checkout-tooltip-content__border-width solid @checkout-tooltip-content__border-color); + .css(border-radius, @checkout-tooltip-content__border-width); + .css(font-size, @checkout-tooltip-content__font-size); + .css(padding, @checkout-tooltip-content__padding); + .css(width, @checkout-tooltip-content__width); + display: none; + left: 38px; + position: absolute; + text-transform: none; + top: -9px; + word-wrap: break-word; + z-index: 2; + + &:before, + &:after { + .arrow( + @_position: left, + @_size: @checkout-tooltip-icon-arrow__font-size, + @_color: @checkout-tooltip-content__background-color + ); + .css(left, @checkout-tooltip-icon-arrow__left); + .css(top, @checkout-tooltip-content__padding); + content: ''; + display: block; + position: absolute; + z-index: 3; + } + &:before { + .css(border-right-color, @checkout-tooltip-content__active__border-color); + } + &:after { + .css(border-right-color, @checkout-tooltip-content__background-color); + width: 1px; + z-index: 4; + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__xs) { + .modal-popup { + .field-tooltip { + .field-tooltip-content { + .css(width, @checkout-tooltip-content-mobile-popup__width); + } + } + } +} + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @checkout-tooltip-breakpoint__screen-m) { + .field-tooltip { + .field-tooltip-content { + &:extend(.abs-checkout-tooltip-content-position-top-mobile all); + } + } +} diff --git a/app/design/frontend/Magento/blank/Magento_SalesRule/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_SalesRule/web/css/source/_module.less new file mode 100644 index 0000000000000000000000000000000000000000..8361a32c5e8f3a20e2278ab8896b015237ade8c0 --- /dev/null +++ b/app/design/frontend/Magento/blank/Magento_SalesRule/web/css/source/_module.less @@ -0,0 +1,21 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .opc-wrapper { + .form-discount { + max-width: 500px; + .field { + .label { + &:extend(.abs-visually-hidden all); + } + } + } + } +} diff --git a/app/design/frontend/Magento/blank/web/css/_styles.less b/app/design/frontend/Magento/blank/web/css/_styles.less index e1f7113c61eafb29ebc4494b82ab2269961c86f9..75ff8775d8c8a10a656cc55c1d0bfd163bb4f800 100644 --- a/app/design/frontend/Magento/blank/web/css/_styles.less +++ b/app/design/frontend/Magento/blank/web/css/_styles.less @@ -5,3 +5,4 @@ @import 'source/lib/_lib.less'; // Global lib @import 'source/_sources.less'; // Theme styles +@import 'source/_components.less'; // Components styles (modal/sliding panel) diff --git a/app/design/frontend/Magento/blank/web/css/source/_components.less b/app/design/frontend/Magento/blank/web/css/source/_components.less new file mode 100644 index 0000000000000000000000000000000000000000..9f6db89c38d126d254ae3e4423ed7fccf8d3e1ed --- /dev/null +++ b/app/design/frontend/Magento/blank/web/css/source/_components.less @@ -0,0 +1,11 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Components +// _____________________________________________ + +@import 'components/_modals.less'; // from lib +@import 'components/_modals_extend.less'; // local diff --git a/app/design/frontend/Magento/blank/web/css/source/_extends.less b/app/design/frontend/Magento/blank/web/css/source/_extends.less index df818e7003ce2e68d7f529b31d2af5e2f82e6943..19705339dae3c4f0430aac361f16a2952ef1350c 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_extends.less +++ b/app/design/frontend/Magento/blank/web/css/source/_extends.less @@ -507,6 +507,12 @@ } } +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .abs-add-box-sizing-desktop-m { + @abs-add-box-sizing(); + } +} + // // Revert field type // --------------------------------------------- @@ -1022,9 +1028,176 @@ } // -// Form Field Date Input -//-------------------------------------- +// Form Field Date Input +// --------------------------------------------- + .abs-field-date-input { - margin-right: @indent__s; + .css(margin-right, @indent__s); width: calc(~"100% - (@{icon-calendar__font-size} + @{indent__s})"); } + +// +// Form Field Tooltip +// --------------------------------------------- + +.abs-field-tooltip { + &:extend(.abs-add-box-sizing all); + position: relative; + input { + .css(margin-right, @indent__s); + width: calc(~"100% - (@{checkout-tooltip-icon__font-size} + @{indent__s} + @{indent__xs})"); + &:focus { + + .field-tooltip { + .field-tooltip-action { + &:before { + .css(color, @checkout-tooltip-icon__hover__color); + } + } + .field-tooltip-content { + display: block; + } + } + } + } +} + +// +// Checkout Tooltip Content (position: top) +// --------------------------------------------- + +@abs-checkout-tooltip-content-position-top: { + .css(right, @checkout-tooltip-content-mobile__right); + .css(top, @checkout-tooltip-content-mobile__top); + left: auto; + + &:before, + &:after { + .arrow( + @_position: top, + @_size: @checkout-tooltip-icon-arrow__font-size, + @_color: @checkout-tooltip-content__background-color + ); + .css(margin-top, @checkout-tooltip-icon-arrow__left); + .css(right, @indent__s); + left: auto; + top: 0%; + } + &:before { + .css(border-bottom-color, @checkout-tooltip-content__border-color); + } + &:after { + .css(border-bottom-color, @checkout-tooltip-content__background-color); + top: 1px; + } +}; + +.abs-checkout-tooltip-content-position-top { + @abs-checkout-tooltip-content-position-top(); +} + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = (@screen__m + 1)) { + .abs-checkout-tooltip-content-position-top-mobile { + @abs-checkout-tooltip-content-position-top(); + } +} + +// +// Checkout title +// --------------------------------------------- + +.abs-checkout-title { + .css(border-bottom, @checkout-step-title__border); + .css(padding-bottom, @checkout-step-title__padding); + .typography( + @_font-size: @checkout-step-title__font-size, + @_font-weight: @checkout-step-title__font-weight, + @_font-family: false, + @_font-style: false, + @_line-height: false + ); +} + +// +// Shopping cart sidebar and checkout sidebar totals +// --------------------------------------------- + +.abs-sidebar-totals { + .mark { + font-weight: @font-weight__regular; + padding-left: 4px; + strong { + font-weight: @font-weight__regular; + } + } + .amount { + padding-right: 4px; + text-align: right; + strong { + font-weight: @font-weight__regular; + } + } + .grand { + .mark, + .amount { + padding-top: @indent__base; + } + .amount { + padding-right: 4px; + text-align: right; + strong { + font-weight: @font-weight__bold; + } + } + } + .msrp { + margin-bottom: @indent__s; + } + .totals-tax { + &-summary { + .mark, + .amount { + .css(border-top, @border-width__base solid @border-color__base); + .css(border-bottom, @border-width__base solid @border-color__base); + cursor: pointer; + } + .amount .price { + position: relative; + padding-right: @indent__m; + .icon-font( + @icon-down, + @_icon-font-size: 30px, + @_icon-font-text-hide: true, + @_icon-font-position: after, + @_icon-font-display: block + ); + &:after { + position: absolute; + right: -5px; + top: -12px; + } + } + &.expanded { + .mark, + .amount { + border-bottom: 0; + } + .amount .price { + .icon-font-symbol( + @_icon-font-content: @icon-up, + @_icon-font-position: after + ); + } + } + } + &-details { + display: none; + .css(border-bottom, @border-width__base solid @border-color__base); + &.shown { + display: table-row; + } + } + } + .table-caption { + &:extend(.abs-no-display all); + } +} diff --git a/app/design/frontend/Magento/blank/web/css/source/_loaders.less b/app/design/frontend/Magento/blank/web/css/source/_loaders.less index 0c608a402d54782d412ab447990f01e045c00e73..576c7b2ca933ec7e365f24e50e12163c6819dfe5 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_loaders.less +++ b/app/design/frontend/Magento/blank/web/css/source/_loaders.less @@ -9,25 +9,34 @@ & when (@media-common = true) { -.load.indicator { - .loader(); - position: absolute; - > span { - display: none; + .load.indicator { + .loader(); + position: absolute; + > span { + display: none; + } } -} -.loading-mask { - .loading-mask(); - background: rgba(255, 255, 255, .5); - .loader { - > img { - .loading-mask(); + .loading-mask { + .loading-mask(); + background: rgba(255, 255, 255, .5); + .loader { + > img { + .loading-mask(); + } + > p { + display: none; + } } - > p { - display: none; + } + + body { + > .loading-mask { + z-index: @loader-overlay__z-index; } } -} + ._block-content-loading { + position: relative; + } } diff --git a/app/design/frontend/Magento/blank/web/css/source/_navigation.less b/app/design/frontend/Magento/blank/web/css/source/_navigation.less index c16516b0e20bd4069c4f9ee32df098ffb00ac623..f1809aeafb167fec419655d62d4f7969d68b8485 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_navigation.less +++ b/app/design/frontend/Magento/blank/web/css/source/_navigation.less @@ -149,7 +149,7 @@ height: 100%; width: 100%; .page-wrapper { - height:100%; + height: 100%; overflow: hidden; position: relative; left: 0; diff --git a/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less new file mode 100644 index 0000000000000000000000000000000000000000..e4b01ecd0df6e5d9a9c0c10e275d6ccc5098efa1 --- /dev/null +++ b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less @@ -0,0 +1,166 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Components -> Modals +// _____________________________________________ + +// +// Variables +// --------------------------------------------- + +@modal-title__color: @text__color; +@modal-title__border: 1px solid @color-gray-light5; + +@modal-popup-title__font-size: 26px; +@modal-popup-title-mobile__font-size: @font-size__base; +@modal-popup-breakpoint-screen__m: @screen__m + 1; + +@modal-slide__first__indent-left: 44px; +@modal-slide-mobile__background-color: @color-gray-light01; +@modal-overlay__background-color: fade(@color-gray20, 55%); + +@modal-action-close__color: @primary__color; +@modal-action-close__font-size: 32px; +@modal-action-close__hover__color: darken(@primary__color, 10%); + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .modal-custom, + .modal-popup, + .modal-slide { + .action-close { + .button-reset(); + .button-icon( + @icon-remove, + @_icon-font-color: @minicart-icons-color, + @_icon-font-size: @modal-action-close__font-size, + @_icon-font-line-height: @modal-action-close__font-size, + @_icon-font-text-hide: true + ); + position: absolute; + right: 0; + top: 0; + &:hover { + &:before { + color: @modal-action-close__hover__color; + } + } + } + } + .modal-custom { + .action-close { + .css(margin, @indent__m); + } + } + .modal-popup { + .modal-title { + .css(border-bottom, @modal-title__border); + .css(font-weight, @font-weight__light); + .css(padding-bottom, @indent__s); + font-size: @modal-popup-title__font-size; + margin-bottom: 0; + min-height: 1em; + word-wrap: break-word; + } + .action-close { + padding: @modal-popup__padding; + } + } + + .modal-slide { + .action-close { + padding: @modal-slide-header__padding-vertical @modal-slide__padding; + } + .page-main-actions { + margin-top: @modal-slide-header__padding-vertical; + margin-bottom: @modal-slide-header__padding-vertical - (@indent__l/2); + } + } + + .modals-overlay { + .css(background-color, @modal-overlay__background-color); + bottom: 0; + left: 0; + position: fixed; + right: 0; + top: 0; + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @modal-popup-breakpoint-screen__m) { + .modal-popup { + &.modal-slide { + .modal-inner-wrap[class] { + .css(background-color, @modal-slide-mobile__background-color); + } + &._inner-scroll { + &._show { + -webkit-overflow-scrolling: touch; + overflow-y: auto; + } + .modal-inner-wrap { + height: auto; + min-height: 100%; + } + } + } + .modal-title { + .css(font-size, @modal-popup-title-mobile__font-size); + .css(font-weight, @font-weight__bold); + } + } + .custom-slide { + .abs-modal(); + .abs-modal-slide(); + &._show { + -webkit-overflow-scrolling: touch; + overflow-y: auto; + overflow-x: hidden; + } + .modal-inner-wrap { + .css(background-color, @modal-slide-mobile__background-color); + box-sizing: border-box; + height: auto; + min-height: 100%; + } + } + body._has-modal-custom { + height: 100vh; + overflow: hidden; + width: 100vw; + .modal-custom-overlay { + .css(background-color, @modal-overlay__background-color); + height: 100vh; + left: 0; + position: fixed; + top: 0; + width: 100vw; + z-index: @overlay__z-index; + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @modal-popup-breakpoint-screen__m) { + .modal-popup { + &.modal-slide { + .modal-footer { + .css(border-top, @modal-title__border); + text-align: right; + } + } + } +} diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less index 9b111f1353784f0f84d6b39f63bd79fc1d246df1..85932830410a8ee3ef47bc3eabf105116270a9cc 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less @@ -5,647 +5,4 @@ @import 'module/_cart.less'; @import 'module/_minicart.less'; - -@opc-margin-left: 10%; - -// -// Common -// _____________________________________________ - -& when (@media-common = true) { - - // - // One Page Checkout - // --------------------------------------------- - - .opc-wrapper:extend(.abs-add-box-sizing all) { - .field select { - max-width: none; - } - > .opc:extend(.abs-reset-list all) { - } - .section { - &.allow { - .step-title { - cursor: pointer; - .icon-font( - @icon-edit, - @_icon-font-size: 20px, - @_icon-font-display: block, - @_icon-font-position: after - ); - &:after { - position: absolute; - right: 18px; - top: 12px; - } - } - &.active { - .step-title { - cursor: default; - } - .step-title:after { - display: none; - } - } - } - .step-content { - display: none; - } - &.active { - .step-title { - .css(color, @primary__color); - } - .step-content { - display: block; - } - } - } - .step { - &-title { - .css(background, @sidebar__background-color); - .css(color, lighten(@primary__color, 40%)); - margin-bottom: 2px; - padding: 13px @indent__m; - position: relative; - h2 { - .font-size(18); - font-weight: @font-weight__semibold; - margin: 0; - } - .number { - display: none; - } - } - - &-content { - padding: 35px @indent__m 80px; - position: relative; - .addresses .control { - margin: @indent__base 0 @indent__l; - } - .fieldset { - margin-bottom: 0; - &.login { - .form-hasrequired(bottom); - &:after { - margin-top: 35px; - text-align: center; - } - } - .legend.payments-title:extend(.abs-visually-hidden all) { - } - } - .methods-shipping { - .item-content { - .fieldset { - > .legend:extend(.abs-visually-hidden all) { - } - > .legend + br:extend(.abs-no-display all) { - } - > .field { - margin-bottom: 15px; - &:before { - display: none; - } - .control { - display: inline-block; - } - } - } - } - } - .form { - .form-hasrequired(bottom); - &:after { - text-align: center; - } - > .choice { - margin-top: @form-field__vertical-indent; - } - } - .form:not(.login), - .order-review { - .action.primary:extend(.abs-button-l all) { - } - } - .actions { - margin-top: @indent__xl; - } - .field.street { - .field.additional { - .label:extend(.abs-visually-hidden all) { - } - } - } - } - - .fieldset > .field:last-of-type { - margin-bottom: 0; - } - } - - // - // Customer login - // --------------------------------------------- - - .login-wrapper { - .block { - .block-title { - margin-bottom: @indent__l; - strong { - .font-size(22); - font-weight: @font-weight__light; - margin: 0; - } - } - .fieldset.guest { - margin-top: @indent__base; - } - .field { - &.choice { - margin-bottom: @indent__s; - } - &.note { - margin-bottom: @indent__l; - } - } - } - } - - .opc-payment-additional { - margin: 0 0 @indent__s 15px; - + .opc-payment { - margin: @indent__xl 0 0; - } - } - - .action.primary.checkout { - margin: 0 0 @indent__base; - } - - .hidden:extend(.abs-no-display all) { - } - - .actions-toolbar { - margin: @indent__xl 0 0; - } - - .field { - &.month { - padding-right: @indent__s; - .control { - position: relative; - &:after { - color: @primary__color__light; - content: '/'; - position: absolute; - right: -9px; - top: @indent__xs; - } - } - } - &.cvv { - width: 30%; - .control { - position: relative; - } - .note { - position: absolute; - right: -23px; - top: 0; - &:before { - display: none; - } - > a { - .icon-font( - @_icon-font-content: @icon-help, - @_icon-font-size: 16px, - @_icon-font-color: @primary__color__light, - @_icon-font-color-hover: @primary__color, - @_icon-font-text-hide: true - ); - } - } - } - } - } - - // - // Shipping methods - // --------------------------------------------- - - .methods-shipping { - .item-title:extend(.abs-methods-shipping-title all) { - } - .item-content:extend(.abs-adjustment-incl-excl-tax all) { - margin: 0 0 35px; - .field { - margin-bottom: 15px; - .price { - font-weight: @font-weight__bold; - } - &.choice { - .control { - float: left; - } - .label { - display: block; - overflow: hidden; - } - } - } - } - .price.box { - > .price { - display: block; - } - .regular .price, - .price .price { - font-weight: @font-weight__bold; - } - } - .price-box { - margin-bottom: @indent__xs; - margin-left: @indent__base; - margin-top: @indent__s; - } - } - - // - // Payment methods - // --------------------------------------------- - - .methods-payment { - border-bottom: @border-width__base solid @border-color__base; - .item-title { - border-top: @border-width__base solid @border-color__base; - font-weight: @font-weight__regular; - margin: 0; - padding: 16px 15px 15px; - } - .item-content { - margin: 0; - > .fieldset { - padding: 0 @indent__s @indent__xl; - &.redirect { - margin: @indent__s 0 @indent__l 37px; - padding: 0; - width: 80%; - } - } - } - img { - margin-right: @indent__xs; - vertical-align: middle; - } - } - - // - // Order review - // --------------------------------------------- - .table-order-review:extend(.abs-product-options-list all) { - thead tr:first-child th { - padding-top: 0; - } - .col { - &.price, - &.qty { - text-align: center; - white-space: nowrap; - } - &.price:extend(.abs-incl-excl-tax all), - &.subtotal:extend(.abs-incl-excl-tax all) { - } - } - .item-options:extend(.abs-add-clearfix all) { - margin: @indent__base 0 0; - .price { - font-weight: @font-weight__bold; - } - } - .product-item-name:extend(.abs-checkout-product-name all) { - } - .cart-price:extend(.abs-checkout-cart-price all) { - } - .grand.totals { - .font-size(16); - th, - td { - padding: 0 @indent__s; - } - } - } - - .cart-tax-info + .cart-tax-total, - .order-details-items .table-wrapper .cart-tax-info + .cart-tax-total { - display: block; - } - - // - // Checkout Progress - // --------------------------------------------- - - .opc-block-progress-wrapper { - margin-bottom: @indent__l; - margin-top: @indent__base; - } - - .opc-block-progress:extend(.abs-add-box-sizing all) { - display: none; - &.order-review-step { - display: block; - } - > .title { - .css(background, @sidebar__background-color); - .font-size(18); - font-weight: @font-weight__light; - margin: 0; - padding: @indent__s 15px; - strong { - font-weight: @font-weight__regular; - } - } - > .content { - .css(background, @sidebar__background-color); - padding: 0 15px; - .items { - margin: 0; - } - .item-title { - border-top: @border-width__base solid @border-color__base; - display: none; - margin: 0; - padding: 15px 0 7px; - &.complete { - display: block; - } - span { - .font-size(16); - font-weight: @font-weight__semibold; - } - } - .item-content { - display: none; - margin: 0; - overflow: hidden; - padding: 0 0 15px; - &.complete { - display: block; - } - } - .action { - font-weight: @font-weight__regular; - } - .data.table { - font-size: @font-size__s; - } - } - .payment-method { - > .title { - font-weight: @font-weight__light; - } - > .content { - margin: 0 0 @indent__s; - &:last-child { - margin-bottom: 0; - } - } - .items-cards { - margin: 0; - > .content { - margin: 0; - } - } - .data.table { - th { - padding: @indent__xs @indent__s @indent__xs 0; - } - td { - padding: @indent__xs 0; - } - } - } - } - - // - // Checkout Success - // --------------------------------------------- - - .checkout-onepage-success { - .page-title-wrapper { - .print:extend(.abs-no-display all) { - } - } - } - - .checkout-success { - .actions-toolbar { - margin-top: 50px; - } - } - - .checkout-onepage-index { - .nav-toggle:extend(.abs-no-display all) { - } - .logo { - margin-left: 0; - } - } -} - -// -// Mobile -// _____________________________________________ - -.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { - .table-wrapper.order-review-wrapper:extend(.abs-no-border-top all) { - .table.table-order-review:extend(.abs-checkout-order-review all) { - tbody tr { - td { - &:not(:last-child) { - border: none; - } - } - &:first-child td:first-child { - padding-top: 0; - } - } - } - - .table.table-order-review:not(.totals):not(.cart):not(.table-comparison) tbody > tr > td:last-child { - border-bottom: none; - border-top: none; - } - } -} - -// -// Desktop -// _____________________________________________ - -.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) { - .checkout-onepage-index .column.main:extend(.abs-add-clearfix-desktop-s all) { - } - - .opc-wrapper:extend(.abs-add-box-sizing-desktop-s all) { - .layout-column(2, 2, @layout-column-checkout__width-main); - .step-content:extend(.abs-form-field-column-2-s all) { - .form { - &.shipping.address, - &.billing, - &.methods-shipping { - margin-left: @opc-margin-left; - width: 80%; - } - &:after { - text-align: right; - } - } - - .field { - &.street, - &.choice { - width: 100%; - } - &.street .field.additional { - padding: 0; - width: 100%; - } - } - - .payments, - .order-review { - .field:extend(.abs-form-field-revert-column-1-s all) { - &:nth-last-child(1), - &:nth-last-child(2) { - margin-bottom: @indent__base; - } - &:last-child { - margin: 0; - } - } - } - - .toolbar { - text-align: left; - } - } - - // - // Login or register - // --------------------------------------------- - - .login-wrapper:extend(.abs-add-clearfix-desktop-s all) { - .block:extend(.abs-blocks-2columns-s all) { - margin-bottom: 0; - } - .fieldset { - .field { - padding: 0; - width: 100%; - } - &.login:after { - text-align: left; - } - } - .field.choice:not(.persistent):before { - display: none; - } - } - - .checkout-submit-order .actions-toolbar > .primary { - float: right; - } - } - - // - // Payment methods - // --------------------------------------------- - - .methods-payment .item-content > .fieldset, - .order-review .fieldset { - margin: @indent__s 0 @indent__l @opc-margin-left; - padding: 0; - width: 46%; - .field .field { - &.cvv { - display: inline-block; - width: 30%; - } - &.date { - display: inline-block; - width: 70%; - } - &.month { - padding-right: 12px; - } - &.month, - &.year { - margin-bottom: 0; - } - } - } - - .checkout-success .subtitle .print { - margin-left: @indent__xl; - } - - .table-order-review { - .col.subtotal, - .amount { - text-align: right; - } - .col.item { - width: 70%; - } - .grand.totals { - .font-size(16); - th, - td { - padding: 0 0 @indent__xl; - } - strong { - border-top: @border-width__base solid @border-color__base; - display: block; - padding-top: 11px; - } - .mark { - strong { - margin-left: @indent__s; - padding-right: @indent__s; - } - } - .amount { - strong { - margin-right: @indent__s; - padding-left: @indent__s; - } - } - } - } - - // - // Checkout success - // --------------------------------------------- - - .checkout-onepage-success { - .page-title-wrapper { - .print:extend(.abs-action-print-s all) { - display: inline-block; - .font-size(14); - margin-left: @indent__xl; - } - } - } - - .opc-block-progress-wrapper:extend(.abs-add-box-sizing-desktop-s all) { - .layout-column(2, 1, @layout-column-checkout__width-left); - margin-top: 0; - padding-right: @layout-column-main__sidebar-offset; - } - - .opc-block-progress.active { - display: block; - } -} +@import 'module/_checkout.less'; diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less index 84fe60c7262910782021ee8c38b2d319cc66efc7..9157adac7398e56430135bd4835ffc768cc3d304 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less @@ -13,453 +13,366 @@ & when (@media-common = true) { - // - // Shopping cart - // --------------------------------------------- - - .checkout-cart-index { - .page-main { - padding-left: 0; - padding-right: 0; - } - .page-title-wrapper { - padding-left: @layout__width-xs-indent; - padding-right: @layout__width-xs-indent; - } + // + // Shopping cart + // --------------------------------------------- + + .checkout-cart-index { + .page-main { + padding-left: 0; + padding-right: 0; + } + .page-title-wrapper { + padding-left: @layout__width-xs-indent; + padding-right: @layout__width-xs-indent; + } + } + .cart { + // Cart container + &-container { + .form-cart { + &:extend(.abs-shopping-cart-items all); + } } - .cart { - // Cart container - &-container { - .form-cart { - &:extend(.abs-shopping-cart-items all); - } - } - - // Summary block - &-summary { - &:extend(.abs-add-box-sizing all); - .css(background, @sidebar__background-color); - margin-bottom: 25px; - padding: 1px 0 25px; - > .title { - display: none; - .font-size(24); - font-weight: @font-weight__light; - margin: 12px 0; - } - - .block { - form:not(:last-of-type) { - .fieldset { - margin: 0 0 @indent__m; - } - } - - .price { - font-weight: @font-weight__bold; - } - - .field { - margin: 0 0 16px; - &.note { - display: none; - } - } - - .actions-toolbar { - > .primary { - text-align: left; - .action.primary { - &:extend(.abs-revert-to-action-secondary all); - width: auto; - } - } - } - - .fieldset.estimate { - > .legend, - > .legend + br { - &:extend(.abs-no-display all); - } - } - &:extend(.abs-cart-block all); - .title { - strong { - .font-size(14); - font-weight: @font-weight__semibold; - } - } - .item-options { - margin: 0 0 16px; - .field { - .radio { - float: left; - } - .radio { - + .label { - display: block; - margin: 0; - overflow: hidden; - } - } - } - } - } - - .page-main & { - .block { - margin-bottom: 0; - } - } - - .checkout-methods-items { - &:extend(.abs-reset-list all); - margin: 20px 0 0; - padding: 0 @mobile-cart-padding; - text-align: center; - .action.primary.checkout { - &:extend(.abs-button-l all); - width: 100%; - } - .item { - margin-bottom: 25px; - &:last-child { - margin-bottom: 0; - } - } - } - .message { - padding-left: 20px; - > *:first-child:before { - display: none; - } - } - &:extend(.abs-adjustment-incl-excl-tax all); - } - - // Totals block - &-totals { - border-top: 1px solid @border-color__base; - padding-top: 10px; - tbody, - tfoot { - .mark { - border: 0; - font-weight: @font-weight__regular; - padding: 6px 0; - text-align: left; - } - .amount { - border: 0; - font-weight: @font-weight__regular; - padding: 6px 0 6px 14px; - text-align: right; - } - } - .table-caption { - &:extend(.abs-no-display all); - } - .grand { - th, - td { - padding: 11px 0; - } - .mark { - border-top: 1px solid @border-color__base; - .font-size(16); - padding-right: @indent__s; - strong { - display: inline-block; - font-weight: @font-weight__regular; - padding: 3px 0 0; - } - } - .amount { - border-top: 1px solid @border-color__base; - .font-size(18); - } - } - .msrp { - margin-bottom: @indent__s; - } - tbody tr:last-child td { - padding-bottom: 19px; - } - .totals-tax { - &-summary { - .mark, - .amount { - border-bottom: @border-width__base solid @border-color__base; - border-top: @border-width__base solid @border-color__base; - cursor: pointer; - } - .amount .price { - .icon-font( - @icon-down, - @_icon-font-size: 12px, - @_icon-font-line-height: 12px, - @_icon-font-text-hide: true, - @_icon-font-position: after - ); - padding-right: 20px; - position: relative; - &:after { - position: absolute; - right: 3px; - top: 3px; - } - } - &.expanded { - .mark, - .amount { - border-bottom: 0; - } - .amount .price { - .icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after - ); - } - } - } - &-details { - border-bottom: @border-width__base solid @border-color__base; - display: none; - &.shown { - display: table-row; - } - } - } - .table-wrapper { - margin-bottom: 0; - } + // Summary block + &-summary { + &:extend(.abs-add-box-sizing all); + .css(background, @sidebar__background-color); + margin-bottom: 25px; + padding: 1px 0 25px; + > .title { + display: none; + .font-size(24); + font-weight: @font-weight__light; + margin: 12px 0; + } + + .block { + form:not(:last-of-type) { + .fieldset { + margin: 0 0 @indent__m; + } } - // Products table - &.table-wrapper { - .cart { - thead { - tr th.col { - border-bottom: @border-width__base solid @border-color__base; - padding-bottom: 15px; - padding-top: 24px; - } - } - tbody { - td { - border: 0; - } - } - > .item { - border-bottom: @border-width__base solid @border-color__base; - position: relative; - } - } - .col { - padding-top: 15px; - &.price, - &.subtotal, - &.msrp { - padding: @cart-item-cell-padding-top 11px @indent__s; - text-align: center; - &:extend(.abs-incl-excl-tax all); - } - &.qty { - padding: 20px 11px @indent__s; - text-align: center; - .label { - &:extend(.abs-visually-hidden all); - } - .input-text { - height: 36px; - margin-top: -7px; - text-align: center; - width: 45px; - } - } - > .price { - .css(color, @primary__color__lighter); - .font-size(18); - font-weight: @font-weight__bold; - } - } + .price { + font-weight: @font-weight__bold; + } - .item-actions { - td { - padding-bottom: 0; - padding-left: @mobile-cart-padding; - padding-right: @mobile-cart-padding; - white-space: normal; - } - } - .item { - .col.item { - display: block; - min-height: 75px; - padding: 15px @mobile-cart-padding @indent__s 90px; - position: relative; - } - } + .field { + margin: 0 0 16px; + &.note { + display: none; + } + } - .actions-toolbar { - &:extend(.abs-add-clearfix all); - min-height: 20px; - padding-bottom: 15px; - position: relative; - > .action-edit, - > .action-delete { - position: absolute; - right: 16px; - top: 0; - .icon-font( - @icon-edit, - @_icon-font-size: 18px, - @_icon-font-line-height: 20px, - @_icon-font-text-hide: true, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @primary__color, - @_icon-font-color-active: @minicart-icons-color - ); - } - > .action-delete { - right: 0; - .icon-font-symbol( - @_icon-font-content: @icon-trash - ); - } - } - .action { - margin-right: @indent__m; - &:last-child { - margin-right: 0; - } - &.help.map { - &:extend(.abs-action-button-as-link all); - font-weight: @font-weight__regular; - } + .actions-toolbar { + > .primary { + text-align: left; + .action.primary { + &:extend(.abs-revert-to-action-secondary all); + width: auto; } + } + } - .product { - &-item-photo { - display: block; - left: @mobile-cart-padding; - max-width: 65px; - padding: 0; - position: absolute; - top: 15px; - width: 100%; - } - &-item-name { - display: block; - .font-size(18); - margin: -3px 0 @indent__xs; - } - } - .gift-registry-name-label { - &:after { - content: ':'; - } + .fieldset.estimate { + > .legend, + > .legend + br { + &:extend(.abs-no-display all); + } + } + &:extend(.abs-cart-block all); + .title { + strong { + .font-size(14); + font-weight: @font-weight__semibold; + } + } + .item-options { + margin: 0 0 16px; + .field { + .radio { + float: left; + } + .radio { + + .label { + display: block; + margin: 0; + overflow: hidden; + } } + } + } + } - // Product options - .item-options { - margin-bottom: 0; - &:extend(.abs-product-options-list all); - &:extend(.abs-add-clearfix all); - } + .page-main & { + .block { + margin-bottom: 0; + } + } + + .checkout-methods-items { + &:extend(.abs-reset-list all); + margin: 20px 0 0; + padding: 0 @mobile-cart-padding; + text-align: center; + .action.primary.checkout { + &:extend(.abs-button-l all); + width: 100%; + } + .item { + margin-bottom: 25px; + &:last-child { + margin-bottom: 0; + } + } + } - .product-item-name + .item-options { - margin-top: @indent__base; - } + .message { + padding-left: 20px; + > *:first-child:before { + display: none; + } + } + &:extend(.abs-adjustment-incl-excl-tax all); + } - .cart-tax-total { - &:extend(.abs-tax-total all); - &-expanded { - &:extend(.abs-tax-total-expanded all); - } - } - .product-image-wrapper { - &:extend(.abs-reset-image-wrapper all); - } - .action.configure { - display: inline-block; - margin: @indent__s 0 0; - } - .item .message { - margin-top: @indent__base; - } + // Totals block + &-totals { + &:extend(.abs-sidebar-totals all); + tbody, + tfoot { + .mark { + text-align: left; } + } + } - // Discount - &-discount { + // Products table + &.table-wrapper { + .cart { + thead { + tr th.col { border-bottom: @border-width__base solid @border-color__base; - clear: left; - .block { - &:extend(.abs-cart-block all); - > .title { - strong { - color: @color-blue1; - font-weight: @font-weight__regular; - } - } - } - .fieldset > .field > .label { - display: none; - } - .actions-toolbar .primary { - .action { - &.primary, - &.cancel { - &:extend(.abs-revert-to-action-secondary all); - border-bottom-left-radius: 0; - border-top-left-radius: 0; - } - } - } - .action.check { - &:extend(.abs-action-button-as-link all); - font-weight: @font-weight__regular; - } - .fieldset { - display: table; - width: 100%; - } - .field { - display: table-cell; - } - .actions-toolbar { - display: table-cell; - vertical-align: top; - width: 1%; - .action { - &.primary, - &.cancel { - border-bottom-left-radius: 0; - border-top-left-radius: 0; - margin: 0 0 0 -1px; - white-space: nowrap; - width: auto; - } - } - .secondary { - bottom: 5px; - left: @mobile-cart-padding; - position: absolute; - } - } + padding-bottom: 15px; + padding-top: 24px; + } } - - // Empty cart - &-empty { - padding-left: @layout__width-xs-indent; - padding-right: @layout__width-xs-indent; + tbody { + td { + border: 0; + } + } + > .item { + border-bottom: @border-width__base solid @border-color__base; + position: relative; + } + } + .col { + padding-top: 15px; + &.price, + &.subtotal, + &.msrp { + padding: @cart-item-cell-padding-top 11px @indent__s; + text-align: center; + &:extend(.abs-incl-excl-tax all); + } + &.qty { + padding: 20px 11px @indent__s; + text-align: center; + .label { + &:extend(.abs-visually-hidden all); + } + .input-text { + height: 36px; + margin-top: -7px; + text-align: center; + width: 45px; + } + } + > .price { + .css(color, @primary__color__lighter); + .font-size(18); + font-weight: @font-weight__bold; + } + } + + .item-actions { + td { + padding-bottom: 0; + padding-left: @mobile-cart-padding; + padding-right: @mobile-cart-padding; + white-space: normal; + } + } + .item { + .col.item { + display: block; + min-height: 75px; + padding: 15px @mobile-cart-padding @indent__s 90px; + position: relative; + } + } + + .actions-toolbar { + &:extend(.abs-add-clearfix all); + min-height: 20px; + padding-bottom: 15px; + position: relative; + > .action-edit, + > .action-delete { + position: absolute; + right: 16px; + top: 0; + .icon-font( + @icon-edit, + @_icon-font-size: 18px, + @_icon-font-line-height: 20px, + @_icon-font-text-hide: true, + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @primary__color, + @_icon-font-color-active: @minicart-icons-color + ); + } + > .action-delete { + right: 0; + .icon-font-symbol( + @_icon-font-content: @icon-trash + ); + } + } + .action { + margin-right: @indent__m; + &:last-child { + margin-right: 0; + } + &.help.map { + &:extend(.abs-action-button-as-link all); + font-weight: @font-weight__regular; + } + } + + .product { + &-item-photo { + display: block; + left: @mobile-cart-padding; + max-width: 65px; + padding: 0; + position: absolute; + top: 15px; + width: 100%; } + &-item-name { + display: block; + .font-size(18); + margin: -3px 0 @indent__xs; + } + } + .gift-registry-name-label { + &:after { + content: ':'; + } + } + + // Product options + .item-options { + margin-bottom: 0; + &:extend(.abs-product-options-list all); + &:extend(.abs-add-clearfix all); + } + + .product-item-name + .item-options { + margin-top: @indent__base; + } + + .cart-tax-total { + &:extend(.abs-tax-total all); + &-expanded { + &:extend(.abs-tax-total-expanded all); + } + } + .product-image-wrapper { + &:extend(.abs-reset-image-wrapper all); + } + .action.configure { + display: inline-block; + margin: @indent__s 0 0; + } + .item .message { + margin-top: @indent__base; + } + } - .cart-tax-info + .cart-tax-total { - display: block; + // Discount + &-discount { + border-bottom: @border-width__base solid @border-color__base; + clear: left; + .block { + &:extend(.abs-cart-block all); + > .title { + strong { + color: @color-blue1; + font-weight: @font-weight__regular; + } } + } + .fieldset > .field > .label { + display: none; + } + .actions-toolbar .primary { + .action { + &.primary, + &.cancel { + &:extend(.abs-revert-to-action-secondary all); + border-bottom-left-radius: 0; + border-top-left-radius: 0; + } + } + } + .action.check { + &:extend(.abs-action-button-as-link all); + font-weight: @font-weight__regular; + } + .fieldset { + display: table; + width: 100%; + } + .field { + display: table-cell; + } + .actions-toolbar { + display: table-cell; + vertical-align: top; + width: 1%; + .action { + &.primary, + &.cancel { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + margin: 0 0 0 -1px; + white-space: nowrap; + width: auto; + } + } + .secondary { + bottom: 5px; + left: @mobile-cart-padding; + position: absolute; + } + } } + + // Empty cart + &-empty { + padding-left: @layout__width-xs-indent; + padding-right: @layout__width-xs-indent; + } + + .cart-tax-info + .cart-tax-total { + display: block; + } + } } // @@ -467,110 +380,97 @@ // _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { - .cart { - &-totals { - .table.totals { - th { - &:extend(.abs-col-no-prefix all); - display: table-cell; - } - td { - &:extend(.abs-col-no-prefix all); - display: table-cell; - } - tbody tr:not(:last-child) td { - &:extend(.abs-no-border-bottom-top all); - } - .amount { - text-align: right; - } - } - } - .table.items { - .col.item, - .item-actions td { - &:extend(.abs-col-no-prefix all); - } - .col.qty { - text-align: center; - } - tbody > tr > td:last-child { - &:extend(.abs-no-border-bottom-top all); - } - } + .cart { + &-totals { + .totals { + &:extend(.abs-sidebar-totals-mobile all); + } + } + .table.items { + .col.item, + .item-actions td { + &:extend(.abs-col-no-prefix all); + } + .col.qty { + text-align: center; + } + tbody > tr > td:last-child { + &:extend(.abs-no-border-bottom-top all); + } } + } } .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { - .cart { - // Cart container - &-container { - .form-cart { - .actions.main { - text-align: center; - } - } + .cart { + // Cart container + &-container { + .form-cart { + .actions.main { + text-align: center; } + } + } - &-discount { - border-bottom: @border-width__base solid @border-color__base; - } + &-discount { + border-bottom: @border-width__base solid @border-color__base; + } - &.table-wrapper { - border-top: @border-width__base solid @border-color__base; - thead { - .col { - &.item, - &.qty, - &.price, - &.subtotal, - &.msrp { - display: none; - } - } - } - .col { - &.qty, - &.price, - &.subtotal, - &.msrp { - box-sizing: border-box; - display: block; - float: left; - white-space: nowrap; - width: 33%; - &:before { - content: attr(data-th); - display: block; - font-weight: @font-weight__semibold; - padding-bottom: 10px; - } - } - &.msrp { - white-space: normal; - } - } - .item .col.item { - padding-bottom: 0; - } - tbody > tr > td:last-child { - border: 0; - } + &.table-wrapper { + border-top: @border-width__base solid @border-color__base; + thead { + .col { + &.item, + &.qty, + &.price, + &.subtotal, + &.msrp { + display: none; + } + } + } + .col { + &.qty, + &.price, + &.subtotal, + &.msrp { + box-sizing: border-box; + display: block; + float: left; + white-space: nowrap; + width: 33%; + &:before { + content: attr(data-th); + display: block; + font-weight: @font-weight__semibold; + padding-bottom: 10px; + } } + &.msrp { + white-space: normal; + } + } + .item .col.item { + padding-bottom: 0; + } + tbody > tr > td:last-child { + border: 0; + } + } - &-totals { - padding-left: @mobile-cart-padding; - padding-right: @mobile-cart-padding; - .table-wrapper { - border-top: 0; - } - .totals { - tbody > tr:not(:last-child) > td:last-child { - border: 0; - } - } + &-totals { + padding-left: @mobile-cart-padding; + padding-right: @mobile-cart-padding; + .table-wrapper { + border-top: 0; + } + .totals { + tbody > tr:not(:last-child) > td:last-child { + border: 0; } + } } + } } @@ -579,14 +479,14 @@ // _____________________________________________ & when (@media-common = true) { - // Cross sell - .block.crosssell { - margin-top: 70px; - .css(padding, 0 @mobile-cart-padding); - .product-item-info { - width: 200px; - } + // Cross sell + .block.crosssell { + margin-top: 70px; + .css(padding, 0 @mobile-cart-padding); + .product-item-info { + width: 200px; } + } } // @@ -594,150 +494,150 @@ // _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { - .checkout-cart-index { - .page-main { - padding-left: @layout__width-xs-indent; - padding-right: @layout__width-xs-indent; - } - .page-title-wrapper { - &:extend(.abs-revert-side-paddings all); - } + .checkout-cart-index { + .page-main { + padding-left: @layout__width-xs-indent; + padding-right: @layout__width-xs-indent; } - .cart { - // Cart container - &-container { - &:extend(.abs-add-clearfix-desktop all); - .form-cart { - &:extend(.abs-shopping-cart-items-desktop all); - .actions.main { - text-align: right; - } - } - .widget { - float: left; - } + .page-title-wrapper { + &:extend(.abs-revert-side-paddings all); + } + } + .cart { + // Cart container + &-container { + &:extend(.abs-add-clearfix-desktop all); + .form-cart { + &:extend(.abs-shopping-cart-items-desktop all); + .actions.main { + text-align: right; } + } + .widget { + float: left; + } + } - // Summary block - &-summary { - .layout-column(2, 2, @layout-column-checkout__width-left); - padding: 1px @indent__base @indent__m; - position: relative; - > .title { - display: block; - } - .fieldset .actions-toolbar { - margin-left: 0; - > .secondary { - float: none; - } - } - .block { - > .title { - padding-left: 0; - &:after { - right: 3px; - } - } - .content { - &:extend(.abs-revert-side-paddings all); - } - .fieldset { - .field { - .form-field-type-revert(@_type: block); - margin: 0 0 @indent__s; - } - } - } - .checkout-methods-items { - padding: 0; - } + // Summary block + &-summary { + .layout-column(2, 2, @layout-column-checkout__width-left); + padding: 1px @indent__base @indent__m; + position: relative; + > .title { + display: block; + } + .fieldset .actions-toolbar { + margin-left: 0; + > .secondary { + float: none; } + } + .block { + > .title { + padding-left: 0; + &:after { + right: 3px; + } + } + .content { + &:extend(.abs-revert-side-paddings all); + } + .fieldset { + .field { + .form-field-type-revert(@_type: block); + margin: 0 0 @indent__s; + } + } + } + .checkout-methods-items { + padding: 0; + } + } - // Products table - &.table-wrapper { - tbody td { - padding-top: @cart-item-cell-padding-top; - } - - .item { - .col.item { - padding: @cart-item-cell-padding-top 8px 20px 0; - } - } - - .item-actions td { - padding: 0; - } + // Products table + &.table-wrapper { + tbody td { + padding-top: @cart-item-cell-padding-top; + } - .product { - &-item-photo { - display: table-cell; - max-width: 100%; - padding-right: 20px; - position: static; - vertical-align: top; - width: 1%; - } - &-item-details { - padding-bottom: 35px; - } - &-item-details { - display: table-cell; - vertical-align: top; - white-space: normal; - width: 99%; - } - } + .item { + .col.item { + padding: @cart-item-cell-padding-top 8px 20px 0; } - - // Discount - &-discount { - border: 0; - .layout-column(2, 1, @layout-column-checkout__width-main); - &:extend(.abs-add-box-sizing-desktop all); - padding-right: 4%; - .block { - &:extend(.abs-blocks-2columns all); - width: 48%; - > .title { - border: 0; - cursor: default; - padding: 0 0 10px; - .column.main & strong { - .font-size(16); - } - &:after { - display: none; - } - } - .content { - display: block !important; // Need for overwriting collapsible widget - padding: 0; - } - } - .actions-toolbar { - .secondary { - bottom: -30px; - left: 0; - position: absolute; - } - } + } + + .item-actions td { + padding: 0; + } + + .product { + &-item-photo { + display: table-cell; + max-width: 100%; + padding-right: 20px; + position: static; + vertical-align: top; + width: 1%; } - - // Empty cart - &-empty { - &:extend(.abs-revert-side-paddings all); + &-item-details { + padding-bottom: 35px; } + &-item-details { + display: table-cell; + vertical-align: top; + white-space: normal; + width: 99%; + } + } } - // Cross sell - .block.crosssell { - .layout-column(2, 1, @layout-column-checkout__width-main); - &:extend(.abs-add-box-sizing-desktop all); - padding: 0 4% 0 0; - .products-grid .product-item { - width: 100%/4; + // Discount + &-discount { + border: 0; + .layout-column(2, 1, @layout-column-checkout__width-main); + &:extend(.abs-add-box-sizing-desktop all); + padding-right: 4%; + .block { + &:extend(.abs-blocks-2columns all); + width: 48%; + > .title { + border: 0; + cursor: default; + padding: 0 0 10px; + .column.main & strong { + .font-size(16); + } + &:after { + display: none; + } + } + .content { + display: block !important; // Need for overwriting collapsible widget + padding: 0; } + } + .actions-toolbar { + .secondary { + bottom: -30px; + left: 0; + position: absolute; + } + } + } + + // Empty cart + &-empty { + &:extend(.abs-revert-side-paddings all); + } + } + + // Cross sell + .block.crosssell { + .layout-column(2, 1, @layout-column-checkout__width-main); + &:extend(.abs-add-box-sizing-desktop all); + padding: 0 4% 0 0; + .products-grid .product-item { + width: 100%/4; } + } } diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less index ddeb77db7fdfda33523a0f4a167f393ece533d43..86564ca26cb6aa19691789f4b16a2917b8f84744 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less @@ -5,330 +5,332 @@ // // Variables -// --------------------------------------------- +// _____________________________________________ @minicart__border-color: @color-gray80; @minicart__padding-horizontal: @indent__base; // // Common -// --------------------------------------------- +// _____________________________________________ & when (@media-common = true) { -// -// Minicart -// --------------------------------------------- + // + // Minicart + // --------------------------------------------- -.block-minicart { - .items-total { - float: left; - margin: 0 @indent__s; - .count { - font-weight: @font-weight__bold; + .block-minicart { + .items-total { + float: left; + margin: 0 @indent__s; + .count { + font-weight: @font-weight__bold; + } } - } - .subtotal { - margin: 0 @indent__s; - text-align: right; - .label { - &:extend(.abs-colon all); + .subtotal { + margin: 0 @indent__s; + text-align: right; + .label { + &:extend(.abs-colon all); + } } - } - .amount { - .price-wrapper { - &:first-child { - .price { - font-size: @font-size__l; - font-weight: @font-weight__bold; + .amount { + .price-wrapper { + &:first-child { + .price { + font-size: @font-size__l; + font-weight: @font-weight__bold; + } } } } - } - .subtitle { - display: none; - } - .subtitle { - &.empty { - display: block; - padding: @indent__l 0 @indent__base; - text-align: center; - font-size: 14px; - } - } - .text { - &.empty { - text-align: center; + .subtitle { + display: none; + &.empty { + display: block; + padding: @indent__l 0 @indent__base; + text-align: center; + font-size: 14px; + } } - } - .block-content { - > .actions { - margin-top: 15px; - > .secondary { + .text { + &.empty { text-align: center; } - > .primary { - margin: 0 @indent__s 15px; - .action { - &.primary { - &:extend(.abs-button-l all); - display: block; - width: 100%; + } + .block-content { + > .actions { + margin-top: 15px; + > .secondary { + text-align: center; + } + > .primary { + margin: 0 @indent__s 15px; + .action { + &.primary { + &:extend(.abs-button-l all); + display: block; + width: 100%; + } } } - } - .paypal-logo { - margin-top: 15px; - text-align: center; + .paypal-logo { + margin-top: 15px; + text-align: center; + } } } + .block-category-link, + .block-product-link, + .block-cms-link, + .block-banners { + margin: 15px 0 0; + text-align: center; + } } - .block-category-link, - .block-product-link, - .block-cms-link, - .block-banners { - margin: 15px 0 0; - text-align: center; - } -} -.minicart-wrapper { - .dropdown( - @_toggle-selector: ~".action.showcart", - @_options-selector: ~".block-minicart", - @_dropdown-toggle-icon-content: @icon-cart, - @_dropdown-toggle-active-icon-content: @icon-cart, - @_dropdown-list-item-padding: false, - @_dropdown-list-item-hover: false, - @_icon-font-position: before, - @_icon-font-size: 22px, - @_icon-font-line-height: 28px, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @minicart-icons-color-hover, - @_icon-font-color-active: @minicart-icons-color - ); - float: right; - .block-minicart { - .css(padding, 25px @minicart__padding-horizontal); - right: 0; - width: 320px; - .block-title { - display: none; - } - &:after { - left: auto; - right: 25px; - } - &:before { - left: auto; - right: 26px; + .minicart-wrapper { + .dropdown( + @_toggle-selector: ~".action.showcart", + @_options-selector: ~".block-minicart", + @_dropdown-toggle-icon-content: @icon-cart, + @_dropdown-toggle-active-icon-content: @icon-cart, + @_dropdown-list-item-padding: false, + @_dropdown-list-item-hover: false, + @_icon-font-position: before, + @_icon-font-size: 22px, + @_icon-font-line-height: 28px, + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @minicart-icons-color-hover, + @_icon-font-color-active: @minicart-icons-color + ); + float: right; + .block-minicart { + .css(padding, 25px @minicart__padding-horizontal); + right: 0; + width: 320px; + .block-title { + display: none; + } + &:after { + left: auto; + right: 25px; + } + &:before { + left: auto; + right: 26px; + } } - } - .product { - .actions { - float: right; - margin: -24px 0 0; - > .primary, - > .secondary { - display: inline; - &:not(:last-child) { - margin-right: 15px; + .product { + .actions { + float: right; + margin: -24px 0 0; + > .primary, + > .secondary { + display: inline; + &:not(:last-child) { + margin-right: 15px; + } } } } - } - .action { - &.close { - width: 40px; - height: 40px; - top: 0; - right: 0; - position: absolute; - .button-reset(); - .button-icon( - @icon-remove, - @_icon-font-color: @minicart-icons-color, - @_icon-font-size: 16px, - @_icon-font-line-height: 16px, - @_icon-font-text-hide: true - ); - } - &.showcart { - .text { - &:extend(.abs-visually-hidden all); + .action { + &.close { + width: 40px; + height: 40px; + top: 0; + right: 0; + position: absolute; + .button-reset(); + .button-icon( + @icon-remove, + @_icon-font-color: @minicart-icons-color, + @_icon-font-size: 16px, + @_icon-font-line-height: 16px, + @_icon-font-text-hide: true + ); } - white-space: nowrap; - .counter.qty { - &.empty { - display: none; + &.showcart { + .text { + &:extend(.abs-visually-hidden all); + } + white-space: nowrap; + .counter.qty { + &.empty { + display: none; + } + .css(background, @active__color); + border-radius: 2px; + .css(color, @page__background-color); + clip: none; + display: inline-block; + height: 24px; + line-height: 24px; + min-width: 18px; + margin: 3px 0 0; + padding: 0 3px; + overflow: hidden; + text-align: center; + white-space: normal; + } + .counter-label { + &:extend(.abs-visually-hidden all); } - .css(background, @active__color); - border-radius: 2px; - .css(color, @page__background-color); - clip: none; - display: inline-block; - height: 24px; - line-height: 24px; - min-width: 18px; - margin: 3px 0 0; - padding: 0 3px; - overflow: hidden; - text-align: center; - white-space: normal; - } - .counter-label { - &:extend(.abs-visually-hidden all); } } + .minicart-widgets { + margin-top: 15px; + } } - .minicart-widgets { - margin-top: 15px; - } -} -.minicart-items-wrapper { - .css(border, 1px solid @minicart__border-color); - .css(margin, 0 -@minicart__padding-horizontal); - border-left: 0; - border-right: 0; - overflow-x: auto; - padding: 15px; -} + .minicart-items-wrapper { + .css(border, 1px solid @minicart__border-color); + .css(margin, 0 -@minicart__padding-horizontal); + border-left: 0; + border-right: 0; + overflow-x: auto; + padding: 15px; + } -.minicart-items { - .list-reset-styles(0, 0); - .item { - &:not(:first-child) { - .css(border-top, 1px solid @minicart__border-color); - } - padding: @indent__base 0; - &:first-child { - padding-top: 0; - } - > .product { - &:extend(.abs-add-clearfix all); + .minicart-items { + .list-reset-styles(0, 0); + .product-item { + &:not(:first-child) { + .css(border-top, 1px solid @minicart__border-color); + } + padding: @indent__base 0; + &:first-child { + padding-top: 0; + } + > .product { + &:extend(.abs-add-clearfix all); + } } - } - .product-image-wrapper { - &:extend(.abs-reset-image-wrapper all); - } - .product-item-pricing { - .label { - display: inline-block; - width: 4.5rem; + .product-image-wrapper { + &:extend(.abs-reset-image-wrapper all); } - } - .price-minicart { - margin-bottom: @indent__xs; - } - .product-item-photo { - float: left; - } - .product-item-name { - font-weight: @font-weight__regular; - margin: 0 0 @indent__s; - a { - .css(color, @link__color); - } - } - .product-item-details { - padding-left: 88px; - .price { - font-weight: @font-weight__bold; + .product-item-pricing { + .label { + display: inline-block; + width: 4.5rem; + } } - .price-including-tax, - .price-excluding-tax { - margin: @indent__xs 0; + .price-minicart { + margin-bottom: @indent__xs; } - .weee[data-label] { - .font-size(11); - .label { - &:extend(.abs-no-display all); + .product-item-name { + font-weight: @font-weight__regular; + margin: 0 0 @indent__s; + a { + .css(color, @link__color); } } - .details-qty { - margin-top: @indent__s; + .product-item-details { + padding-left: 88px; + .price { + font-weight: @font-weight__bold; + } + .price-including-tax, + .price-excluding-tax { + margin: @indent__xs 0; + } + .weee[data-label] { + .font-size(11); + .label { + &:extend(.abs-no-display all); + } + } + .details-qty { + margin-top: @indent__s; + } } - } - .product { - .toggle { - &:extend(.abs-toggling-title all); - &:after { - position: static; - margin: 0 0 0 @indent__xs; - .css(color, @color-gray56); + .product { + > .product-item-photo, + > .product-image-container { + float: left; + } + .toggle { + &:extend(.abs-toggling-title all); + &:after { + position: static; + margin: 0 0 0 @indent__xs; + .css(color, @color-gray56); + } + border: 0; + padding: 0 @indent__xl @indent__xs 0; + } + .active { + > .toggle { + .icon-font-symbol( + @_icon-font-content: @icon-up, + @_icon-font-position: after + ); + } + } + &.pricing { + margin-top: 3px; + } + &.options { + .tooltip.toggle { + .icon-font( + @icon-down, + @_icon-font-size: 12px, + @_icon-font-line-height: 12px, + @_icon-font-text-hide: true, + @_icon-font-margin: -3px 0 0 7px, + @_icon-font-position: after + ); + } + .details { + display: none; + } } - border: 0; - padding: 0 @indent__xl @indent__xs 0; } - .active { - > .toggle { - .icon-font-symbol( - @_icon-font-content: @icon-up, - @_icon-font-position: after - ); + .details-qty, + .price-minicart { + .label { + &:extend(.abs-colon all); } } - &.pricing { - margin-top: 3px; + .item-qty { + width: 40px; + text-align: center; + margin-right: @indent__s; + } + .update-cart-item { + vertical-align: top; + .font-size(11); } - &.options { - .tooltip.toggle { + .action { + &.edit, + &.delete { .icon-font( - @icon-down, - @_icon-font-size: 12px, - @_icon-font-line-height: 12px, + @icon-edit, + @_icon-font-size: 18px, + @_icon-font-line-height: 20px, @_icon-font-text-hide: true, - @_icon-font-margin: -3px 0 0 7px, - @_icon-font-position: after + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @primary__color, + @_icon-font-color-active: @minicart-icons-color ); } - .details { - display: none; + &.delete { + .icon-font-symbol( + @_icon-font-content: @icon-trash + ); } } - } - .details-qty, - .price-minicart { - .label { - &:extend(.abs-colon all); - } - } - .item-qty { - width: 40px; - text-align: center; - margin-right: @indent__s; - } - .update-cart-item { - vertical-align: top; - .font-size(11); - } - .action { - &.edit, - &.delete { - .icon-font( - @icon-edit, - @_icon-font-size: 18px, - @_icon-font-line-height: 20px, - @_icon-font-text-hide: true, - @_icon-font-color: @minicart-icons-color, - @_icon-font-color-hover: @primary__color, - @_icon-font-color-active: @minicart-icons-color - ); - } - &.delete { - .icon-font-symbol( - @_icon-font-content: @icon-trash - ); + .subtitle { + display: none; } } -} } // // Mobile -// --------------------------------------------- +// _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__xs) { .minicart-wrapper .block-minicart { @@ -345,7 +347,7 @@ // // Desktop -// --------------------------------------------- +// _____________________________________________ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .minicart-wrapper { diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less new file mode 100644 index 0000000000000000000000000000000000000000..f8f2ee61ddae6ef52ea6ee2ca6a73c0b2c118cde --- /dev/null +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less @@ -0,0 +1,94 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-wrapper__margin: @indent__base; +@checkout-wrapper__columns: 16; + +@checkout-step-title__border: @border-width__base solid @color-gray80; +@checkout-step-title__font-size: 26px; +@checkout-step-title__font-weight: @font-weight__light; +@checkout-step-title__margin-bottom: 28px; +@checkout-step-title__padding: @indent__s; + +@checkout-step-title-mobile__font-size: 18px; +@checkout-step-title-mobile__margin-bottom: @indent__base; + +@checkout-step-content-mobile__background: @color-gray-light01; +@checkout-step-content-mobile__margin-s: 15px; +@checkout-step-content-mobile__margin: 0 -(@checkout-step-content-mobile__margin-s) @checkout-step-content-mobile__margin-s; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + .checkout-container { + &:extend(.abs-add-clearfix all); + .css(margin, 0 0 @checkout-wrapper__margin); + } + + .opc-wrapper { + .css(margin, 0 0 @checkout-wrapper__margin); + + .opc { + &:extend(.abs-reset-list all); + } + + .step-title { + &:extend(.abs-checkout-title all); + .css(border-bottom, @checkout-step-title__border); + .css(margin, 0 0 @checkout-step-title__margin-bottom); + } + + .step-content { + margin: 0 0 @indent__xl; + } + } + + .checkout-onepage-index { + .nav-sections, + .nav-toggle { + display: none; + } + .logo { + margin-left: 0; + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { + .opc-wrapper { + .step-title { + .css(font-size, @checkout-step-title-mobile__font-size); + .css(margin-bottom, @checkout-step-title-mobile__margin-bottom); + border-bottom: 0; + padding-bottom: 0; + } + .step-content { + .css(margin, 0 0 @checkout-step-content-mobile__margin-s); + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .opc-wrapper { + &:extend(.abs-add-box-sizing-desktop-m all); + .layout-column(2, 1, @checkout-wrapper__columns); + padding-right: @indent__l; + } +} diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less new file mode 100644 index 0000000000000000000000000000000000000000..ccef519f1cbb1cbb51a1937d9a1ee524e74d621b --- /dev/null +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less @@ -0,0 +1,58 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // + // Checkout Estimated Total + // --------------------------------------------- + + .opc-estimated-wrapper { + &:extend(.abs-no-display-desktop all); + &:extend(.abs-add-clearfix all); + .css(background, @checkout-step-content-mobile__background); + .css(border-bottom, @checkout-step-title__border); + .css(border-top, @checkout-step-title__border); + .css(margin, -21px -(@checkout-step-content-mobile__margin-s) @checkout-step-content-mobile__margin-s); + padding: 18px 15px; + + .estimated-block { + .css(font-size, @checkout-step-title-mobile__font-size); + float: left; + font-weight: @font-weight__bold; + + .estimated-label { + display: block; + margin: 0 0 @indent__xs; + } + } + + .minicart-wrapper { + button { + // todo ui: Change .action.showcart to .action-showcart + &.action.showcart { + .button-reset(); + &:before { + .css(color, @primary__color); + } + } + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) { + .opc-estimated-wrapper { + display: none; + } +} diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_modals.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_modals.less new file mode 100644 index 0000000000000000000000000000000000000000..7b2c5a55d6aa4e9000be31b548c098fa17adf33d --- /dev/null +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_modals.less @@ -0,0 +1,90 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-modal-popup__width: 800px; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + .checkout-onepage-index { + .modal-popup { + .field-tooltip { + .field-tooltip-content { + &:extend(.abs-checkout-tooltip-content-position-top all); + } + } + .fieldset { + .field { + .label { + font-weight: @font-weight__regular; + } + } + } + .modal-footer { + .action-hide-popup { + &:extend(.abs-action-button-as-link all); + margin-top: 8px; + } + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) { + .checkout-onepage-index { + .modal-popup { + .modal-footer { + .action-save-address { + width: 100%; + } + .action-hide-popup { + margin-top: @indent__base; + } + } + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .checkout-onepage-index { + .modal-popup { + .form-shipping-address { + .css(max-width, @checkout-shipping-address__max-width); + } + .modal-footer { + .action-save-address { + float: right; + margin: 0 0 0 @indent__base; + } + } + } + } +} + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) { + .checkout-onepage-index { + .modal-popup { + .modal-inner-wrap { + .css(margin-left, -(@checkout-modal-popup__width/2)); + .css(width, @checkout-modal-popup__width); + left: 50%; + } + } + } +} diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_order-summary.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_order-summary.less new file mode 100644 index 0000000000000000000000000000000000000000..b77969dddddadfcd9985ed4fde68e3ef7aa9a5b6 --- /dev/null +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_order-summary.less @@ -0,0 +1,188 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-summary__background-color: @color-white-smoke; +@checkout-summary__padding: 22px @indent__l; + +@checkout-summary-title__margin: @indent__s; +@checkout-summary-mark-value__color: @color-gray60; + +@checkout-summary-items__max-height: 370px; +@checkout-summary-items__padding: 15px; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // + // Order Summary + // --------------------------------------------- + + .opc-block-summary { + .css(background, @checkout-summary__background-color); + .css(margin, 0 0 @checkout-sidebar__margin); + .css(padding, @checkout-summary__padding); + &:extend(.abs-add-box-sizing all); + + > .title { + &:extend(.abs-checkout-title all); + display: block; + } + + // Totals table + .table-totals { + &:extend(.abs-sidebar-totals all); + } + + .mark { + .value { + .css(color, @checkout-summary-mark-value__color); + display: block; + } + } + + .grand.incl { + & + .grand.excl { + .mark, + .amount { + border-top: 0; + .font-size(14); + padding-top: 0; + strong { + font-weight: @font-weight__regular; + } + } + } + } + + .not-calculated { + font-style: italic; + } + + // + // Items list + // --------------------------------------------- + + // Block title + .items-in-cart { + > .title { + border-bottom: @border-width__base solid @border-color__base; + .css(padding, @indent__s @indent__xl @indent__s 0); + cursor: pointer; + .icon-font( + @icon-down, + @_icon-font-size: 12px, + @_icon-font-line-height: 12px, + @_icon-font-text-hide: true, + @_icon-font-margin: 3px 0 0, + @_icon-font-position: after, + @_icon-font-display: block + ); + margin-bottom: 0; + position: relative; + &:after { + position: absolute; + right: 0; + top: @indent__s; + } + strong { + .font-size(18); + font-weight: @font-weight__light; + margin: 0; + } + } + &.active { + > .title { + .icon-font-symbol( + @_icon-font-content: @icon-up, + @_icon-font-position: after + ); + } + } + .product { + position: relative; + } + } + + // Cart items + .minicart-items-wrapper { + .css(margin, 0 -(@checkout-summary-items__padding) 0 0); + .css(max-height, @checkout-summary-items__max-height); + .css(padding, @checkout-summary-items__padding @checkout-summary-items__padding 0 0); + border: 0; + } + .column.main & { + .product-item { + margin: 0; + padding-left: 0; + } + } + .product-item { + .product-item-inner { + display: table; + margin: 0 0 @indent__s; + width: 100%; + } + .product-item-name-block { + display: table-cell; + padding-right: @indent__xs; + text-align: left; + } + .subtotal { + display: table-cell; + text-align: right; + } + .price { + .font-size(16); + font-weight: @font-weight__regular; + } + .price-including-tax { + & + .price-excluding-tax { + .price { + .font-size(10); + } + } + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { + .opc-block-summary { + > .title { + border-bottom: 0; + .css(font-size, @checkout-step-title-mobile__font-size); + .css(margin-bottom, @checkout-step-title-mobile__margin-bottom); + padding-bottom: 0; + } + .totals { + &:extend(.abs-sidebar-totals-mobile all); + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .opc-summary-wrapper { + .modal-header { + .action-close { + display: none; + } + } + } +} diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less new file mode 100644 index 0000000000000000000000000000000000000000..13b59d044d72bef7d86ee8c84ee5979a3745407c --- /dev/null +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less @@ -0,0 +1,181 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-progress-bar__font-size: 18px; +@checkout-progress-bar__font-weight: @font-weight__light; +@checkout-progress-bar__margin: @indent__base; + +@checkout-progress-bar-item__background-color: @color-gray-middle1; +@checkout-progress-bar-item__border-radius: 6px; +@checkout-progress-bar-item__color: @primary__color; +@checkout-progress-bar-item__margin: @indent__s; +@checkout-progress-bar-item__transition: background .3s; +@checkout-progress-bar-item__width: 185px; + +@checkout-progress-bar-item__active__background-color: @color-orange-red1; +@checkout-progress-bar-item__complete__color: @link__color; +@checkout-progress-bar-item__hover__background-color: darken(@checkout-progress-bar-item__background-color, 5%); + +@checkout-progress-bar-item-element__height: @checkout-progress-bar-item-element__width; +@checkout-progress-bar-item-element__width: 38px; + +@checkout-progress-bar-item-element-inner__background-color: @page__background-color; +@checkout-progress-bar-item-element-inner__color: @checkout-progress-bar-item__color; +@checkout-progress-bar-item-element-inner__height: @checkout-progress-bar-item-element-inner__width; +@checkout-progress-bar-item-element-inner__width: @checkout-progress-bar-item-element__width - ( @checkout-progress-bar-item-element-outer-radius__width*2 ); +@checkout-progress-bar-item-element-inner__active__content: @icon-checkmark; + +@checkout-progress-bar-item-element-outer-radius__width: 6px; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // + // Checkout Progress Bar + // --------------------------------------------- + + .opc-progress-bar { + &:extend(.abs-no-display-s all); + &:extend(.abs-reset-list all); + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__s) { + + .opc-progress-bar { + .css(margin, 0 0 @checkout-progress-bar__margin); + counter-reset: i; + font-size: 0; + } + + .opc-progress-bar-item { + .css(margin, 0 0 @checkout-progress-bar-item__margin); + .css(width, @checkout-progress-bar-item__width); + display: inline-block; + position: relative; + text-align: center; + vertical-align: top; + + &:before { // Horizontal line + .css(background, @checkout-progress-bar-item__background-color); + .css(top, @checkout-progress-bar-item-element__width/2); + .css(transition, @checkout-progress-bar-item__transition); + content: ''; + height: 7px; + left: 0; + position: absolute; + width: 100%; + } + + &:first-child { + &:before { + .css(border-radius, @checkout-progress-bar-item__border-radius 0 0 @checkout-progress-bar-item__border-radius); + } + } + + &:last-child { + &:before { + .css(border-radius, 0 @checkout-progress-bar-item__border-radius @checkout-progress-bar-item__border-radius 0); + } + } + + > span { + display: inline-block; + padding-top: 45px; + width: 100%; + word-wrap: break-word; + + .typography( + @_color: @checkout-progress-bar-item__background-color, + @_font-family: false, + @_font-size: @checkout-progress-bar__font-size, + @_font-style: false, + @_font-weight: @checkout-progress-bar__font-weight, + @_line-height: false + ); + + &:before, // Item element + &:after { + .css(background, @checkout-progress-bar-item__background-color); + .css(height, @checkout-progress-bar-item-element__height); + .css(margin-left, -(@checkout-progress-bar-item-element__width/2)); + .css(transition, @checkout-progress-bar-item__transition); + .css(width, @checkout-progress-bar-item-element__width); + border-radius: 50%; + content: ''; + left: 50%; + position: absolute; + top: 0; + } + + &:after { // Item element inner + .css(background, @checkout-progress-bar-item-element-inner__background-color); + .css(height, @checkout-progress-bar-item-element-inner__height); + .css(margin-left, -(@checkout-progress-bar-item-element-inner__width/2)); + .css(top, @checkout-progress-bar-item-element-outer-radius__width); + .css(width, @checkout-progress-bar-item-element-inner__width); + content: counter(i); + counter-increment: i; + .typography( + @_color: @checkout-progress-bar-item-element-inner__color, + @_font-family: false, + @_font-size: @checkout-progress-bar__font-size, + @_font-style: false, + @_font-weight: @font-weight__semibold, + @_line-height: false + ); + } + } + + &._complete { + cursor: pointer; + &:hover { + &:before { + .css(background, @checkout-progress-bar-item__hover__background-color); + } + > span { + &:before { + .css(background, @checkout-progress-bar-item__hover__background-color); + } + } + } + > span { + .css(color, @checkout-progress-bar-item__complete__color); + + &:after { + .css(font-family, @icons__font-name); + .css(content, @checkout-progress-bar-item-element-inner__active__content); + } + } + } + + &._active { + &:before { + background: @checkout-progress-bar-item__active__background-color; + } + > span { + .css(color, @checkout-progress-bar-item__color); + &:before { + .css(background, @checkout-progress-bar-item__active__background-color); + } + &:after { + .css(font-family, @icons__font-name); + .css(content, @checkout-progress-bar-item-element-inner__active__content); + } + } + } + } +} diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less new file mode 100644 index 0000000000000000000000000000000000000000..fb2d200134402a5cc74cf30552da410b542dc21e --- /dev/null +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less @@ -0,0 +1,340 @@ +// /** +// * Copyright © 2015 Magento. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Variables +// _____________________________________________ + +@checkout-shipping-address__max-width: 500px; + +@checkout-shipping-item-icon__background-color: @checkout-shipping-item__active__border-color; +@checkout-shipping-item-icon__color: @color-white; +@checkout-shipping-item-icon__content: @icon-checkmark; + +@checkout-shipping-item__border: 2px solid transparent; +@checkout-shipping-item__line-height: 30px; +@checkout-shipping-item__margin: 0 0 @indent__base; +@checkout-shipping-item__padding: @indent__base (@indent__l + 5px) @indent__base @indent__base; +@checkout-shipping-item__transition: .3s border-color; +@checkout-shipping-item__width: 100%/3; +@checkout-shipping-item-tablet__width: 100%/2; +@checkout-shipping-item-mobile__width: 100%; +@checkout-shipping-item__active__border-color: @color-orange-red1; + +@checkout-shipping-item-icon__selected__height: 27px; +@checkout-shipping-item-icon__selected__width: 29px; + +@checkout-shipping-item-mobile__padding: 0 0 15px; +@checkout-shipping-item-mobile__margin: @checkout-shipping-item-mobile__padding; +@checkout-shipping-item-mobile__active__padding: 15px (@indent__l + 5px) 15px 18px; + +@checkout-shipping-item-before__border-color: @color-gray80; +@checkout-shipping-item-before__height: calc(~"100% - 20px"); + +@checkout-shipping-method__border: @checkout-step-title__border; +@checkout-shipping-method__padding: @indent__base; + +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + .opc-wrapper { + + // + // Shipping Address + // --------------------------------------------- + + .form-login, + .form-shipping-address { + .css(margin-bottom, @checkout-step-title__margin-bottom); + .fieldset { + .field { + .label { + font-weight: @font-weight__regular; + } + } + .note { + font-size: @font-size__base; + margin-top: @indent__s; + } + } + } + + .shipping-address-items { + font-size: 0; + } + + .shipping-address-item { + &:extend(.abs-add-box-sizing all); + .css(border, @checkout-shipping-item__border); + .css(font-size, @font-size__base); + .css(line-height, @checkout-shipping-item__line-height); + .css(margin, @checkout-shipping-item__margin); + .css(padding, @checkout-shipping-item__padding); + .css(transition, @checkout-shipping-item__transition); + .css(width, @checkout-shipping-item-tablet__width); + display: inline-block; + position: relative; + vertical-align: top; + word-wrap: break-word; + + &.selected-item { + .css(border-color, @checkout-shipping-item__active__border-color); + + &:after { + .css(background, @checkout-shipping-item-icon__background-color); + .css(color, @checkout-shipping-item-icon__color); + .css(content, @checkout-shipping-item-icon__content); + .css(font-family, @icons__font-name); + .css(height, @checkout-shipping-item-icon__selected__height); + .css(width, @checkout-shipping-item-icon__selected__width); + font-size: 19px; + line-height: 21px; + padding-top: 2px; + position: absolute; + right: 0; + text-align: center; + top: 0; + } + + .action-select-shipping-item { + &:extend(.abs-no-display-s all); + visibility: hidden; + } + } + } + + .field { + &.addresses { + &:extend(.abs-add-clearfix all); + } + } + + .action-show-popup { + margin: 0 0 @indent__base; + > span { + &:before { + content: '+'; + padding-right: @indent__xs; + } + } + } + + .action-select-shipping-item { + float: right; + margin: @indent__base 0 0; + } + + .edit-address-link { + &:extend(.abs-action-button-as-link all); + display: block; + float: left; + margin: 26px 5px 0 0; + } + } + + // + // Shipping Methods + // --------------------------------------------- + + .checkout-shipping-method { + .step-title { + margin-bottom: 0; + } + .no-quotes-block { + margin: @indent__base 0; + } + } + + .methods-shipping { + .actions-toolbar { + .action { + &.primary { + &:extend(.abs-button-l all); + margin: @indent__base 0 0; + } + } + } + } + + .table-checkout-shipping-method { + thead { + th { + display: none; + } + } + tbody { + td { + .css(border-top, @checkout-shipping-method__border); + .css(padding-bottom, @checkout-shipping-method__padding); + .css(padding-top, @checkout-shipping-method__padding); + &:first-child { + padding-left: 0; + padding-right: 0; + width: 20px; + } + } + tr { + &:first-child { + td { + border-top: none; + } + } + } + .col-price { + font-weight: @font-weight__semibold; + } + .row-error { + td { + border-top: none; + padding-bottom: @indent__s; + padding-top: 0; + } + } + } + } +} + +// +// Mobile +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { + .opc-wrapper { + .form-login, + .form-shipping-address, + .methods-shipping { + .css(background, @checkout-step-content-mobile__background); + .css(margin, @checkout-step-content-mobile__margin); + .css(padding, @indent__base @checkout-step-content-mobile__margin-s); + } + + .form-login { + + .form-shipping-address { + .css(margin-top, -(@checkout-step-content-mobile__margin-s)); + } + } + + .shipping-address-item { + .css(border-bottom, 1px solid @checkout-shipping-item-before__border-color); + .css(margin, @checkout-shipping-item-mobile__margin); + .css(padding, @checkout-shipping-item-mobile__padding); + .css(width, @checkout-shipping-item-mobile__width); + &.selected-item { + .css(padding, @checkout-shipping-item-mobile__active__padding); + border-bottom-width: 2px; + + .edit-address-link { + .css(right, @checkout-shipping-item-icon__selected__width + @indent__s); + } + } + } + + .action-select-shipping-item { + float: none; + margin-top: @indent__s; + width: 100%; + } + + .action-show-popup { + width: 100%; + } + + .methods-shipping { + .css(border-bottom, @checkout-step-title__border); + padding-top: @indent__l; + } + + .edit-address-link { + .icon-font( + @icon-edit, + @_icon-font-size: 18px, + @_icon-font-line-height: 20px, + @_icon-font-text-hide: true, + @_icon-font-color: @minicart-icons-color, + @_icon-font-color-hover: @primary__color, + @_icon-font-color-active: @minicart-icons-color + ); + margin: 0; + position: absolute; + right: 0; + top: 5px; + } + } +} + +// +// Desktop +// _____________________________________________ + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .checkout-shipping-method { + .actions-toolbar { + > .primary { + float: right; + } + .action { + &.primary { + margin: 0; + } + } + } + } + .opc-wrapper { + .form-login, + .form-shipping-address { + .css(max-width, @checkout-shipping-address__max-width); + } + + .form-login { + .css(border-bottom, @checkout-step-title__border); + .css(padding-bottom, @checkout-step-title__margin-bottom); + } + } + .table-checkout-shipping-method { + width: auto; + } +} + +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__l) { + .opc-wrapper { + .shipping-address-item { + .css(width, @checkout-shipping-item__width); + + &:before { + .css(background, @checkout-shipping-item-before__border-color); + .css(height, @checkout-shipping-item-before__height); + content: ''; + left: 0; + position: absolute; + top: 0; + width: 1px; + } + + &:nth-child(3n+1) { + &:before { + display: none; + } + } + + &.selected-item { + &:before { + display: none; + } + + + .shipping-address-item { + &:before { + display: none; + } + } + } + } + } + .table-checkout-shipping-method { + min-width: 500px; + } +} diff --git a/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less index 0d3b4cd47ec03767fba0a2a1291fccd7235b6d4e..d10ebc66f56eaf506ac65e19b8f07dbb1ade7c37 100644 --- a/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less @@ -274,13 +274,19 @@ } .gift-content { border-top: @border-width__base solid @color-gray-light5; - margin-left: -@mobile-cart-padding; margin-right: -@mobile-cart-padding; padding-left: @mobile-cart-padding; padding-right: @mobile-cart-padding; overflow: hidden; } } + + .gift-options-cart-item { + & + .action-towishlist { + left: 43px; + position: absolute; + } + } } // diff --git a/app/design/frontend/Magento/luma/web/css/source/_extends.less b/app/design/frontend/Magento/luma/web/css/source/_extends.less index cc4ab06b849cb5eec4233e701e915deedb4285ed..04018f6977c016c96c9444e206a8eb64ba787fff 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_extends.less +++ b/app/design/frontend/Magento/luma/web/css/source/_extends.less @@ -4,8 +4,9 @@ // */ // -// List default styles reset -//-------------------------------------- +// List default styles reset +// --------------------------------------------- + .abs-reset-list { .list-reset-styles(); > li { @@ -14,16 +15,18 @@ } // -// Primary button -//-------------------------------------- +// Primary button +// --------------------------------------------- + .action-primary { .button-primary(); .css(border-radius, @button__border-radius); } // -// Secondary button -//-------------------------------------- +// Secondary button +// --------------------------------------------- + .abs-revert-to-action-secondary { &:extend(.abs-revert-secondary-color all); .css(border-radius, @button__border-radius); @@ -36,8 +39,9 @@ } // -// Link as a button -//-------------------------------------- +// Link as a button +// --------------------------------------------- + .abs-action-link-button { .button(); .link-as-button(); @@ -46,7 +50,8 @@ // // Button as a link -//-------------------------------------- +// --------------------------------------------- + .abs-action-button-as-link { .button-as-link( @_margin: false @@ -61,28 +66,32 @@ // // Button revert secondary color -//-------------------------------------- +// --------------------------------------------- + .abs-revert-secondary-color { .button-revert-secondary-color(); } // // Button revert secondary size -//-------------------------------------- +// --------------------------------------------- + .abs-revert-secondary-size { .button-revert-secondary-size(); } // // Large button -//-------------------------------------- +// --------------------------------------------- + .abs-button-l { .button-l(); } // -// Product options list -//-------------------------------------- +// Product options list +// --------------------------------------------- + @abs-product-options-list: { dt { float: left; @@ -104,8 +113,9 @@ } // -// Desktop -//-------------------------------------- +// Desktop +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-product-options-list-desktop { @abs-product-options-list(); @@ -113,8 +123,9 @@ } // -// Button reset width, floats, margins -//-------------------------------------- +// Button reset width, floats, margins +// --------------------------------------------- + .abs-button-responsive { .button-responsive(); } @@ -126,8 +137,9 @@ } // -// Blocks in 2 columns -//-------------------------------------- +// Blocks in 2 columns +// --------------------------------------------- + @abs-blocks-2columns: { width: 48%; &:nth-child(1) { @@ -155,8 +167,9 @@ } // -// Reset image alignment in container -//-------------------------------------- +// Reset image alignment in container +// --------------------------------------------- + .abs-reset-image-wrapper { height: auto; padding: 0!important; @@ -166,8 +179,9 @@ } // -// Adaptive images -//-------------------------------------- +// Adaptive images +// --------------------------------------------- + .abs-adaptive-images { display: block; height: auto; @@ -182,8 +196,9 @@ } // -// Title for login blocks -//-------------------------------------- +// Title for login blocks +// --------------------------------------------- + .abs-login-block-title { strong { font-weight: 500; @@ -195,8 +210,9 @@ } // -// Simple Dropdown -//-------------------------------------- +// Simple Dropdown +// --------------------------------------------- + .abs-dropdown-simple { .dropdown( @_dropdown-list-item-padding: 5px 5px 5px 23px, @@ -210,16 +226,18 @@ } // -// Input quantity -//-------------------------------------- +// Input quantity +// --------------------------------------------- + .abs-input-qty { width: 54px; text-align: center; } // -// Marging for blocks & widgets -//-------------------------------------- +// Marging for blocks & widgets +// --------------------------------------------- + .abs-margin-for-blocks-and-widgets { margin-bottom: @indent__xl; } @@ -231,8 +249,9 @@ } // -// Remove button for blocks -//-------------------------------------- +// Remove button for blocks +// --------------------------------------------- + .abs-remove-button-for-blocks { .icon-font( @icon-remove, @@ -246,8 +265,9 @@ } // -// Product link -//-------------------------------------- +// Product link +// --------------------------------------------- + .abs-product-link { font-weight: @font-weight__regular; > a { @@ -265,8 +285,9 @@ } // -// Link -//-------------------------------------- +// Link +// --------------------------------------------- + .abs-like-link { .link(); cursor: pointer; @@ -274,7 +295,8 @@ // // Reset left margin -//-------------------------------------- +// --------------------------------------------- + @abs-reset-left-margin: { margin-left: 0; }; @@ -296,8 +318,9 @@ } // -// Action with icon remove with text -//-------------------------------------- +// Action with icon remove with text +// --------------------------------------------- + .abs-action-remove { &:extend(.abs-action-button-as-link all); width: auto; @@ -308,8 +331,9 @@ } // -// Action with icon remove with text for desktop -//-------------------------------------- +// Action with icon remove with text for desktop +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-action-remove-desktop { margin-left: 90%; @@ -317,8 +341,9 @@ } // -// Add Recipient -//-------------------------------------- +// Add Recipient +// --------------------------------------------- + .abs-add-fields { .fieldset { .field { @@ -360,8 +385,9 @@ } // -// Add Recipient for desktop -//-------------------------------------- +// Add Recipient for desktop +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-add-fields-desktop { .fieldset { @@ -382,8 +408,9 @@ } // -// Margin for forms -//-------------------------------------- +// Margin for forms +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-margin-for-forms-desktop { .css(margin-left, @form-field-type-label-inline__width); @@ -391,8 +418,9 @@ } // -// Visibility hidden / show visibility hidden -//-------------------------------------- +// Visibility hidden / show visibility hidden +// --------------------------------------------- + @abs-hidden: { .visibility-hidden(); }; @@ -402,8 +430,9 @@ } // -// Visually hidden / show visually hidden -//-------------------------------------- +// Visually hidden / show visually hidden +// --------------------------------------------- + @abs-visually-hidden: { .visually-hidden(); }; @@ -437,8 +466,9 @@ } // -// Clearfix -//-------------------------------------- +// Clearfix +// --------------------------------------------- + @abs-add-clearfix: { .clearfix(); }; @@ -472,8 +502,9 @@ } // -// Box-sizing -//-------------------------------------- +// Box-sizing +// --------------------------------------------- + @abs-add-box-sizing: { box-sizing: border-box; }; @@ -494,9 +525,16 @@ } } +.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { + .abs-add-box-sizing-desktop-m { + @abs-add-box-sizing(); + } +} + // -// Revert field type -//-------------------------------------- +// Revert field type +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-revert-field-type-desktop { .fieldset { @@ -512,8 +550,9 @@ } // -// Settings icons -//-------------------------------------- +// Settings icons +// --------------------------------------------- + .abs-navigation-icon { .icon-font( @_icon-font-content: @icon-down, @@ -530,8 +569,9 @@ } // -// Split button -//-------------------------------------- +// Split button +// --------------------------------------------- + .abs-split-button { .dropdown-split( @_options-selector : ~".items", @@ -541,8 +581,9 @@ } // -// Field 2 column -//-------------------------------------- +// Field 2 column +// --------------------------------------------- + @abs-form-field-column-2: { .fieldset { .field { @@ -572,8 +613,9 @@ } // -// Field 1 column -//-------------------------------------- +// Field 1 column +// --------------------------------------------- + @abs-form-field-revert-column-1: { .form-field-column-number(@_column-number: 1); }; @@ -591,8 +633,9 @@ } // -// Checkout shipping methods title -//-------------------------------------- +// Checkout shipping methods title +// --------------------------------------------- + .abs-methods-shipping-title { .font-size(16); margin-bottom: 15px; @@ -600,8 +643,9 @@ } // -// Checkout order review -//-------------------------------------- +// Checkout order review +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .abs-checkout-order-review { tbody > tr { @@ -642,8 +686,9 @@ } // -// Add to Actions -//-------------------------------------- +// Add to Actions +// --------------------------------------------- + .abs-actions-addto { .css(color, @addto-color); display: inline-block; @@ -664,15 +709,17 @@ } // -// Box-tocart block -//-------------------------------------- +// Box-tocart block +// --------------------------------------------- + .abs-box-tocart { margin: 0 0 @indent__l; } // -// General pages forms -//-------------------------------------- +// General pages forms +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-forms-general-desktop { max-width: 500px; @@ -686,8 +733,9 @@ } // -// Revert side paddings -//-------------------------------------- +// Revert side paddings +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-revert-side-paddings { padding-left: 0; @@ -696,8 +744,9 @@ } // -// Abstract toggle title block -//-------------------------------------- +// Abstract toggle title block +// --------------------------------------------- + @abs-toggling-title: { .css(border-top, @border-width__base solid @border-color__base); cursor: pointer; @@ -747,8 +796,9 @@ } // -// Cart discount block -//-------------------------------------- +// Cart discount block +// --------------------------------------------- + .abs-cart-block { margin: 0; > .title { @@ -780,8 +830,9 @@ } // -// Checkout order review price -//-------------------------------------- +// Checkout order review price +// --------------------------------------------- + .abs-checkout-cart-price { .css(color, @primary__color__lighter); .font-size(16); @@ -789,8 +840,9 @@ } // -// Checkout order product name -//-------------------------------------- +// Checkout order product name +// --------------------------------------------- + .abs-checkout-product-name { .font-size(18); font-weight: @font-weight__light; @@ -798,8 +850,9 @@ } // -// Mobile checkout order product name -//-------------------------------------- +// Mobile checkout order product name +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .abs-product-items-summary { tbody { @@ -838,8 +891,9 @@ } // -// Account pages: title -//-------------------------------------- +// Account pages: title +// --------------------------------------------- + .abs-account-title { > strong, > span { @@ -852,8 +906,9 @@ } // -// Account pages: block font size -//-------------------------------------- +// Account pages: block font size +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-account-block-font-size { .font-size(16); @@ -861,15 +916,17 @@ } // -// Account pages: block line-height -//-------------------------------------- +// Account pages: block line-height +// --------------------------------------------- + .abs-account-block-line-height { line-height: 24px; } // -// Account pages: margin for table -//-------------------------------------- +// Account pages: margin for table +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .abs-account-table-margin-mobile { .css(margin-top, -@indent__base); @@ -882,8 +939,9 @@ } // -// Account pages: table col actions -//-------------------------------------- +// Account pages: table col actions +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .abs-col-no-prefix { &:before { @@ -893,8 +951,9 @@ } // -// Account pages: order table summary -//-------------------------------------- +// Account pages: order table summary +// --------------------------------------------- + .abs-account-summary { td { .css(background, @sidebar__background-color); @@ -902,8 +961,9 @@ } // -// Action print with icon -//-------------------------------------- +// Action print with icon +// --------------------------------------------- + @abs-action-print: { .icon-font( @icon-print, @@ -930,8 +990,9 @@ } // -// Excl/Incl tax -//-------------------------------------- +// Excl/Incl tax +// --------------------------------------------- + .abs-incl-excl-tax { .price-including-tax, .price-excluding-tax { @@ -965,8 +1026,9 @@ } // -// Cart tax total -//-------------------------------------- +// Cart tax total +// --------------------------------------------- + .abs-tax-total { cursor: pointer; position: relative; @@ -993,15 +1055,17 @@ } // -// Forms: margin-bottom for small forms -//-------------------------------------- +// Forms: margin-bottom for small forms +// --------------------------------------------- + .abs-forms-margin-small { .css(margin-bottom, @indent__base); } // -// Forms: margin-bottom for small forms -//-------------------------------------- +// Forms: margin-bottom for small forms +// --------------------------------------------- + .abs-rating-summary { .rating { &-summary { @@ -1022,8 +1086,9 @@ } // -// Account pages: actions -//-------------------------------------- +// Account pages: actions +// --------------------------------------------- + .abs-account-actions { &:after { content: ""; @@ -1041,8 +1106,9 @@ } // -// Account blocks -//-------------------------------------- +// Account blocks +// --------------------------------------------- + .abs-account-blocks { .block-title { &:extend(.abs-account-title all); @@ -1064,8 +1130,9 @@ } // -// Add colon -//-------------------------------------- +// Add colon +// --------------------------------------------- + .abs-colon { &:after { content: ": "; @@ -1073,8 +1140,9 @@ } // -// Icon - create add -//-------------------------------------- +// Icon - create add +// --------------------------------------------- + .abs-icon-add { .icon-font( @_icon-font-content: @icon-expand, @@ -1098,8 +1166,9 @@ } // -// Dropdown items - create new -//-------------------------------------- +// Dropdown items - create new +// --------------------------------------------- + .abs-dropdown-items-new { .items .item:last-child { &:hover { @@ -1116,8 +1185,9 @@ } // -// Abstract no display -//-------------------------------------- +// Abstract no display +// --------------------------------------------- + @abs-no-display: { display: none; }; @@ -1139,8 +1209,9 @@ } // -// Status -//-------------------------------------- +// Status +// --------------------------------------------- + .abs-status { .css(border, 2px solid @border-color__base); border-radius: 3px; @@ -1159,8 +1230,9 @@ } // -// Page title - orders pages -//-------------------------------------- +// Page title - orders pages +// --------------------------------------------- + .abs-title-orders { .page-main { .page-title-wrapper { @@ -1208,8 +1280,9 @@ } // -// Table striped -//-------------------------------------- +// Table striped +// --------------------------------------------- + .abs-table-striped { .table-striped( @_stripped-highlight: even @@ -1228,8 +1301,9 @@ } // -// Table bordered desktop -//-------------------------------------- +// Table bordered desktop +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-table-bordered-desktop { .table-bordered( @@ -1240,8 +1314,9 @@ } // -// Pager toolbar for non-catalog pages desktop -//-------------------------------------- +// Pager toolbar for non-catalog pages desktop +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .abs-pager-toolbar { position: relative; @@ -1263,8 +1338,9 @@ } // -// Items counter in blocks -//-------------------------------------- +// Items counter in blocks +// --------------------------------------------- + .abs-block-items-counter { .css(color, @primary__color__lighter); .font-size(12px); @@ -1272,8 +1348,9 @@ } // -// Sidebar and widget blocks title -//-------------------------------------- +// Sidebar and widget blocks title +// --------------------------------------------- + .abs-block-widget-title { strong { font-size: @font-size__l; @@ -1283,8 +1360,9 @@ } // -// Shopping cart items -//-------------------------------------- +// Shopping cart items +// --------------------------------------------- + .abs-shopping-cart-items { margin-bottom: @indent__base; .actions.main { @@ -1305,8 +1383,9 @@ } // -// Remove top border -//-------------------------------------- +// Remove top border +// --------------------------------------------- + .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .abs-no-border-top { border-top: 0; @@ -1314,7 +1393,7 @@ } // -// Remove bottom border +// Remove bottom border //-------------------------------------- .media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { .abs-no-border-bottom { @@ -1323,8 +1402,9 @@ } // -// Form Field Date -//-------------------------------------- +// Form Field Date +// --------------------------------------------- + .abs-field-date { .control { position: relative; @@ -1336,9 +1416,207 @@ } // -// Form Field Date Input -//-------------------------------------- +// Form Field Date Input +// --------------------------------------------- + .abs-field-date-input { - margin-right: @indent__s; + .css(margin-right, @indent__s); width: calc(~"100% - (@{icon-calendar__font-size} + @{indent__s})"); } + +// +// Form Field Tooltip +// --------------------------------------------- + +.abs-field-tooltip { + &:extend(.abs-add-box-sizing all); + position: relative; + input { + .css(margin-right, @indent__s); + width: calc(~"100% - (@{checkout-tooltip-icon__font-size} + @{indent__s} + @{indent__xs})"); + &:focus { + + .field-tooltip { + .field-tooltip-action { + &:before { + .css(color, @checkout-tooltip-icon__hover__color); + } + } + .field-tooltip-content { + display: block; + } + } + } + } +} + +// +// Checkout Tooltip Content (position: top) +// --------------------------------------------- + +@abs-checkout-tooltip-content-position-top: { + .css(right, @checkout-tooltip-content-mobile__right); + .css(top, @checkout-tooltip-content-mobile__top); + left: auto; + + &:before, + &:after { + .arrow( + @_position: top, + @_size: @checkout-tooltip-icon-arrow__font-size, + @_color: @checkout-tooltip-content__background-color + ); + .css(margin-top, @checkout-tooltip-icon-arrow__left); + .css(right, @indent__s); + left: auto; + top: 0%; + } + &:before { + .css(border-bottom-color, @checkout-tooltip-content__active__border-color); + } + &:after { + .css(border-bottom-color, @checkout-tooltip-content__background-color); + top: 1px; + } +}; + +.abs-checkout-tooltip-content-position-top { + @abs-checkout-tooltip-content-position-top(); +} + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = (@screen__m + 1)) { + .abs-checkout-tooltip-content-position-top-mobile { + @abs-checkout-tooltip-content-position-top(); + } +} + +// +// Checkout title +// --------------------------------------------- + +.abs-checkout-title { + .css(padding-bottom, @checkout-step-title__padding); + .typography( + @_font-size: @checkout-step-title__font-size, + @_font-weight: @checkout-step-title__font-weight, + @_font-family: false, + @_font-style: false, + @_line-height: false + ); +} + +// +// Shopping cart sidebar and checkout sidebar totals +// --------------------------------------------- + +.abs-sidebar-totals { + border-top: 1px solid @border-color__base; + padding-top: 10px; + tbody, + tfoot { + .mark { + border: 0; + font-weight: @font-weight__regular; + padding: 6px 0; + } + .amount { + border: 0; + font-weight: @font-weight__regular; + padding: 6px 0 6px 14px; + text-align: right; + } + } + .table-caption { + &:extend(.abs-no-display all); + } + .grand { + th, + td { + padding: 11px 0; + } + strong { + display: inline-block; + font-weight: @font-weight__semibold; + padding: 3px 0 0; + } + .mark { + border-top: 1px solid @border-color__base; + .font-size(18); + padding-right: @indent__s; + } + .amount { + border-top: 1px solid @border-color__base; + .font-size(18); + } + } + .msrp { + margin-bottom: @indent__s; + } + tbody tr:last-child td { + padding-bottom: 19px; + } + .totals-tax { + &-summary { + .mark, + .amount { + border-top: @border-width__base solid @border-color__base; + border-bottom: @border-width__base solid @border-color__base; + cursor: pointer; + } + .amount .price { + position: relative; + padding-right: @indent__base; + .icon-font( + @icon-down, + @_icon-font-size: 12px, + @_icon-font-line-height: 12px, + @_icon-font-text-hide: true, + @_icon-font-position: after + ); + &:after { + position: absolute; + right: 3px; + top: 3px; + } + } + &.expanded { + .mark, + .amount { + border-bottom: 0; + } + .amount .price { + .icon-font-symbol( + @_icon-font-content: @icon-up, + @_icon-font-position: after + ); + } + } + } + &-details { + display: none; + border-bottom: @border-width__base solid @border-color__base; + &.shown { + display: table-row; + } + } + } + .table-wrapper { + margin-bottom: 0; + } +} + +.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) { + .abs-sidebar-totals-mobile { + th { + &:extend(.abs-col-no-prefix all); + } + td { + &:extend(.abs-col-no-prefix all); + } + tbody tr:not(:last-child) td { + &:extend(.abs-no-border-bottom-top all); + } + .amount { + text-align: right; + } + } +} diff --git a/app/design/frontend/Magento/luma/web/css/source/_theme.less b/app/design/frontend/Magento/luma/web/css/source/_theme.less index f293d18d117a1911f079065f25280984a9fd54a7..52914c1bd64117c7cba4af7e2086731a7ae19870 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_theme.less +++ b/app/design/frontend/Magento/luma/web/css/source/_theme.less @@ -248,3 +248,23 @@ @overlay__opacity-old: 70; @gallery-thumb-border-color-active: @active__color; + +// Modal popup +@modal-action-close__font-size: @font-size__base; + +// Checkout tooltip icon +@checkout-tooltip-icon__font-size: 21px; + +// Checkout Payment Option icon +@checkout-payment-option-title-icon__font-size: 14px; +@checkout-payment-option-title-icon__line-height: 16px; +@checkout-payment-option-title-icon__margin: 0 0 0 @indent__s; + +// Checkout Sidebar Shipping Information +@checkout-sidebar-shipping-information-edit-icon__content: @icon-edit; +@checkout-sidebar-shipping-information-edit-icon__font-size: 18px; +@checkout-sidebar-shipping-information-edit-icon__line-height: 20px; +@checkout-sidebar-shipping-information-edit-icon__top: @indent__s; + +// Checkout +@checkout-sidebar__columns: 8; diff --git a/app/design/frontend/Magento/luma/web/css/source/_variables.less b/app/design/frontend/Magento/luma/web/css/source/_variables.less index dbdbeb65ad660dccec8e724925392cf18b254c96..ee76525dd8cc68c2906c4bfa5aecdbaede9c7f32 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_variables.less +++ b/app/design/frontend/Magento/luma/web/css/source/_variables.less @@ -26,7 +26,6 @@ @icon-success: '\e60e'; @icon-error: '\e61f'; @icon-edit: '\e601'; -@icon-help: '\e623'; @icon-print: '\e624'; @icon-star-empty: '\e625'; @icon-download: '\e626'; diff --git a/app/design/frontend/Magento/luma/web/fonts/Luma-Icons.svg b/app/design/frontend/Magento/luma/web/fonts/Luma-Icons.svg index 5e68e79f8e3e44488f98f45b6a4d1408f485d2ec..fa092836d03823258384bc553188cc92e412a02f 100644 --- a/app/design/frontend/Magento/luma/web/fonts/Luma-Icons.svg +++ b/app/design/frontend/Magento/luma/web/fonts/Luma-Icons.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg"><defs><font id="Luma-Icons" horiz-adv-x="512"><font-face units-per-em="512" ascent="480" descent="-32"/><missing-glyph horiz-adv-x="512"/><glyph unicode=" " d="" horiz-adv-x="256"/><glyph unicode="" d="M436.608 435.568c-65.68 31.424-144.064 2.832-174.976-63.84-2.16-4.64-4.016-10.448-5.664-17.2-1.648 6.752-3.504 12.56-5.632 17.2-30.944 66.672-109.248 95.264-174.944 63.84-65.6-31.424-93.744-110.96-62.832-177.648 30.928-66.672 243.344-257.84 243.344-257.84s0.016 0.224 0.048 0.576c0.048-0.352 0.064-0.576 0.064-0.576s212.512 191.168 243.44 257.84c30.896 66.688 2.832 146.224-62.848 177.648z"/><glyph unicode="" d="M362.533 425.051c-49.81-49.792-20.809-20.772-20.809-20.772l96.402-96.384c0 0-31.067-31.049 20.772 20.773s-46.611 146.194-96.365 96.384zM320.147 383.671l-227.987-227.986 0.329-0.293-54.071-146.524 149.833 50.688 0.311-0.311 0.786 0.805v0.019l227.2 227.2-96.403 96.403zM179.036 104.375l-78.811-33.28 37.047 75.044 38.345 38.363 41.764-41.783-38.345-38.345z"/><glyph unicode="" d="M255.952 480l-255.952-448h512l-256.048 448zM287.12 353.808v-65.36l-16.688-128.544h-27.088l-18.032 128.544-0.992 65.36h62.8zM224.096 64.112v64.112h64.24v-64.112h-64.24z"/><glyph unicode="" d="M363.923 112.019c-29.805-28.764-68.663-43.502-108.013-43.538-35.145 0.036-70.199 11.757-99.347 35.932-37.029 30.829-56.046 74.971-56.1 119.661 0 7.442 0.549 14.829 1.591 22.18l-60.672-11.374c-0.164-3.602-0.292-7.186-0.292-10.807-0.036-61.495 26.459-122.899 77.549-165.285 40.009-33.335 88.887-49.683 137.252-49.683h0.128c56.211 0 112.164 22.217 153.746 64.914l39.844-39.772 0.311 124.745-131.803 0.348 45.805-47.324zM393.344 389.23c-40.046 33.335-88.923 49.664-137.271 49.664-55.808 0-111.397-21.833-152.923-63.945l-37.687 34.798-0.677-120.722 130.487-0.75-46.336 48.493c29.641 28.252 68.188 42.697 107.154 42.733 35.108-0.036 70.217-11.721 99.328-35.932 37.029-30.829 56.046-74.935 56.137-119.698 0-6.437-0.457-12.892-1.225-19.365l60.435 11.593c0.036 2.615 0.164 5.212 0.164 7.772-0.036 61.549-26.514 122.899-77.587 165.357z"/><glyph unicode="" d="M95.792-32h320.4v320.080h-320.4v-320.080zM318.336 228.512c0 9.904 8.032 17.904 17.952 17.904 9.904 0 17.936-8 17.936-17.904v-188.736c0-9.888-8.032-17.92-17.936-17.92-9.92 0-17.952 8.032-17.952 17.92v188.736zM238.048 228.512c0 9.904 8.032 17.904 17.92 17.904s17.92-8 17.92-17.904v-188.736c0-9.888-8.032-17.92-17.92-17.92s-17.92 8.032-17.92 17.92v188.736zM157.6 228.512c0 9.904 8 17.904 17.92 17.904 9.888 0 17.92-8 17.92-17.904v-188.736c0-9.888-8.032-17.92-17.92-17.92-9.92 0-17.92 8.032-17.92 17.92v188.736zM423.216 416.528h-71.232v10.896c0 29.040-19.76 52.576-48.8 52.576h-94.72c-29.008 0-48.48-23.536-48.48-52.576v-10.896h-71.232c-13.696 0-24.768-11.088-24.768-24.752v-71.984h384v71.984c0 13.664-11.040 24.752-24.768 24.752zM319.936 416.528h-128.192v14.704c0.032 9.248 7.488 16.736 16.72 16.768h94.72c9.216-0.032 16.704-7.52 16.752-16.768v-14.704z"/><glyph unicode="" d="M511.52 278.496c-1.312 4.096-5.152 6.88-9.44 6.88h-180.704l-55.952 171.744c-1.344 4.096-5.136 6.88-9.44 6.88-4.272 0-8.096-2.784-9.44-6.88l-56.24-171.744h-180.384c-4.256 0-8.096-2.784-9.44-6.88-1.312-4.064 0.128-8.592 3.584-11.088l145.984-106.32-56.256-172.72c-1.328-4.096 0.128-8.592 3.616-11.12 3.456-2.496 8.208-2.496 11.664 0l146.896 106.624 146.64-106.624c1.792-1.28 3.76-1.936 5.808-1.936 2.096 0 4.144 0.656 5.856 1.936 3.568 2.528 4.96 7.008 3.6 11.12l-56.24 172.72 146.288 106.32c3.488 2.496 4.928 6.992 3.6 11.088z"/><glyph unicode="" d="M473.015 200.375v49.371l-7.003 2.268-52.882 17.244-14.116 34.103 27.154 57.381-34.908 34.907-6.583-3.309-49.555-25.198-34.103 14.117-21.394 59.757h-49.371l-2.286-6.985-17.262-52.882-34.048-14.099-57.399 27.136-34.925-34.926 3.309-6.564 25.18-49.591-14.080-34.029-59.758-21.412v-49.39l6.949-2.249 52.901-17.28 14.099-34.067-27.118-57.38 34.925-34.925 6.528 3.328 49.591 25.197 34.066-14.116 21.394-59.757h49.371l2.286 6.985 17.28 52.882 34.029 14.116 57.399-27.136 34.944 34.908-3.346 6.546-25.197 49.572 14.116 34.067 59.813 21.413zM256 154.861c-38.199 0-69.156 30.957-69.156 69.139 0 38.217 30.958 69.156 69.156 69.156 38.163 0 69.156-30.94 69.156-69.156 0-38.18-31.012-69.139-69.156-69.139z"/><glyph unicode="" d="M31.008 351.36l224.992-239.984 225.040 239.984z"/><glyph unicode="" d="M383.415 226.596l-212.571 218.587-37.285-34.981 178.286-183.277-183.278-188.452 36.48-35.657 205.659 211.456-0.201 0.201z"/><glyph unicode="" d="M52.928 345.2h406.144c11.056 0 20 8.976 20 20.016 0 11.072-8.944 20.032-20 20.032h-406.144c-11.056 0-20.016-8.96-20.016-20.032 0-11.040 8.96-20.016 20.016-20.016zM459.072 244.016h-406.144c-11.056 0-20.016-8.944-20.016-20.016s8.96-20.016 20.016-20.016h406.144c11.056 0 20 8.944 20 20.016s-8.928 20.016-20 20.016zM459.072 102.8h-406.144c-11.056 0-20.016-8.96-20.016-20.032s8.96-20.016 20.016-20.016h406.144c11.056 0 20 8.944 20 20.016s-8.928 20.032-20 20.032z"/><glyph unicode="" d="M256.144 480c-89.12 0-161.344-72.24-161.344-161.376 0-89.104 161.344-350.624 161.344-350.624s161.376 261.52 161.376 350.624c0 89.136-72.192 161.376-161.376 161.376zM256.144 269.616c-27.056 0-49.024 21.952-49.024 49.008 0 27.072 21.984 49.024 49.024 49.024 27.104 0 49.088-21.952 49.088-49.024 0-27.056-21.984-49.008-49.088-49.008z"/><glyph unicode="" d="M0 256.144h224.032v223.808h-224.032v-223.808zM288.128 479.952v-95.728h224.176v95.728h-224.176zM0-32h224.032v223.808h-224.032v-223.808zM288.128 256.144h224.176v95.728h-224.176v-95.728zM288.128 96.080h224.176v95.728h-224.176v-95.728zM288.128-32h224.176v95.712h-224.176v-95.712z"/><glyph unicode="" d="M332.764 119.003c-9.216 0-45.495-56.027-65.243-56.027-5.284 0-7.863 4.644-7.863 9.216 0 10.569 7.241 27.044 11.154 36.937l47.397 128.384c23.772 63.891-6.546 81.024-34.871 81.024-38.217 0-72.448-19.091-98.779-44.124-8.576-8.576-37.523-36.206-37.523-48.091 0-3.932 3.931-8.576 8.576-8.576 11.813 0 43.447 57.308 67.803 57.308 5.285 0 11.191-5.924 6.583-17.755l-46.080-115.968c-4.644-11.154-27.044-65.171-27.044-96.786 0-25.015 16.476-36.188 40.192-36.188 66.523 0 143.543 81.645 143.543 100.755-0.019 5.925-4.589 9.892-7.844 9.892zM319.543 439.661c-28.947 0-54.016-23.68-54.016-52.663 0-27.008 17.792-44.8 44.837-44.8 29.55 0 54.62 22.4 54.62 52.7 0 27.008-19.072 44.764-45.44 44.764z"/><glyph unicode="" d="M0 351.552h128.464v128.448h-128.464v-128.448zM191.76 351.552h128.528v128.448h-128.528v-128.448zM383.568 480v-128.448h128.496v128.448h-128.496zM0 159.744h128.464v128.464h-128.464v-128.464zM191.76 159.744h128.528v128.464h-128.528v-128.464zM383.568 159.744h128.496v128.464h-128.496v-128.464zM0-32h128.464v128h-128.464v-128zM191.76-32h128.528v128h-128.528v-128zM383.568-32h128.496v128h-128.496v-128z"/><glyph unicode="" d="M255.296 450.464c-124.688 0-225.76-101.072-225.76-225.76 0-124.672 101.072-225.76 225.76-225.76 124.672 0 225.76 101.088 225.76 225.76 0 124.688-101.072 225.76-225.76 225.76zM231.936 94.576l-125.936 128.032 32.208 25.936 72.864-57.088c29.76 35.424 96 106.032 187.312 161.984l7.696-17.792c-83.808-77.088-152.48-185.6-174.144-241.072z"/><glyph unicode="" d="M0 241.12h512v-34.064h-512v34.064z"/><glyph unicode="" d="M478.263 426.149c-142.555-87.388-245.98-197.632-292.48-252.947l-113.792 89.161-50.267-40.539 196.663-199.973c33.847 86.674 141.056 256.11 271.872 376.485l-11.995 27.813z"/><glyph unicode="" d="M220.576 83.248c-26.352 0-47.696-21.376-47.696-47.712s21.344-47.664 47.696-47.664c26.336 0 47.696 21.328 47.696 47.664s-21.36 47.712-47.696 47.712zM385.344 83.248c-26.4 0-47.76-21.376-47.76-47.712s21.344-47.664 47.76-47.664c26.288 0 47.632 21.328 47.632 47.664s-21.344 47.712-47.632 47.712zM459.856 350.32c-122.384 0-319.856 0-319.856 0s-19.152 52.608-37.392 84.864c-14.128 24.976-43.344 23.968-43.344 23.968-20.096 0-33.024-12.288-33.024-32.4 0-20.096 15.92-36.16 36.032-36.16l8.496-0.080 95.2-262.192 266.832-0.208c0 0 48.784 199.632 46.272 191.888 8.944 27.68-2.448 30.32-19.216 30.32zM166.528 257.344c-14 0-25.36 11.36-25.36 25.376s11.36 25.392 25.36 25.392c14.016 0 25.36-11.376 25.36-25.392s-11.344-25.376-25.36-25.376zM220.768 172.64c-14.016 0-25.376 11.376-25.376 25.392 0 13.984 11.36 25.36 25.376 25.36 14 0 25.36-11.376 25.36-25.36 0.016-14.016-11.36-25.392-25.36-25.392zM248.656 257.344c-14 0-25.376 11.36-25.376 25.376s11.36 25.392 25.376 25.392c14 0 25.36-11.376 25.36-25.392s-11.36-25.376-25.36-25.376zM302.896 172.64c-14 0-25.36 11.376-25.36 25.392 0 13.984 11.36 25.36 25.36 25.36 14.048 0 25.44-11.376 25.44-25.36 0-14.016-11.392-25.392-25.44-25.392zM330.848 257.344c-14 0-25.408 11.36-25.408 25.376s11.408 25.392 25.408 25.392c14 0 25.328-11.376 25.328-25.392s-11.328-25.376-25.328-25.376zM385.040 172.64c-13.984 0-25.328 11.376-25.328 25.392 0 13.984 11.36 25.36 25.328 25.36 14 0 25.408-11.376 25.408-25.36 0-14.016-11.408-25.392-25.408-25.392zM412.96 257.344c-14.016 0-25.36 11.36-25.36 25.376s11.344 25.392 25.36 25.392c14.048 0 25.376-11.376 25.376-25.392s-11.328-25.376-25.376-25.376z"/><glyph unicode="" d="M142.992 332.768c10.352 0 18.8 8.4 18.8 18.8v67.68c0 10.368-8.432 18.784-18.8 18.784-10.384 0-18.8-8.4-18.8-18.784v-67.68c0-10.4 8.416-18.8 18.8-18.8zM394.384 383.344v-0.32c7.776-6.944 12.72-17.008 12.72-28.288 0-20.816-16.88-37.712-37.744-37.712s-37.76 16.912-37.76 37.712c0 11.264 4.976 21.344 12.784 28.288v0.32h-176.416v-0.32c7.824-6.944 12.768-17.008 12.768-28.288 0-20.816-16.896-37.712-37.728-37.712-20.864 0-37.744 16.912-37.744 37.712 0 11.264 4.928 21.344 12.752 28.288v0.32h-85.536v-383.6h447.248v383.6h-85.344zM448.72 32.832h-383.152v254.72h383.152v-254.72zM369.36 332.768c10.384 0 18.784 8.4 18.784 18.8v67.68c0 10.368-8.4 18.784-18.784 18.784-10.352 0-18.816-8.4-18.816-18.784v-67.68c0-10.4 8.464-18.8 18.816-18.8zM349.216 184.128h-47.936v-47.872h47.952v47.872zM349.216 256.112h-47.936v-47.824h47.952v47.824zM349.216 114.112h-47.936v-47.872h47.952v47.872zM416.656 256.112h-47.92v-47.824h47.92v47.824zM416.656 184.128h-47.92v-47.872h47.92v47.872zM281.696 256.112h-47.872v-47.824h47.872v47.824zM146.8 184.128h-47.856v-47.872h47.856v47.872zM214.288 114.112h-47.888v-47.872h47.872v47.872zM146.8 114.112h-47.856v-47.872h47.856v47.872zM281.696 184.128h-47.872v-47.872h47.872v47.872zM281.696 114.112h-47.872v-47.872h47.872v47.872zM214.288 184.128h-47.888v-47.872h47.872v47.872zM214.288 256.112h-47.888v-47.824h47.872v47.824z"/><glyph unicode="" d="M256 444.727l-200.814-243.291h131.054v-198.144h139.575v198.144h131.017z"/><glyph unicode="" d="M325.779 246.583v198.144h-139.593v-198.144h-130.999l200.832-243.292 200.813 243.292z"/><glyph unicode="" d="M487.232 35.872c0 0-78.176 80.288-109.328 111.312-13.552 13.552-22.832 22.752-22.832 22.752 10.56 15.088 18.816 31.616 24.704 49.392 5.84 17.76 8.752 36.496 8.752 56.192 0 25.36-4.816 49.2-14.448 71.552-9.664 22.32-22.784 41.824-39.456 58.432-16.64 16.688-36.144 29.824-58.496 39.472-22.336 9.664-46.176 14.496-71.536 14.496-25.344 0-49.184-4.848-71.552-14.496-22.336-9.648-41.712-22.784-58.192-39.472-16.416-16.608-29.52-36.128-39.152-58.448-9.664-22.336-14.496-46.192-14.496-71.552 0-25.376 4.848-49.216 14.496-71.552 9.632-22.304 22.72-41.792 39.152-58.464 16.464-16.608 35.856-29.776 58.176-39.456 22.368-9.664 46.208-14.448 71.552-14.448 19.68 0 38.416 2.88 56.208 8.768 17.776 5.856 34.288 14.144 49.36 24.72 0 0 8.576-8.512 21.2-21.216 34.512-34.64 110.416-113.392 110.416-113.392 11.456-4.992 29.712 0.336 38.848 8.064 9.040 7.776 14.096 23.984 6.624 37.344zM327.792 223.28c-7.008-16.192-16.576-30.336-28.624-42.336-12.096-12.048-26.192-21.616-42.336-28.608-16.128-7.024-33.392-10.528-51.68-10.528-18.704 0-36.096 3.504-52.256 10.528-16.16 7.008-30.288 16.56-42.336 28.608-12.048 12.016-21.616 26.16-28.608 42.336-7.008 16.112-10.512 33.568-10.512 52.24 0 18.272 3.504 35.632 10.512 51.984 6.992 16.336 16.56 30.56 28.608 42.592 12.048 12.096 26.176 21.664 42.336 28.608 16.16 7.056 33.552 10.512 52.256 10.512 18.288 0 35.552-3.456 51.68-10.512 16.144-6.96 30.24-16.512 42.336-28.608 12.032-12.032 21.616-26.256 28.624-42.592 7.008-16.352 10.48-33.712 10.48-51.984 0.016-18.672-3.456-36.128-10.48-52.24z"/><glyph unicode="" d="M483.255 415.177l-36.023 35.968-191.25-191.268-191.25 191.268-35.986-35.968 191.268-191.269-191.123-191.14 35.968-35.932 191.14 191.104 191.123-191.104 35.932 35.932-191.104 191.123z"/><glyph unicode="" d="M200.21 226.889l178.213 183.315-37.248 34.981-212.608-218.588 218.459-223.78 36.389 35.657z"/><glyph unicode="" d="M256 335.168l-224.992-239.984h450.032z"/><glyph unicode="" d="M96.624 451.12v-454.24l312.928 227.12z"/><glyph unicode="" d="M102.992 224l312.912-227.12v454.24z"/><glyph unicode="" d="M0 0.464h63.984v479.536h-63.984v-479.536zM512.080 480h-415.824v-287.888h415.824l-138.208 142.032 138.208 145.856z"/><glyph unicode="" d="M512 241.12h-238.512v238.88h-34.016v-238.88h-239.472v-34.064h239.472v-239.056h34.016v239.056h238.512z"/><glyph unicode="" d="M255.968 228.064l221.488 155.84c-2.656 0.528-5.344 0.848-8.128 0.848h-426.656c-2.8 0-5.504-0.32-8.144-0.848l221.44-155.84zM256.928 168.496l-0.96 1.408-0.944-1.408-254.56 179.136c-0.176-1.6-0.464-3.2-0.464-4.816v-267.712c0-23.904 19.104-43.312 42.672-43.312h426.656c23.6 0 42.688 19.408 42.688 43.312v267.712c0 1.632-0.288 3.216-0.496 4.816l-254.592-179.136z"/><glyph unicode="" d="M127.584 31.776v127.632h-127.584v-127.632h127.584zM319.248 416.24h-126.928v-384.448h126.928v384.448zM511.584 287.472h-127.376v-255.68h127.376v255.68z"/><glyph unicode="" d="M255.296 450.464c-124.688 0-225.76-101.072-225.76-225.76 0-124.672 101.072-225.76 225.76-225.76 124.672 0 225.76 101.088 225.76 225.76 0 124.688-101.072 225.76-225.76 225.76zM372.16 144.832l-37.104-37.104-79.088 79.056-79.056-79.040-37.12 37.136 79.024 79.024-79.136 79.12 37.136 37.136 79.12-79.136 79.184 79.184 37.152-37.152-79.2-79.168 79.088-79.056z"/><glyph unicode="" d="M262.748 418.688c-113.664 2.249-207.214-67.803-208.969-156.435-0.585-30.829 9.984-59.813 28.8-84.644l-4.919 4.955c32.384-41.618-31.104-153.308-31.104-153.308l142.281 70.345c22.51-7.095 44.16-11.923 69.724-12.452 113.664-2.231 205.111 78.355 206.848 167.004 1.755 88.631-88.96 162.304-202.661 164.535z"/><glyph unicode="" d="M259.163 285.422l201.837-196.224 38.546 41.070-240.713 234.021-246.363-240.476 39.26-40.101z"/><glyph unicode="" d="M252.819 162.579l-201.82 196.224-38.528-41.070 240.677-234.021 246.4 240.476-39.332 40.101z"/><glyph unicode="" d="M256-33.248c-141.408 0-256 114.624-256 256s114.592 256 256 256c141.376 0 256-114.624 256-256s-114.608-256-256-256zM256 447.76c-124.048 0-225.008-100.96-225.008-225.008s100.96-225.024 225.008-225.024 224.992 100.96 224.992 225.008-100.928 225.024-224.992 225.024zM320.24 219.152l-15.6-12.128c-8.496-6.624-14.128-14.32-16.912-23.152-1.776-5.6-3.008-12.256-3.168-24h-59.712c0.88 24.848 3.504 39.968 7.328 49.472 3.808 9.472 13.632 20.368 29.44 32.72l16.032 12.528c5.28 4 9.536 8.32 12.752 13.024 5.872 8.064 8.784 16.976 8.784 26.656 0 11.152-3.248 21.312-9.776 30.496-6.496 9.184-18.4 13.808-35.712 13.808-17.008 0-29.056-5.68-36.16-17.008s-10.592-21.664-10.592-33.84h-63.68c1.744 41.872 16.32 70.16 43.776 87.632 17.344 11.152 38.656 16.752 63.904 16.752 33.216 0 60.784-7.936 82.752-23.808 21.968-15.84 34.8-48.432 34.8-79.6 0-19.088-6.624-26.096-16.144-39.184-5.584-7.92-16.272-18.048-32.112-30.368zM287.728 64h-63.504v63.68h63.504v-63.68z"/><glyph unicode="" d="M416.656 128v135.696h-320.672v-135.696h-95.984v199.344c0 13.76 11.168 24.912 24.944 24.912h462.144c13.744 0 24.912-11.152 24.912-24.912v-199.344h-95.344zM464.304 324.624c-11.024 0-19.92-8.928-19.92-19.936s8.896-19.952 19.92-19.952c10.992 0 19.968 8.96 19.968 19.952 0 11.008-8.992 19.936-19.968 19.936zM127.728 480h256v-96.192h-256v96.192zM160.976 31.664h191.232v192.336h31.824v-224.080h-255.984v224.080h32.912v-192.336z"/><glyph unicode="" d="M502.080 285.376h-180.704l-55.952 171.744c-1.344 4.096-5.136 6.88-9.44 6.88-4.272 0-8.096-2.784-9.44-6.88l-56.24-171.744h-180.384c-4.256 0-8.096-2.784-9.44-6.88-1.312-4.064 0.128-8.592 3.584-11.088l145.984-106.32-56.256-172.72c-1.328-4.096 0.128-8.592 3.616-11.12 3.456-2.496 8.208-2.496 11.664 0l146.896 106.624 146.64-106.624c1.792-1.28 3.76-1.936 5.808-1.936 2.096 0 4.144 0.656 5.856 1.936 3.568 2.528 4.96 7.008 3.6 11.12l-56.24 172.72 146.288 106.32c3.488 2.496 4.928 7.008 3.6 11.088-1.312 4.096-5.168 6.88-9.44 6.88zM333.424 170.256l48.208-148.064-125.632 91.36-125.968-91.44 48.256 148.128-125.168 91.136h154.576l48.256 147.376 48.016-147.376h154.832l-125.376-91.12z"/><glyph unicode="" d="M319.376 223.824v127.76h-126.752v-127.76h-89.744l153.168-188.608 153.088 188.608zM256.016 480c-141.392 0-256-114.608-256-255.984 0-141.392 114.608-256.016 256-256.016 141.376 0 256 114.624 256 256.016 0 141.376-114.624 255.984-256 255.984zM256.016 0c-123.52 0-224 100.496-224 224.016 0 123.504 100.48 223.984 224 223.984s224-100.48 224-223.984c0-123.52-100.48-224.016-224-224.016z"/><glyph unicode="" d="M255.982 440.594c-119.607 0-216.576-96.969-216.576-216.594s96.969-216.595 216.576-216.595c119.625 0 216.595 96.969 216.595 216.595s-96.951 216.595-216.595 216.595zM255.982 419.913c108.051 0 195.913-87.881 195.913-195.913 0-45.184-15.507-86.711-41.325-119.899-3.108 1.134-6.217 2.195-9.197 3.456-19.748 8.265-41.709 17.957-61.421 26.094-5.632 1.536-11.264 3.072-16.896 4.608-6.692 4.589-13.33 19.986-16.914 27.666-3.548 0.512-7.149 1.005-10.752 1.481 0.531 11.868 7.881 12.544 10.752 21.541 2.541 7.954 0.293 18.341 4.279 25.728 2.779 5.12 9.125 5.12 12.233 9.545 2.853 3.95 4.772 10.917 5.668 15.799 1.609 8.905 3.017 21.12-1.207 29.988-2.432 5.065-3.968 5.577-4.644 11.739-0.823 7.516 2.212 31.891 2.341 37.175 0.293 13.678-0.055 14.793-3.346 28.123 0 0-4.005 12.087-10.295 15.726l-12.58 2.158-7.772 7.186c-31.305 19.273-64.877 5.76-82.834-1.499-25.911-8.43-42.295-33.792-30.867-87.955 1.957-9.289-5.065-13.421-4.608-18.468 1.042-11.045 1.207-37.614 11.648-44.124 0.969-0.603 8.375-2.469 8.339-1.938 1.006-10.752 2.048-21.522 3.054-32.238 2.615-7.149 8.869-7.954 10.679-18.048l-7.991-1.92c-3.602-7.68-10.185-23.077-16.896-27.666-5.65-1.517-11.282-3.053-16.915-4.589-19.731-8.119-41.655-17.829-61.422-26.094-1.079-0.439-2.213-0.786-3.291-1.207-24.759 32.786-39.625 73.454-39.625 117.632 0 108.032 87.881 195.913 195.895 195.913z"/><glyph unicode="" d="M94.8 322.592l-93.424 78.464-0.496-321.968 316.688 56.336-89.216 74.96c182.112 167.52 227.904-8.128 246.272-204.784 65.936 574.064-229.84 445.328-379.824 316.992z"/><glyph unicode="" d="M428.432 224h-20.080v96.176c0 43.36-16.448 83.104-43.632 112.144-27.056 29.056-65.632 47.712-108.16 47.68-42.544 0.032-81.12-18.624-108.192-47.68-27.184-29.040-43.632-68.784-43.648-112.144v-96.176h-20.816c-10.816 0-19.584-8.752-19.584-19.584v-216.8c0-10.848 8.768-19.616 19.584-19.616h344.528c10.8 0 19.584 8.768 19.584 19.632v216.8c0 10.816-8.784 19.568-19.584 19.568zM176.816 320.176c0 25.024 9.472 47.168 24.192 62.928 14.848 15.728 34.144 24.784 55.552 24.816 21.376-0.032 40.688-9.072 55.536-24.816 14.704-15.744 24.176-37.888 24.176-62.928v-96.176h-159.44v96.176z"/><glyph unicode="" d="M150.896 316.944h-112.192c-9.040 0-16.384-7.312-16.384-16.368v-80c0-9.056 7.344-16.368 16.384-16.368h112.192c9.056 0 16.432 7.312 16.432 16.368v80c0 9.056-7.376 16.368-16.432 16.368zM150.896 171.056h-79.376c-9.056 0-16.432-7.312-16.432-16.368v-170.32c-0.016-9.056 7.36-16.368 16.432-16.368h79.376c9.056 0 16.432 7.312 16.432 16.368v170.32c0 9.056-7.376 16.368-16.432 16.368zM473.328 316.944h-244.88c-9.056 0-16.368-7.312-16.368-16.368v-80c0-9.056 7.312-16.368 16.368-16.368h244.88c8.992 0 16.368 7.312 16.368 16.368v80c0 9.056-7.36 16.368-16.368 16.368zM439.52 169.376h-210.56c-9.056 0-16.368-7.344-16.368-16.4v-168.592c0-9.056 7.312-16.368 16.368-16.368h210.56c9.056 0 16.368 7.312 16.368 16.368v168.592c0 9.056-7.312 16.4-16.368 16.4zM251.952 335.68c19.12-3.504 37.568-5.536 54.816-5.536 86.688 0 133.68 46.592 133.936 90.464 0.128 28.256-20.752 58.88-68.368 59.376-63.808 0-103.312-45.056-123.872-78.496-20.944 33.312-60.624 77.472-124.56 77.472-46.256-0.464-67.2-31.088-67.008-59.328 0.176-43.888 47.248-90.512 133.936-90.512v0c18.752 0 38.88 2.128 59.872 6.336l1.248 0.224zM373.264 439.008c8-0.064 26.56-2 26.432-18.192-0.064-20.624-28.992-49.68-92.944-49.68-8.816 0-18 0.56-27.632 1.68 14.576 25.648 45.216 66.192 94.144 66.192zM190.832 370.128v0c-63.936 0-92.88 29.056-92.992 49.68-0.080 16.16 18.496 18.096 27.36 18.192 48.368 0 78.816-40.56 93.184-66.224-9.552-1.088-18.736-1.648-27.552-1.648z"/><glyph unicode="" d="M182.256 403.408c0-9.248-7.504-16.72-16.688-16.72h-9.776c-9.216 0-16.72 7.472-16.72 16.72v59.872c0 9.216 7.504 16.72 16.72 16.72h9.776c9.184 0 16.688-7.504 16.688-16.72v-59.872zM373.072 403.408c0-9.248-7.504-16.72-16.688-16.72h-9.744c-9.248 0-16.688 7.472-16.688 16.72v59.872c0 9.216 7.424 16.72 16.688 16.72h9.744c9.184 0 16.688-7.504 16.688-16.72v-59.872zM398.816 253.152l-33.936 27.664-133.68-163.872-71.312 56.688-25.28-31.728 105.184-83.648zM471.952 434h-62.432v-26.064c0-27.68-22.56-50.192-50.128-50.192h-9.808c-27.68 0-50.128 22.496-50.128 50.192v26.064h-85.504v-26.064c0-27.68-22.496-50.192-50.128-50.192h-9.76c-27.664 0-50.16 22.496-50.16 50.192v26.064h-63.808c-9.216 0-16.72-7.504-16.72-16.688v-432.592c0-9.216 7.504-16.72 16.72-16.72h431.84c9.184 0 16.688 7.504 16.688 16.72v432.592c0.016 9.184-7.488 16.688-16.672 16.688zM438.512 42.592c0-9.248-7.504-16.72-16.752-16.72h-331.504c-9.248 0-16.752 7.472-16.752 16.72v252.096c0 9.248 7.504 16.688 16.752 16.688h331.504c9.248 0 16.752-7.44 16.752-16.688v-252.096z"/></font></defs></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg"><defs><font-face units-per-em="512" ascent="480" descent="-32" /><missing-glyph horiz-adv-x="512" /><glyph unicode=" " d="" horiz-adv-x="256" /><glyph unicode="" d="M436.608 435.568c-65.68 31.424-144.064 2.832-174.976-63.84-2.16-4.64-4.016-10.448-5.664-17.2-1.648 6.752-3.504 12.56-5.632 17.2-30.944 66.672-109.248 95.264-174.944 63.84-65.6-31.424-93.744-110.96-62.832-177.648 30.928-66.672 243.344-257.84 243.344-257.84s0.016 0.224 0.048 0.576c0.048-0.352 0.064-0.576 0.064-0.576s212.512 191.168 243.44 257.84c30.896 66.688 2.832 146.224-62.848 177.648z" /><glyph unicode="" d="M362.533 425.051c-49.81-49.792-20.809-20.772-20.809-20.772l96.402-96.384c0 0-31.067-31.049 20.772 20.773s-46.611 146.194-96.365 96.384zM320.147 383.671l-227.987-227.986 0.329-0.293-54.071-146.524 149.833 50.688 0.311-0.311 0.786 0.805v0.019l227.2 227.2-96.403 96.403zM179.036 104.375l-78.811-33.28 37.047 75.044 38.345 38.363 41.764-41.783-38.345-38.345z" /><glyph unicode="" d="M255.952 480l-255.952-448h512l-256.048 448zM287.12 353.808v-65.36l-16.688-128.544h-27.088l-18.032 128.544-0.992 65.36h62.8zM224.096 64.112v64.112h64.24v-64.112h-64.24z" /><glyph unicode="" d="M363.923 112.019c-29.805-28.764-68.663-43.502-108.013-43.538-35.145 0.036-70.199 11.757-99.347 35.932-37.029 30.829-56.046 74.971-56.1 119.661 0 7.442 0.549 14.829 1.591 22.18l-60.672-11.374c-0.164-3.602-0.292-7.186-0.292-10.807-0.036-61.495 26.459-122.899 77.549-165.285 40.009-33.335 88.887-49.683 137.252-49.683h0.128c56.211 0 112.164 22.217 153.746 64.914l39.844-39.772 0.311 124.745-131.803 0.348 45.805-47.324zM393.344 389.23c-40.046 33.335-88.923 49.664-137.271 49.664-55.808 0-111.397-21.833-152.923-63.945l-37.687 34.798-0.677-120.722 130.487-0.75-46.336 48.493c29.641 28.252 68.188 42.697 107.154 42.733 35.108-0.036 70.217-11.721 99.328-35.932 37.029-30.829 56.046-74.935 56.137-119.698 0-6.437-0.457-12.892-1.225-19.365l60.435 11.593c0.036 2.615 0.164 5.212 0.164 7.772-0.036 61.549-26.514 122.899-77.587 165.357z" /><glyph unicode="" d="M95.792-32h320.4v320.080h-320.4v-320.080zM318.336 228.512c0 9.904 8.032 17.904 17.952 17.904 9.904 0 17.936-8 17.936-17.904v-188.736c0-9.888-8.032-17.92-17.936-17.92-9.92 0-17.952 8.032-17.952 17.92v188.736zM238.048 228.512c0 9.904 8.032 17.904 17.92 17.904s17.92-8 17.92-17.904v-188.736c0-9.888-8.032-17.92-17.92-17.92s-17.92 8.032-17.92 17.92v188.736zM157.6 228.512c0 9.904 8 17.904 17.92 17.904 9.888 0 17.92-8 17.92-17.904v-188.736c0-9.888-8.032-17.92-17.92-17.92-9.92 0-17.92 8.032-17.92 17.92v188.736zM423.216 416.528h-71.232v10.896c0 29.040-19.76 52.576-48.8 52.576h-94.72c-29.008 0-48.48-23.536-48.48-52.576v-10.896h-71.232c-13.696 0-24.768-11.088-24.768-24.752v-71.984h384v71.984c0 13.664-11.040 24.752-24.768 24.752zM319.936 416.528h-128.192v14.704c0.032 9.248 7.488 16.736 16.72 16.768h94.72c9.216-0.032 16.704-7.52 16.752-16.768v-14.704z" /><glyph unicode="" d="M511.52 278.496c-1.312 4.096-5.152 6.88-9.44 6.88h-180.704l-55.952 171.744c-1.344 4.096-5.136 6.88-9.44 6.88-4.272 0-8.096-2.784-9.44-6.88l-56.24-171.744h-180.384c-4.256 0-8.096-2.784-9.44-6.88-1.312-4.064 0.128-8.592 3.584-11.088l145.984-106.32-56.256-172.72c-1.328-4.096 0.128-8.592 3.616-11.12 3.456-2.496 8.208-2.496 11.664 0l146.896 106.624 146.64-106.624c1.792-1.28 3.76-1.936 5.808-1.936 2.096 0 4.144 0.656 5.856 1.936 3.568 2.528 4.96 7.008 3.6 11.12l-56.24 172.72 146.288 106.32c3.488 2.496 4.928 6.992 3.6 11.088z" /><glyph unicode="" d="M473.015 200.375v49.371l-7.003 2.268-52.882 17.244-14.116 34.103 27.154 57.381-34.908 34.907-6.583-3.309-49.555-25.198-34.103 14.117-21.394 59.757h-49.371l-2.286-6.985-17.262-52.882-34.048-14.099-57.399 27.136-34.925-34.926 3.309-6.564 25.18-49.591-14.080-34.029-59.758-21.412v-49.39l6.949-2.249 52.901-17.28 14.099-34.067-27.118-57.38 34.925-34.925 6.528 3.328 49.591 25.197 34.066-14.116 21.394-59.757h49.371l2.286 6.985 17.28 52.882 34.029 14.116 57.399-27.136 34.944 34.908-3.346 6.546-25.197 49.572 14.116 34.067 59.813 21.413zM256 154.861c-38.199 0-69.156 30.957-69.156 69.139 0 38.217 30.958 69.156 69.156 69.156 38.163 0 69.156-30.94 69.156-69.156 0-38.18-31.012-69.139-69.156-69.139z" /><glyph unicode="" d="M31.008 351.36l224.992-239.984 225.040 239.984z" /><glyph unicode="" d="M383.415 226.596l-212.571 218.587-37.285-34.981 178.286-183.277-183.278-188.452 36.48-35.657 205.659 211.456-0.201 0.201z" /><glyph unicode="" d="M52.928 345.2h406.144c11.056 0 20 8.976 20 20.016 0 11.072-8.944 20.032-20 20.032h-406.144c-11.056 0-20.016-8.96-20.016-20.032 0-11.040 8.96-20.016 20.016-20.016zM459.072 244.016h-406.144c-11.056 0-20.016-8.944-20.016-20.016s8.96-20.016 20.016-20.016h406.144c11.056 0 20 8.944 20 20.016s-8.928 20.016-20 20.016zM459.072 102.8h-406.144c-11.056 0-20.016-8.96-20.016-20.032s8.96-20.016 20.016-20.016h406.144c11.056 0 20 8.944 20 20.016s-8.928 20.032-20 20.032z" /><glyph unicode="" d="M256.144 480c-89.12 0-161.344-72.24-161.344-161.376 0-89.104 161.344-350.624 161.344-350.624s161.376 261.52 161.376 350.624c0 89.136-72.192 161.376-161.376 161.376zM256.144 269.616c-27.056 0-49.024 21.952-49.024 49.008 0 27.072 21.984 49.024 49.024 49.024 27.104 0 49.088-21.952 49.088-49.024 0-27.056-21.984-49.008-49.088-49.008z" /><glyph unicode="" d="M0 256.144h224.032v223.808h-224.032v-223.808zM288.128 479.952v-95.728h224.176v95.728h-224.176zM0-32h224.032v223.808h-224.032v-223.808zM288.128 256.144h224.176v95.728h-224.176v-95.728zM288.128 96.080h224.176v95.728h-224.176v-95.728zM288.128-32h224.176v95.712h-224.176v-95.712z" /><glyph unicode="" d="M332.764 119.003c-9.216 0-45.495-56.027-65.243-56.027-5.284 0-7.863 4.644-7.863 9.216 0 10.569 7.241 27.044 11.154 36.937l47.397 128.384c23.772 63.891-6.546 81.024-34.871 81.024-38.217 0-72.448-19.091-98.779-44.124-8.576-8.576-37.523-36.206-37.523-48.091 0-3.932 3.931-8.576 8.576-8.576 11.813 0 43.447 57.308 67.803 57.308 5.285 0 11.191-5.924 6.583-17.755l-46.080-115.968c-4.644-11.154-27.044-65.171-27.044-96.786 0-25.015 16.476-36.188 40.192-36.188 66.523 0 143.543 81.645 143.543 100.755-0.019 5.925-4.589 9.892-7.844 9.892zM319.543 439.661c-28.947 0-54.016-23.68-54.016-52.663 0-27.008 17.792-44.8 44.837-44.8 29.55 0 54.62 22.4 54.62 52.7 0 27.008-19.072 44.764-45.44 44.764z" /><glyph unicode="" d="M0 351.552h128.464v128.448h-128.464v-128.448zM191.76 351.552h128.528v128.448h-128.528v-128.448zM383.568 480v-128.448h128.496v128.448h-128.496zM0 159.744h128.464v128.464h-128.464v-128.464zM191.76 159.744h128.528v128.464h-128.528v-128.464zM383.568 159.744h128.496v128.464h-128.496v-128.464zM0-32h128.464v128h-128.464v-128zM191.76-32h128.528v128h-128.528v-128zM383.568-32h128.496v128h-128.496v-128z" /><glyph unicode="" d="M255.296 450.464c-124.688 0-225.76-101.072-225.76-225.76 0-124.672 101.072-225.76 225.76-225.76 124.672 0 225.76 101.088 225.76 225.76 0 124.688-101.072 225.76-225.76 225.76zM231.936 94.576l-125.936 128.032 32.208 25.936 72.864-57.088c29.76 35.424 96 106.032 187.312 161.984l7.696-17.792c-83.808-77.088-152.48-185.6-174.144-241.072z" /><glyph unicode="" d="M0 241.12h512v-34.064h-512v34.064z" /><glyph unicode="" d="M478.263 426.149c-142.555-87.388-245.98-197.632-292.48-252.947l-113.792 89.161-50.267-40.539 196.663-199.973c33.847 86.674 141.056 256.11 271.872 376.485l-11.995 27.813z" /><glyph unicode="" d="M220.576 83.248c-26.352 0-47.696-21.376-47.696-47.712s21.344-47.664 47.696-47.664c26.336 0 47.696 21.328 47.696 47.664s-21.36 47.712-47.696 47.712zM385.344 83.248c-26.4 0-47.76-21.376-47.76-47.712s21.344-47.664 47.76-47.664c26.288 0 47.632 21.328 47.632 47.664s-21.344 47.712-47.632 47.712zM459.856 350.32c-122.384 0-319.856 0-319.856 0s-19.152 52.608-37.392 84.864c-14.128 24.976-43.344 23.968-43.344 23.968-20.096 0-33.024-12.288-33.024-32.4 0-20.096 15.92-36.16 36.032-36.16l8.496-0.080 95.2-262.192 266.832-0.208c0 0 48.784 199.632 46.272 191.888 8.944 27.68-2.448 30.32-19.216 30.32zM166.528 257.344c-14 0-25.36 11.36-25.36 25.376s11.36 25.392 25.36 25.392c14.016 0 25.36-11.376 25.36-25.392s-11.344-25.376-25.36-25.376zM220.768 172.64c-14.016 0-25.376 11.376-25.376 25.392 0 13.984 11.36 25.36 25.376 25.36 14 0 25.36-11.376 25.36-25.36 0.016-14.016-11.36-25.392-25.36-25.392zM248.656 257.344c-14 0-25.376 11.36-25.376 25.376s11.36 25.392 25.376 25.392c14 0 25.36-11.376 25.36-25.392s-11.36-25.376-25.36-25.376zM302.896 172.64c-14 0-25.36 11.376-25.36 25.392 0 13.984 11.36 25.36 25.36 25.36 14.048 0 25.44-11.376 25.44-25.36 0-14.016-11.392-25.392-25.44-25.392zM330.848 257.344c-14 0-25.408 11.36-25.408 25.376s11.408 25.392 25.408 25.392c14 0 25.328-11.376 25.328-25.392s-11.328-25.376-25.328-25.376zM385.040 172.64c-13.984 0-25.328 11.376-25.328 25.392 0 13.984 11.36 25.36 25.328 25.36 14 0 25.408-11.376 25.408-25.36 0-14.016-11.408-25.392-25.408-25.392zM412.96 257.344c-14.016 0-25.36 11.36-25.36 25.376s11.344 25.392 25.36 25.392c14.048 0 25.376-11.376 25.376-25.392s-11.328-25.376-25.376-25.376z" /><glyph unicode="" d="M142.992 332.768c10.352 0 18.8 8.4 18.8 18.8v67.68c0 10.368-8.432 18.784-18.8 18.784-10.384 0-18.8-8.4-18.8-18.784v-67.68c0-10.4 8.416-18.8 18.8-18.8zM394.384 383.344v-0.32c7.776-6.944 12.72-17.008 12.72-28.288 0-20.816-16.88-37.712-37.744-37.712s-37.76 16.912-37.76 37.712c0 11.264 4.976 21.344 12.784 28.288v0.32h-176.416v-0.32c7.824-6.944 12.768-17.008 12.768-28.288 0-20.816-16.896-37.712-37.728-37.712-20.864 0-37.744 16.912-37.744 37.712 0 11.264 4.928 21.344 12.752 28.288v0.32h-85.536v-383.6h447.248v383.6h-85.344zM448.72 32.832h-383.152v254.72h383.152v-254.72zM369.36 332.768c10.384 0 18.784 8.4 18.784 18.8v67.68c0 10.368-8.4 18.784-18.784 18.784-10.352 0-18.816-8.4-18.816-18.784v-67.68c0-10.4 8.464-18.8 18.816-18.8zM349.216 184.128h-47.936v-47.872h47.952v47.872zM349.216 256.112h-47.936v-47.824h47.952v47.824zM349.216 114.112h-47.936v-47.872h47.952v47.872zM416.656 256.112h-47.92v-47.824h47.92v47.824zM416.656 184.128h-47.92v-47.872h47.92v47.872zM281.696 256.112h-47.872v-47.824h47.872v47.824zM146.8 184.128h-47.856v-47.872h47.856v47.872zM214.288 114.112h-47.888v-47.872h47.872v47.872zM146.8 114.112h-47.856v-47.872h47.856v47.872zM281.696 184.128h-47.872v-47.872h47.872v47.872zM281.696 114.112h-47.872v-47.872h47.872v47.872zM214.288 184.128h-47.888v-47.872h47.872v47.872zM214.288 256.112h-47.888v-47.824h47.872v47.824z" /><glyph unicode="" d="M256 444.727l-200.814-243.291h131.054v-198.144h139.575v198.144h131.017z" /><glyph unicode="" d="M325.779 246.583v198.144h-139.593v-198.144h-130.999l200.832-243.292 200.813 243.292z" /><glyph unicode="" d="M487.232 35.872c0 0-78.176 80.288-109.328 111.312-13.552 13.552-22.832 22.752-22.832 22.752 10.56 15.088 18.816 31.616 24.704 49.392 5.84 17.76 8.752 36.496 8.752 56.192 0 25.36-4.816 49.2-14.448 71.552-9.664 22.32-22.784 41.824-39.456 58.432-16.64 16.688-36.144 29.824-58.496 39.472-22.336 9.664-46.176 14.496-71.536 14.496-25.344 0-49.184-4.848-71.552-14.496-22.336-9.648-41.712-22.784-58.192-39.472-16.416-16.608-29.52-36.128-39.152-58.448-9.664-22.336-14.496-46.192-14.496-71.552 0-25.376 4.848-49.216 14.496-71.552 9.632-22.304 22.72-41.792 39.152-58.464 16.464-16.608 35.856-29.776 58.176-39.456 22.368-9.664 46.208-14.448 71.552-14.448 19.68 0 38.416 2.88 56.208 8.768 17.776 5.856 34.288 14.144 49.36 24.72 0 0 8.576-8.512 21.2-21.216 34.512-34.64 110.416-113.392 110.416-113.392 11.456-4.992 29.712 0.336 38.848 8.064 9.040 7.776 14.096 23.984 6.624 37.344zM327.792 223.28c-7.008-16.192-16.576-30.336-28.624-42.336-12.096-12.048-26.192-21.616-42.336-28.608-16.128-7.024-33.392-10.528-51.68-10.528-18.704 0-36.096 3.504-52.256 10.528-16.16 7.008-30.288 16.56-42.336 28.608-12.048 12.016-21.616 26.16-28.608 42.336-7.008 16.112-10.512 33.568-10.512 52.24 0 18.272 3.504 35.632 10.512 51.984 6.992 16.336 16.56 30.56 28.608 42.592 12.048 12.096 26.176 21.664 42.336 28.608 16.16 7.056 33.552 10.512 52.256 10.512 18.288 0 35.552-3.456 51.68-10.512 16.144-6.96 30.24-16.512 42.336-28.608 12.032-12.032 21.616-26.256 28.624-42.592 7.008-16.352 10.48-33.712 10.48-51.984 0.016-18.672-3.456-36.128-10.48-52.24z" /><glyph unicode="" d="M483.255 415.177l-36.023 35.968-191.25-191.268-191.25 191.268-35.986-35.968 191.268-191.269-191.123-191.14 35.968-35.932 191.14 191.104 191.123-191.104 35.932 35.932-191.104 191.123z" /><glyph unicode="" d="M200.21 226.889l178.213 183.315-37.248 34.981-212.608-218.588 218.459-223.78 36.389 35.657z" /><glyph unicode="" d="M256 335.168l-224.992-239.984h450.032z" /><glyph unicode="" d="M96.624 451.12v-454.24l312.928 227.12z" /><glyph unicode="" d="M102.992 224l312.912-227.12v454.24z" /><glyph unicode="" d="M0 0.464h63.984v479.536h-63.984v-479.536zM512.080 480h-415.824v-287.888h415.824l-138.208 142.032 138.208 145.856z" /><glyph unicode="" d="M512 241.12h-238.512v238.88h-34.016v-238.88h-239.472v-34.064h239.472v-239.056h34.016v239.056h238.512z" /><glyph unicode="" d="M255.968 228.064l221.488 155.84c-2.656 0.528-5.344 0.848-8.128 0.848h-426.656c-2.8 0-5.504-0.32-8.144-0.848l221.44-155.84zM256.928 168.496l-0.96 1.408-0.944-1.408-254.56 179.136c-0.176-1.6-0.464-3.2-0.464-4.816v-267.712c0-23.904 19.104-43.312 42.672-43.312h426.656c23.6 0 42.688 19.408 42.688 43.312v267.712c0 1.632-0.288 3.216-0.496 4.816l-254.592-179.136z" /><glyph unicode="" d="M127.584 31.776v127.632h-127.584v-127.632h127.584zM319.248 416.24h-126.928v-384.448h126.928v384.448zM511.584 287.472h-127.376v-255.68h127.376v255.68z" /><glyph unicode="" d="M255.296 450.464c-124.688 0-225.76-101.072-225.76-225.76 0-124.672 101.072-225.76 225.76-225.76 124.672 0 225.76 101.088 225.76 225.76 0 124.688-101.072 225.76-225.76 225.76zM372.16 144.832l-37.104-37.104-79.088 79.056-79.056-79.040-37.12 37.136 79.024 79.024-79.136 79.12 37.136 37.136 79.12-79.136 79.184 79.184 37.152-37.152-79.2-79.168 79.088-79.056z" /><glyph unicode="" d="M262.748 418.688c-113.664 2.249-207.214-67.803-208.969-156.435-0.585-30.829 9.984-59.813 28.8-84.644l-4.919 4.955c32.384-41.618-31.104-153.308-31.104-153.308l142.281 70.345c22.51-7.095 44.16-11.923 69.724-12.452 113.664-2.231 205.111 78.355 206.848 167.004 1.755 88.631-88.96 162.304-202.661 164.535z" /><glyph unicode="" d="M259.163 285.422l201.837-196.224 38.546 41.070-240.713 234.021-246.363-240.476 39.26-40.101z" /><glyph unicode="" d="M252.819 162.579l-201.82 196.224-38.528-41.070 240.677-234.021 246.4 240.476-39.332 40.101z" /><glyph unicode="" d="M256-33.248c-141.408 0-256 114.624-256 256s114.592 256 256 256c141.376 0 256-114.624 256-256s-114.608-256-256-256zM256 447.76c-124.048 0-225.008-100.96-225.008-225.008s100.96-225.024 225.008-225.024 224.992 100.96 224.992 225.008-100.928 225.024-224.992 225.024zM320.24 219.152l-15.6-12.128c-8.496-6.624-14.128-14.32-16.912-23.152-1.776-5.6-3.008-12.256-3.168-24h-59.712c0.88 24.848 3.504 39.968 7.328 49.472 3.808 9.472 13.632 20.368 29.44 32.72l16.032 12.528c5.28 4 9.536 8.32 12.752 13.024 5.872 8.064 8.784 16.976 8.784 26.656 0 11.152-3.248 21.312-9.776 30.496-6.496 9.184-18.4 13.808-35.712 13.808-17.008 0-29.056-5.68-36.16-17.008s-10.592-21.664-10.592-33.84h-63.68c1.744 41.872 16.32 70.16 43.776 87.632 17.344 11.152 38.656 16.752 63.904 16.752 33.216 0 60.784-7.936 82.752-23.808 21.968-15.84 34.8-48.432 34.8-79.6 0-19.088-6.624-26.096-16.144-39.184-5.584-7.92-16.272-18.048-32.112-30.368zM287.728 64h-63.504v63.68h63.504v-63.68z" /><glyph unicode="" d="M416.656 128v135.696h-320.672v-135.696h-95.984v199.344c0 13.76 11.168 24.912 24.944 24.912h462.144c13.744 0 24.912-11.152 24.912-24.912v-199.344h-95.344zM464.304 324.624c-11.024 0-19.92-8.928-19.92-19.936s8.896-19.952 19.92-19.952c10.992 0 19.968 8.96 19.968 19.952 0 11.008-8.992 19.936-19.968 19.936zM127.728 480h256v-96.192h-256v96.192zM160.976 31.664h191.232v192.336h31.824v-224.080h-255.984v224.080h32.912v-192.336z" /><glyph unicode="" d="M502.080 285.376h-180.704l-55.952 171.744c-1.344 4.096-5.136 6.88-9.44 6.88-4.272 0-8.096-2.784-9.44-6.88l-56.24-171.744h-180.384c-4.256 0-8.096-2.784-9.44-6.88-1.312-4.064 0.128-8.592 3.584-11.088l145.984-106.32-56.256-172.72c-1.328-4.096 0.128-8.592 3.616-11.12 3.456-2.496 8.208-2.496 11.664 0l146.896 106.624 146.64-106.624c1.792-1.28 3.76-1.936 5.808-1.936 2.096 0 4.144 0.656 5.856 1.936 3.568 2.528 4.96 7.008 3.6 11.12l-56.24 172.72 146.288 106.32c3.488 2.496 4.928 7.008 3.6 11.088-1.312 4.096-5.168 6.88-9.44 6.88zM333.424 170.256l48.208-148.064-125.632 91.36-125.968-91.44 48.256 148.128-125.168 91.136h154.576l48.256 147.376 48.016-147.376h154.832l-125.376-91.12z" /><glyph unicode="" d="M319.376 223.824v127.76h-126.752v-127.76h-89.744l153.168-188.608 153.088 188.608zM256.016 480c-141.392 0-256-114.608-256-255.984 0-141.392 114.608-256.016 256-256.016 141.376 0 256 114.624 256 256.016 0 141.376-114.624 255.984-256 255.984zM256.016 0c-123.52 0-224 100.496-224 224.016 0 123.504 100.48 223.984 224 223.984s224-100.48 224-223.984c0-123.52-100.48-224.016-224-224.016z" /><glyph unicode="" d="M255.982 440.594c-119.607 0-216.576-96.969-216.576-216.594s96.969-216.595 216.576-216.595c119.625 0 216.595 96.969 216.595 216.595s-96.951 216.595-216.595 216.595zM255.982 419.913c108.051 0 195.913-87.881 195.913-195.913 0-45.184-15.507-86.711-41.325-119.899-3.108 1.134-6.217 2.195-9.197 3.456-19.748 8.265-41.709 17.957-61.421 26.094-5.632 1.536-11.264 3.072-16.896 4.608-6.692 4.589-13.33 19.986-16.914 27.666-3.548 0.512-7.149 1.005-10.752 1.481 0.531 11.868 7.881 12.544 10.752 21.541 2.541 7.954 0.293 18.341 4.279 25.728 2.779 5.12 9.125 5.12 12.233 9.545 2.853 3.95 4.772 10.917 5.668 15.799 1.609 8.905 3.017 21.12-1.207 29.988-2.432 5.065-3.968 5.577-4.644 11.739-0.823 7.516 2.212 31.891 2.341 37.175 0.293 13.678-0.055 14.793-3.346 28.123 0 0-4.005 12.087-10.295 15.726l-12.58 2.158-7.772 7.186c-31.305 19.273-64.877 5.76-82.834-1.499-25.911-8.43-42.295-33.792-30.867-87.955 1.957-9.289-5.065-13.421-4.608-18.468 1.042-11.045 1.207-37.614 11.648-44.124 0.969-0.603 8.375-2.469 8.339-1.938 1.006-10.752 2.048-21.522 3.054-32.238 2.615-7.149 8.869-7.954 10.679-18.048l-7.991-1.92c-3.602-7.68-10.185-23.077-16.896-27.666-5.65-1.517-11.282-3.053-16.915-4.589-19.731-8.119-41.655-17.829-61.422-26.094-1.079-0.439-2.213-0.786-3.291-1.207-24.759 32.786-39.625 73.454-39.625 117.632 0 108.032 87.881 195.913 195.895 195.913z" /><glyph unicode="" d="M94.8 322.592l-93.424 78.464-0.496-321.968 316.688 56.336-89.216 74.96c182.112 167.52 227.904-8.128 246.272-204.784 65.936 574.064-229.84 445.328-379.824 316.992z" /><glyph unicode="" d="M428.432 224h-20.080v96.176c0 43.36-16.448 83.104-43.632 112.144-27.056 29.056-65.632 47.712-108.16 47.68-42.544 0.032-81.12-18.624-108.192-47.68-27.184-29.040-43.632-68.784-43.648-112.144v-96.176h-20.816c-10.816 0-19.584-8.752-19.584-19.584v-216.8c0-10.848 8.768-19.616 19.584-19.616h344.528c10.8 0 19.584 8.768 19.584 19.632v216.8c0 10.816-8.784 19.568-19.584 19.568zM176.816 320.176c0 25.024 9.472 47.168 24.192 62.928 14.848 15.728 34.144 24.784 55.552 24.816 21.376-0.032 40.688-9.072 55.536-24.816 14.704-15.744 24.176-37.888 24.176-62.928v-96.176h-159.44v96.176z" /><glyph unicode="" d="M150.896 316.944h-112.192c-9.040 0-16.384-7.312-16.384-16.368v-80c0-9.056 7.344-16.368 16.384-16.368h112.192c9.056 0 16.432 7.312 16.432 16.368v80c0 9.056-7.376 16.368-16.432 16.368zM150.896 171.056h-79.376c-9.056 0-16.432-7.312-16.432-16.368v-170.32c-0.016-9.056 7.36-16.368 16.432-16.368h79.376c9.056 0 16.432 7.312 16.432 16.368v170.32c0 9.056-7.376 16.368-16.432 16.368zM473.328 316.944h-244.88c-9.056 0-16.368-7.312-16.368-16.368v-80c0-9.056 7.312-16.368 16.368-16.368h244.88c8.992 0 16.368 7.312 16.368 16.368v80c0 9.056-7.36 16.368-16.368 16.368zM439.52 169.376h-210.56c-9.056 0-16.368-7.344-16.368-16.4v-168.592c0-9.056 7.312-16.368 16.368-16.368h210.56c9.056 0 16.368 7.312 16.368 16.368v168.592c0 9.056-7.312 16.4-16.368 16.4zM251.952 335.68c19.12-3.504 37.568-5.536 54.816-5.536 86.688 0 133.68 46.592 133.936 90.464 0.128 28.256-20.752 58.88-68.368 59.376-63.808 0-103.312-45.056-123.872-78.496-20.944 33.312-60.624 77.472-124.56 77.472-46.256-0.464-67.2-31.088-67.008-59.328 0.176-43.888 47.248-90.512 133.936-90.512v0c18.752 0 38.88 2.128 59.872 6.336l1.248 0.224zM373.264 439.008c8-0.064 26.56-2 26.432-18.192-0.064-20.624-28.992-49.68-92.944-49.68-8.816 0-18 0.56-27.632 1.68 14.576 25.648 45.216 66.192 94.144 66.192zM190.832 370.128v0c-63.936 0-92.88 29.056-92.992 49.68-0.080 16.16 18.496 18.096 27.36 18.192 48.368 0 78.816-40.56 93.184-66.224-9.552-1.088-18.736-1.648-27.552-1.648z" /><glyph unicode="" d="M182.256 403.408c0-9.248-7.504-16.72-16.688-16.72h-9.776c-9.216 0-16.72 7.472-16.72 16.72v59.872c0 9.216 7.504 16.72 16.72 16.72h9.776c9.184 0 16.688-7.504 16.688-16.72v-59.872zM373.072 403.408c0-9.248-7.504-16.72-16.688-16.72h-9.744c-9.248 0-16.688 7.472-16.688 16.72v59.872c0 9.216 7.424 16.72 16.688 16.72h9.744c9.184 0 16.688-7.504 16.688-16.72v-59.872zM398.816 253.152l-33.936 27.664-133.68-163.872-71.312 56.688-25.28-31.728 105.184-83.648zM471.952 434h-62.432v-26.064c0-27.68-22.56-50.192-50.128-50.192h-9.808c-27.68 0-50.128 22.496-50.128 50.192v26.064h-85.504v-26.064c0-27.68-22.496-50.192-50.128-50.192h-9.76c-27.664 0-50.16 22.496-50.16 50.192v26.064h-63.808c-9.216 0-16.72-7.504-16.72-16.688v-432.592c0-9.216 7.504-16.72 16.72-16.72h431.84c9.184 0 16.688 7.504 16.688 16.72v432.592c0.016 9.184-7.488 16.688-16.672 16.688zM438.512 42.592c0-9.248-7.504-16.72-16.752-16.72h-331.504c-9.248 0-16.752 7.472-16.752 16.72v252.096c0 9.248 7.504 16.688 16.752 16.688h331.504c9.248 0 16.752-7.44 16.752-16.688v-252.096z" /></font></defs></svg> \ No newline at end of file diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php index ae4604fd1c322d09f41da047fc23ae9fcff6934f..158a3ef5a771179f7fca114d3eaaf2c5f3d41fcc 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php @@ -24,6 +24,11 @@ use OAuth\OAuth1\Token\TokenInterface; */ class OauthClient extends AbstractService { + /** + * The maximum timeout for http request in seconds + */ + const DEFAULT_TIMEOUT = 120; + /** @var string|null */ protected $_oauthVerifier = null; @@ -36,6 +41,7 @@ class OauthClient extends AbstractService ) { if (!isset($httpClient)) { $httpClient = new \OAuth\Common\Http\Client\StreamClient(); + $httpClient->setTimeout(self::DEFAULT_TIMEOUT); } if (!isset($storage)) { $storage = new \OAuth\Common\Storage\Session(); diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/AddressDetailsManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/AddressDetailsManagementTest.php deleted file mode 100644 index 9081283ffa462a2520d277f2826c088e965061c6..0000000000000000000000000000000000000000 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/AddressDetailsManagementTest.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Quote\Api; - -class AddressDetailsManagementTest extends \Magento\TestFramework\TestCase\WebapiAbstract -{ - const SERVICE_VERSION = 'V1'; - const SERVICE_NAME = 'quoteAddressDetailsManagementV1'; - const RESOURCE_PATH = '/V1/carts/'; - - /** - * @var \Magento\TestFramework\ObjectManager - */ - protected $objectManager; - - protected function setUp() - { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - } - - /** - * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php - */ - public function testSaveAddresses() - { - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = $this->objectManager->create('Magento\Quote\Model\Quote'); - $quote->load('test_order_1', 'reserved_order_id'); - - $serviceInfo = [ - 'rest' => [ - 'resourcePath' => self::RESOURCE_PATH . 'mine/addresses', - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, - ], - 'soap' => [ - 'service' => self::SERVICE_NAME, - 'serviceVersion' => self::SERVICE_VERSION, - 'operation' => self::SERVICE_NAME . 'SaveAddresses', - ], - ]; - - $addressData = [ - 'firstname' => 'John', - 'lastname' => 'Smith', - 'email' => 'cat@dog.com', - 'company' => 'eBay Inc', - 'street' => ['Typical Street', 'Tiny House 18'], - 'city' => 'Big City', - 'region_id' => 12, - 'region' => 'California', - 'region_code' => 'CA', - 'postcode' => '0985432', - 'country_id' => 'US', - 'telephone' => '88776655', - 'fax' => '44332255', - ]; - $requestData = [ - 'cart_id' => $quote->getId(), - 'billingAddress' => $addressData, - 'shippingAddress' => $addressData - ]; - - $response = $this->_webApiCall($serviceInfo, $requestData); - - $this->assertArrayHasKey('shipping_methods', $response); - $this->assertCount(1, $response['shipping_methods']); - $this->assertEquals('flatrate', $response['shipping_methods'][0]['method_code']); - - $this->assertArrayHasKey('payment_methods', $response); - $this->assertCount(2, $response['payment_methods']); - $this->assertEquals('checkmo', $response['payment_methods'][0]['code']); - } -} diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php index 1380a7251302f4d63ac9f61358ecb24a6bd8643c..bef10d5a5cfb5ab0114aab0bc7e4e60d5fc4e0cc 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartTotalRepositoryTest.php @@ -77,6 +77,7 @@ class CartTotalRepositoryTest extends WebapiAbstract Totals::KEY_BASE_SHIPPING_INCL_TAX => $shippingAddress->getBaseShippingInclTax(), Totals::KEY_BASE_CURRENCY_CODE => $quote->getBaseCurrencyCode(), Totals::KEY_QUOTE_CURRENCY_CODE => $quote->getQuoteCurrencyCode(), + Totals::KEY_ITEMS_QTY => $quote->getItemsQty(), Totals::KEY_ITEMS => [$this->getQuoteItemTotalsData($quote)], ]; @@ -85,6 +86,10 @@ class CartTotalRepositoryTest extends WebapiAbstract $data = $this->formatTotalsData($data); $actual = $this->_webApiCall($this->getServiceInfoForTotalsService($cartId), $requestData); unset($actual['items'][0]['options']); + unset($actual['weee_tax_applied_amount']); + + /** TODO: cover total segments with separate test */ + unset($actual['total_segments']); if (array_key_exists('extension_attributes', $actual)) { unset($actual['extension_attributes']); } @@ -231,12 +236,17 @@ class CartTotalRepositoryTest extends WebapiAbstract Totals::KEY_BASE_SHIPPING_INCL_TAX => $shippingAddress->getBaseShippingInclTax(), Totals::KEY_BASE_CURRENCY_CODE => $quote->getBaseCurrencyCode(), Totals::KEY_QUOTE_CURRENCY_CODE => $quote->getQuoteCurrencyCode(), + Totals::KEY_ITEMS_QTY => $quote->getItemsQty(), Totals::KEY_ITEMS => [$this->getQuoteItemTotalsData($quote)], ]; $data = $this->formatTotalsData($data); $actual = $this->_webApiCall($serviceInfo); unset($actual['items'][0]['options']); + unset($actual['weee_tax_applied_amount']); + + /** TODO: cover total segments with separate test */ + unset($actual['total_segments']); if (array_key_exists('extension_attributes', $actual)) { unset($actual['extension_attributes']); } diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions.php new file mode 100644 index 0000000000000000000000000000000000000000..0cdd46da28ece5bf94756fde012f0bec0a0e7e1f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\GiftMessage\Test\Block\Cart; + +use Magento\GiftMessage\Test\Fixture\GiftMessage; +use Magento\Mtf\Block\Form; + +/** + * Class GiftOptions + * Add gift options on checkout cart order level + */ +class GiftOptions extends Form +{ + /** + * Selector for gift message on order form + * + * @var string + */ + protected $giftMessageOrderForm = ".gift-message fieldset"; + + /** + * Allow gift message on order level + * + * @var string + */ + protected $allowGiftOptions = '.title'; + + /** + * Selector for apply Gift Message button on item + * + * @var string + */ + protected $giftMessageOrderButton = ".action-update"; + + /** + * Selector for Gift Message Summary + * + * @var string + */ + protected $giftMessageSummary = ".gift-message-summary"; + + /** + * Fill gift message form on order level + * + * @param GiftMessage $giftMessage + * @return void + */ + public function fillGiftMessageOrder(GiftMessage $giftMessage) + { + /** @var \Magento\GiftMessage\Test\Block\Cart\GiftOptions\GiftMessageForm $giftMessageForm */ + if ($giftMessage->getAllowGiftMessagesForOrder() === 'Yes') { + $this->_rootElement->find($this->allowGiftOptions)->click(); + $giftMessageForm = $this->blockFactory->create( + 'Magento\GiftMessage\Test\Block\Cart\GiftOptions\GiftMessageForm', + ['element' => $this->_rootElement->find($this->giftMessageOrderForm)] + ); + $giftMessageForm->fill($giftMessage); + $this->_rootElement->find($this->giftMessageOrderButton)->click(); + $this->waitForElementVisible($this->giftMessageSummary); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline/GiftMessageForm.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions/GiftMessageForm.php similarity index 80% rename from dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline/GiftMessageForm.php rename to dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions/GiftMessageForm.php index 2c1a696e6929dc5c6bec4daa66abe309ccb4432a..a8b0c26d710726878c7a7d147fc9c1f077156fce 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline/GiftMessageForm.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions/GiftMessageForm.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\GiftMessage\Test\Block\Message\Inline; +namespace Magento\GiftMessage\Test\Block\Cart\GiftOptions; use Magento\Mtf\Block\Form; diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline/GiftMessageForm.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions/GiftMessageForm.xml similarity index 58% rename from dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline/GiftMessageForm.xml rename to dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions/GiftMessageForm.xml index 220c89ef22a04bc1c04c9a3f4542b53512d9c39b..43407c31535f56a199a96b9bcca36b21f3095fb3 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline/GiftMessageForm.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/GiftOptions/GiftMessageForm.xml @@ -8,13 +8,13 @@ <mapping strict="0"> <fields> <sender> - <selector>[id^='gift-message'][name$='[from]']</selector> + <selector>[id='gift-message-whole-from']</selector> </sender> <recipient> - <selector>[id^='gift-message'][name$='[to]']</selector> + <selector>[id='gift-message-whole-to']</selector> </recipient> <message> - <selector>[id^='gift-message'][name$='[message]']</selector> + <selector>[id='gift-message-whole-message']</selector> </message> </fields> </mapping> diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.php new file mode 100644 index 0000000000000000000000000000000000000000..78ce8fe619261744f1a8dfd817ea6980fce21a32 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\GiftMessage\Test\Block\Cart\Item; + +use Magento\GiftMessage\Test\Fixture\GiftMessage; +use Magento\Mtf\Block\Form; +use Magento\Mtf\Client\Locator; + +/** + * Add gift options on checkout cart item level + */ +class GiftOptions extends Form +{ + /** + * Selector for gift message on item form + * + * @var string + */ + protected $giftMessageItemForm = '//div[@class="gift-message"]//fieldset[ancestor::tbody[contains(.,"%s")]]'; + + /** + * Allow Gift Options for items + * + * @var string + */ + protected $allowGiftOptions = '//a[contains(@class,"action-gift")][ancestor::tbody[contains(.,"%s")]]'; + + /** + * Selector for apply Gift Message button on order + * + * @var string + */ + protected $giftMessageItemButton = ".action-update"; + + /** + * Selector for Gift Message Summary + * + * @var string + */ + protected $giftMessageSummary = '//div[@class="gift-message-summary"][ancestor::tbody[contains(.,"%s")]]'; + + /** + * Fill gift message form on item level + * + * @param GiftMessage $giftMessage + * @param array $products + * @return void + */ + public function fillGiftMessageItem(GiftMessage $giftMessage, $products = []) + { + /** @var \Magento\GiftMessage\Test\Block\Cart\GiftOptions\GiftMessageForm $giftMessageForm */ + if ($giftMessage->getAllowGiftOptionsForItems() === 'Yes') { + foreach ($products as $product) { + if ($product->getIsVirtual() !== 'Yes') { + $this->_rootElement->find( + sprintf($this->allowGiftOptions, $product->getName()), + Locator::SELECTOR_XPATH + )->click(); + $giftMessageForm = $this->blockFactory->create( + 'Magento\GiftMessage\Test\Block\Cart\GiftOptions\GiftMessageForm', + [ + 'element' => $this->_rootElement->find( + sprintf($this->giftMessageItemForm, $product->getName()), + Locator::SELECTOR_XPATH + ) + ] + ); + $giftMessageForm->fill($giftMessage); + $this->_rootElement->find($this->giftMessageItemButton)->click(); + $this->waitForElementVisible( + sprintf($this->giftMessageSummary, $product->getName()), + Locator::SELECTOR_XPATH + ); + } + } + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.xml similarity index 100% rename from dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline.xml rename to dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.xml diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline.php deleted file mode 100644 index 0c41872447b7796c0ee47861fa32e44403797dbf..0000000000000000000000000000000000000000 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Inline.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\GiftMessage\Test\Block\Message; - -use Magento\GiftMessage\Test\Fixture\GiftMessage; -use Magento\Mtf\Block\Form; -use Magento\Mtf\Client\Locator; - -/** - * Class Inline - * Checkout add gift options - */ -class Inline extends Form -{ - /** - * Selector for gift message on item form - * - * @var string - */ - protected $giftMessageItemForm = ".//li[@class='item'][contains(.,'%s')]/div[@class='options']"; - - /** - * Selector for gift message on order form - * - * @var string - */ - protected $giftMessageOrderForm = ".gift-messages-order"; - - /** - * Selector for "Gift Message" button on order - * - * @var string - */ - protected $giftMessageItemButton = ".//li[@class='item'][contains(.,'%s')]/div[@class='options']/a"; - - /** - * Selector for "Gift Message" button on item - * - * @var string - */ - protected $giftMessageOrderButton = "#allow-gift-options-for-order-container > a"; - - /** - * Fill gift message form - * - * @param GiftMessage $giftMessage - * @param array $products - * @return void - */ - public function fillGiftMessage(GiftMessage $giftMessage, $products = []) - { - $this->fill($giftMessage); - - /** @var \Magento\GiftMessage\Test\Block\Message\Inline\GiftMessageForm $giftMessageForm */ - if ($giftMessage->getAllowGiftMessagesForOrder() === 'Yes') { - $this->_rootElement->find($this->giftMessageOrderButton)->click(); - $giftMessageForm = $this->blockFactory->create( - 'Magento\GiftMessage\Test\Block\Message\Inline\GiftMessageForm', - ['element' => $this->_rootElement->find($this->giftMessageOrderForm)] - ); - $giftMessageForm->fill($giftMessage); - } - - if ($giftMessage->getAllowGiftOptionsForItems() === 'Yes') { - foreach ($products as $product) { - $this->_rootElement->find( - sprintf($this->giftMessageItemButton, $product->getName()), - Locator::SELECTOR_XPATH - )->click(); - $giftMessageForm = $this->blockFactory->create( - 'Magento\GiftMessage\Test\Block\Message\Inline\GiftMessageForm', - [ - 'element' => $this->_rootElement->find( - sprintf($this->giftMessageItemForm, $product->getName()), - Locator::SELECTOR_XPATH - ) - ] - ); - $giftMessageForm->fill($giftMessage); - } - } - } -} diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php index b3c29e2252085a4470eaeb586d78fe42b8d8109a..c680b61b485b4b7addb8334a548ea6f2c91a4121 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php @@ -57,6 +57,9 @@ class View extends Block */ public function getGiftMessage($itemName) { + if (!$this->giftMessageButtonIsVisible($itemName)) { + return []; + } $message = []; $labelsToSkip = []; $this->clickGiftMessageButton($itemName); @@ -88,4 +91,18 @@ class View extends Block Locator::SELECTOR_XPATH )->click(); } + + /** + * Click "Gift Message" for special item. + * + * @param string $itemName + * @return bool + */ + protected function giftMessageButtonIsVisible($itemName) + { + return $this->_rootElement->find( + sprintf($this->giftMessageButtonSelector, $itemName), + Locator::SELECTOR_XPATH + )->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php index a9a17c123c4c1b44d43312727d49111b29735da7..932115cdf37abb0a769342973706c00a20f05734 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php @@ -62,6 +62,10 @@ class AssertGiftMessageInFrontendOrderItems extends AbstractConstraint 'message' => $itemGiftMessage->getMessage(), ]; } + if ($product->getIsVirtual() == 'Yes') { + $expectedData = []; + } + \PHPUnit_Framework_Assert::assertEquals( $expectedData, $customerOrderView->getGiftMessageForItemBlock()->getGiftMessage($product->getName()), diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutCart.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutCart.xml new file mode 100644 index 0000000000000000000000000000000000000000..c911cebf77f4afe51df39d6159bc5ef6f2874499 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutCart.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/pages.xsd"> + <page name="CheckoutCart" mca="checkout/cart"> + <block name="giftMessagesItemBlock" class="Magento\GiftMessage\Test\Block\Cart\Item\GiftOptions" locator=".gift-options-cart-item" strategy="css selector"/> + <block name="giftMessagesOrderBlock" class="Magento\GiftMessage\Test\Block\Cart\GiftOptions" locator=".cart-gift-item" strategy="css selector"/> + </page> +</config> diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutOnepage.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutOnepage.xml deleted file mode 100644 index 0a83605791e225384c20d3572d861bfd0d31b927..0000000000000000000000000000000000000000 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutOnepage.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/** - * Copyright © 2015 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - --> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/pages.xsd"> - <page name="CheckoutOnepage" mca="checkout/onepage"> - <block name="giftMessagesBlock" class="Magento\GiftMessage\Test\Block\Message\Inline" locator=".gift-message" strategy="css selector"/> - </page> -</config> diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageStep.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageStep.php index 190de05c9eecdf1d89c29a6aeea3cc18416de37e..35c7994df9e5434e5f647e3bf5716433ce8de6de 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageStep.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageStep.php @@ -6,7 +6,7 @@ namespace Magento\GiftMessage\Test\TestStep; -use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Checkout\Test\Page\CheckoutCart; use Magento\GiftMessage\Test\Fixture\GiftMessage; use Magento\Mtf\TestStep\TestStepInterface; @@ -19,9 +19,9 @@ class AddGiftMessageStep implements TestStepInterface /** * Onepage checkout page * - * @var CheckoutOnepage + * @var CheckoutCart */ - protected $checkoutOnepage; + protected $checkoutCart; /** * Gift message fixture @@ -39,13 +39,13 @@ class AddGiftMessageStep implements TestStepInterface /** * @constructor - * @param CheckoutOnepage $checkoutOnepage + * @param CheckoutCart $checkoutCart * @param GiftMessage $giftMessage * @param array $products */ - public function __construct(CheckoutOnepage $checkoutOnepage, GiftMessage $giftMessage, array $products = []) + public function __construct(CheckoutCart $checkoutCart, GiftMessage $giftMessage, array $products = []) { - $this->checkoutOnepage = $checkoutOnepage; + $this->checkoutCart = $checkoutCart; $this->giftMessage = $giftMessage; $this->products = $products; } @@ -57,6 +57,8 @@ class AddGiftMessageStep implements TestStepInterface */ public function run() { - $this->checkoutOnepage->getGiftMessagesBlock()->fillGiftMessage($this->giftMessage, $this->products); + $this->checkoutCart->open(); + $this->checkoutCart->getGiftMessagesItemBlock()->fillGiftMessageItem($this->giftMessage, $this->products); + $this->checkoutCart->getGiftMessagesOrderBlock()->fillGiftMessageOrder($this->giftMessage, $this->products); } } diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml index de5469059a9b89883c6210b648f0783b8af43fd8..0dfdf20437f1c1d626d645680346d0d8f31f2228 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml @@ -13,10 +13,10 @@ <step name="createProducts" module="Magento_Catalog" next="createCustomer" /> <step name="createCustomer" module="Magento_Customer" next="loginCustomerOnFrontend" /> <step name="loginCustomerOnFrontend" module="Magento_Customer" next="addProductsToTheCart" /> - <step name="addProductsToTheCart" module="Magento_Checkout" next="proceedToCheckout" /> + <step name="addProductsToTheCart" module="Magento_Checkout" next="addGiftMessage" /> + <step name="addGiftMessage" module="Magento_GiftMessage" next="proceedToCheckout" /> <step name="proceedToCheckout" module="Magento_Checkout" next="fillBillingInformation" /> - <step name="fillBillingInformation" module="Magento_Checkout" next="addGiftMessage" /> - <step name="addGiftMessage" module="Magento_GiftMessage" next="fillShippingMethod" /> + <step name="fillBillingInformation" module="Magento_Checkout" next="fillShippingMethod" /> <step name="fillShippingMethod" module="Magento_Checkout" next="selectPaymentMethod" /> <step name="selectPaymentMethod" module="Magento_Checkout" next="placeOrder" /> <step name="placeOrder" module="Magento_Checkout" /> diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php index cf8a02f20f8489eebb0a4d52c3b9e4172e274bff..becd0114cd30e313f035823e5c7d42b49db79338 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php @@ -5,9 +5,11 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ + /** @var \Magento\Customer\Model\Address $customerAddress */ $customerAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->create('Magento\Customer\Model\Address'); + $customerAddress->isObjectNew(true); $customerAddress->setData( [ diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php index b715451581bf1796b04556498e444ae0a1503267..72b4ffaa01c12d3e2d6dc1166c9f38ed5556bac3 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php @@ -11,6 +11,7 @@ require 'customer_address.php'; /** @var \Magento\Customer\Model\Address $customerAddress */ $customerAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->create('Magento\Customer\Model\Address'); + $customerAddress->isObjectNew(true); $customerAddress->setData( [ diff --git a/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d2869eb4f6c6a3148ae69e322a02353addd06ab4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php @@ -0,0 +1,160 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Directory\Model\Country\Postcode; + +use Magento\TestFramework\Helper\Bootstrap; + +class ValidatorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Directory\Model\Country\Postcode\ValidatorInterface + */ + protected $validator; + + protected function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->validator = $objectManager->create('Magento\Directory\Model\Country\Postcode\ValidatorInterface'); + } + + /** + * @dataProvider getPostcodesDataProvider + */ + public function testPostCodes($countryId, $validPostcode) + { + try { + $this->assertTrue($this->validator->validate($validPostcode, $countryId)); + $this->assertFalse($this->validator->validate('INVALID-100', $countryId)); + } catch (\InvalidArgumentException $ex) { + //skip validation test for none existing countryId + } + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Provided countryId does not exist. + */ + public function testPostCodesThrowsExceptionIfCountryDoesNotExist() + { + $this->validator->validate('12345', 'INVALID-CODE'); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getPostcodesDataProvider() + { + return [ + ['countryId' => 'DZ', 'postcode' => '12345'], + ['countryId' => 'AS', 'postcode' => '12345'], + ['countryId' => 'AR', 'postcode' => '1234'], + ['countryId' => 'AM', 'postcode' => '123456'], + ['countryId' => 'AU', 'postcode' => '1234'], + ['countryId' => 'AT', 'postcode' => '1234'], + ['countryId' => 'AZ', 'postcode' => '1234'], + ['countryId' => 'AZ', 'postcode' => '123456'], + ['countryId' => 'BD', 'postcode' => '1234'], + ['countryId' => 'BY', 'postcode' => '123456'], + ['countryId' => 'BE', 'postcode' => '1234'], + ['countryId' => 'BA', 'postcode' => '12345'], + ['countryId' => 'BR', 'postcode' => '12345'], + ['countryId' => 'BR', 'postcode' => '12345-678'], + ['countryId' => 'BN', 'postcode' => 'PS1234'], + ['countryId' => 'BG', 'postcode' => '1234'], + ['countryId' => 'CA', 'postcode' => 'P9M 3T6'], + ['countryId' => 'IC', 'postcode' => '12345'], + ['countryId' => 'CN', 'postcode' => '123456'], + ['countryId' => 'HR', 'postcode' => '12345'], + ['countryId' => 'CU', 'postcode' => '12345'], + ['countryId' => 'CY', 'postcode' => '1234'], + ['countryId' => 'CZ', 'postcode' => '123 45'], + ['countryId' => 'DK', 'postcode' => '1234'], + ['countryId' => 'EE', 'postcode' => '12345'], + ['countryId' => 'FI', 'postcode' => '12345'], + ['countryId' => 'FR', 'postcode' => '12345'], + ['countryId' => 'GF', 'postcode' => '12345'], + ['countryId' => 'GE', 'postcode' => '1234'], + ['countryId' => 'DE', 'postcode' => '12345'], + ['countryId' => 'GR', 'postcode' => '123 45'], + ['countryId' => 'GL', 'postcode' => '1234'], + ['countryId' => 'GP', 'postcode' => '12345'], + ['countryId' => 'GU', 'postcode' => '12345'], + ['countryId' => 'GG', 'postcode' => 'PL5 7TH'], + ['countryId' => 'HU', 'postcode' => '1234'], + ['countryId' => 'IS', 'postcode' => '123'], + ['countryId' => 'IN', 'postcode' => '123456'], + ['countryId' => 'ID', 'postcode' => '12345'], + ['countryId' => 'IL', 'postcode' => '12345'], + ['countryId' => 'IT', 'postcode' => '12345'], + ['countryId' => 'JP', 'postcode' => '123-4567'], + ['countryId' => 'JP', 'postcode' => '123'], + ['countryId' => 'JE', 'postcode' => 'TY8 9PL'], + ['countryId' => 'KZ', 'postcode' => '123456'], + ['countryId' => 'KE', 'postcode' => '12345'], + ['countryId' => 'KR', 'postcode' => '123-456'], + ['countryId' => 'KG', 'postcode' => '123456'], + ['countryId' => 'LV', 'postcode' => '1234'], + ['countryId' => 'LI', 'postcode' => '1234'], + ['countryId' => 'LT', 'postcode' => '12345'], + ['countryId' => 'LU', 'postcode' => '1234'], + ['countryId' => 'MK', 'postcode' => '1234'], + ['countryId' => 'MG', 'postcode' => '123'], + ['countryId' => 'MY', 'postcode' => '12345'], + ['countryId' => 'MV', 'postcode' => '12345'], + ['countryId' => 'MV', 'postcode' => '1234'], + ['countryId' => 'MT', 'postcode' => 'WRT 123'], + ['countryId' => 'MT', 'postcode' => 'WRT 45'], + ['countryId' => 'MH', 'postcode' => '12345'], + ['countryId' => 'MQ', 'postcode' => '12345'], + ['countryId' => 'MX', 'postcode' => '12345'], + ['countryId' => 'MD', 'postcode' => '1234'], + ['countryId' => 'MC', 'postcode' => '12345'], + ['countryId' => 'MN', 'postcode' => '123456'], + ['countryId' => 'MA', 'postcode' => '12345'], + ['countryId' => 'NL', 'postcode' => '1234 TR'], + ['countryId' => 'NO', 'postcode' => '1234'], + ['countryId' => 'PK', 'postcode' => '12345'], + ['countryId' => 'PH', 'postcode' => '1234'], + ['countryId' => 'PL', 'postcode' => '12-345'], + ['countryId' => 'PT', 'postcode' => '1234'], + ['countryId' => 'PT', 'postcode' => '1234-567'], + ['countryId' => 'PR', 'postcode' => '12345'], + ['countryId' => 'RE', 'postcode' => '12345'], + ['countryId' => 'RO', 'postcode' => '123456'], + ['countryId' => 'RU', 'postcode' => '123456'], + ['countryId' => 'MP', 'postcode' => '12345'], + ['countryId' => 'CS', 'postcode' => '12345'], + ['countryId' => 'SG', 'postcode' => '123456'], + ['countryId' => 'SK', 'postcode' => '123 45'], + ['countryId' => 'SI', 'postcode' => '1234'], + ['countryId' => 'ZA', 'postcode' => '1234'], + ['countryId' => 'ES', 'postcode' => '12345'], + ['countryId' => 'XY', 'postcode' => '12345'], + ['countryId' => 'SZ', 'postcode' => 'R123'], + ['countryId' => 'SE', 'postcode' => '123 45'], + ['countryId' => 'CH', 'postcode' => '1234'], + ['countryId' => 'TW', 'postcode' => '123'], + ['countryId' => 'TW', 'postcode' => '12345'], + ['countryId' => 'TJ', 'postcode' => '123456'], + ['countryId' => 'TH', 'postcode' => '12345'], + ['countryId' => 'TR', 'postcode' => '12345'], + ['countryId' => 'TM', 'postcode' => '123456'], + ['countryId' => 'UA', 'postcode' => '12345'], + ['countryId' => 'GB', 'postcode' => 'PL12 3RT'], + ['countryId' => 'GB', 'postcode' => 'P1L 2RT'], + ['countryId' => 'GB', 'postcode' => 'QW1 2RT'], + ['countryId' => 'GB', 'postcode' => 'QW1R 2TG'], + ['countryId' => 'GB', 'postcode' => 'L12 3PL'], + ['countryId' => 'GB', 'postcode' => 'Q1 2PL'], + ['countryId' => 'US', 'postcode' => '12345-6789'], + ['countryId' => 'US', 'postcode' => '12345'], + ['countryId' => 'UY', 'postcode' => '12345'], + ['countryId' => 'UZ', 'postcode' => '123456'], + ['countryId' => 'VI', 'postcode' => '12345'], + ]; + } +} diff --git a/dev/tests/performance/benchmark.jmx b/dev/tests/performance/benchmark.jmx index 6fda461b91e00c23daa17bf64a3f578f456c5ffc..92ac0e689898c76a1dd489ec125330ad1f4d3c61 100644 --- a/dev/tests/performance/benchmark.jmx +++ b/dev/tests/performance/benchmark.jmx @@ -892,19 +892,16 @@ <stringProp name="ConstantTimer.delay">${sleep_between_steps}</stringProp> </ConstantTimer> <hashTree/> - <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Checkout billing/shipping addresses" enabled="true"> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Checkout shipping information" enabled="true"> <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"shippingAddress":{"company":"","fax":"","city":"Culver City","firstname":"Name","lastname":"Lastname"
 -,"street":{"0":"10441 Jefferson Blvd, ste 200","1":""},"telephone":"1-310-945-0345","postcode":"90232"
 -,"region_id":"12","country_id":"US","region":"","save_in_address_book":"1","email":"test@example.com"
 -,"same_as_billing":1},"billingAddress":{"company":"","fax":"","city":"Culver City","firstname":"Name"
 -,"lastname":"Lastname","street":{"0":"10441 Jefferson Blvd, ste 200","1":""},"telephone":"1-310-945-0345"
 -,"postcode":"90232","region_id":"12","country_id":"US","region":"","save_in_address_book":"1","email"
 -:"test@example.com","same_as_billing":1},"additionalData":{"extensionAttributes":{}}}</stringProp> + <stringProp name="Argument.value">{"addressInformation":{"shipping_address":{"countryId":"US","regionId":"12","regionCode":"CA","region"
 +:"California","street":["10441 Jefferson Blvd","ste 200"],"company":"","telephone":"1-310-945-0345","fax"
 +:"","postcode":"90232","city":"Culver City","firstname":"Firstname","lastname":"Lastname","saveInAddressBook"
 +:true},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -915,7 +912,7 @@ <stringProp name="HTTPSampler.response_timeout"></stringProp> <stringProp name="HTTPSampler.protocol">http</stringProp> <stringProp name="HTTPSampler.contentEncoding">UTF-8</stringProp> - <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/addresses</stringProp> + <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/shipping-information</stringProp> <stringProp name="HTTPSampler.method">POST</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> @@ -948,7 +945,7 @@ <hashTree/> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert success" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="-768590464">{"shipping_methods":</stringProp> + <stringProp name="-1494218646">{"payment_methods":</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> @@ -960,15 +957,17 @@ <stringProp name="ConstantTimer.delay">${sleep_between_steps}</stringProp> </ConstantTimer> <hashTree/> - <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Checkout shipping/payment method" enabled="true"> + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Checkout payment information" enabled="true"> <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> <collectionProp name="Arguments.arguments"> <elementProp name="" elementType="HTTPArgument"> <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value">{"cartId":"${cart_id}","paymentMethod":{"method":"checkmo","po_number":null,"cc_owner"
 -:null,"cc_number":null,"cc_type":null,"cc_exp_year":null,"cc_exp_month":null,"additional_data":null}
 -,"shippingCarrierCode":"flatrate","shippingMethodCode":"flatrate"}</stringProp> + <stringProp name="Argument.value">{"cartId":"${cart_id}","paymentMethod":{"method":"checkmo","po_number":null,"cc_owner":null,"cc_number":null
 +,"cc_type":null,"cc_exp_year":null,"cc_exp_month":null,"additional_data":null},"billingAddress":{"countryId"
 +:"US","regionId":"12","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd","ste 200"
 +],"company":"","telephone":"1-310-945-0345","fax":"","postcode":"90232","city":"Culver City","firstname"
 +:"Firstname","lastname":"Lastname","saveInAddressBook":true}}</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> @@ -979,70 +978,8 @@ <stringProp name="HTTPSampler.response_timeout"></stringProp> <stringProp name="HTTPSampler.protocol">http</stringProp> <stringProp name="HTTPSampler.contentEncoding">UTF-8</stringProp> - <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/collect-totals</stringProp> - <stringProp name="HTTPSampler.method">PUT</stringProp> - <boolProp name="HTTPSampler.follow_redirects">true</boolProp> - <boolProp name="HTTPSampler.auto_redirects">false</boolProp> - <boolProp name="HTTPSampler.use_keepalive">true</boolProp> - <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> - <boolProp name="HTTPSampler.monitor">false</boolProp> - <stringProp name="HTTPSampler.embedded_url_re"></stringProp> - </HTTPSamplerProxy> - <hashTree> - <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> - <collectionProp name="HeaderManager.headers"> - <elementProp name="" elementType="Header"> - <stringProp name="Header.name">Referer</stringProp> - <stringProp name="Header.value">http://mage2.com/checkout/onepage/</stringProp> - </elementProp> - <elementProp name="" elementType="Header"> - <stringProp name="Header.name">Content-Type</stringProp> - <stringProp name="Header.value">application/json; charset=UTF-8 </stringProp> - </elementProp> - <elementProp name="" elementType="Header"> - <stringProp name="Header.name">Accept</stringProp> - <stringProp name="Header.value">application/json</stringProp> - </elementProp> - <elementProp name="" elementType="Header"> - <stringProp name="Header.name">X-Requested-With</stringProp> - <stringProp name="Header.value">XMLHttpRequest</stringProp> - </elementProp> - </collectionProp> - </HeaderManager> - <hashTree/> - <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true"> - <collectionProp name="Asserion.test_strings"> - <stringProp name="629313218">{"grand_total":</stringProp> - </collectionProp> - <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> - <boolProp name="Assertion.assume_success">false</boolProp> - <intProp name="Assertion.test_type">2</intProp> - </ResponseAssertion> - <hashTree/> - </hashTree> - <ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Constant Timer" enabled="true"> - <stringProp name="ConstantTimer.delay">${sleep_between_steps}</stringProp> - </ConstantTimer> - <hashTree/> - <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Checkout place order" enabled="true"> - <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> - <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> - <collectionProp name="Arguments.arguments"> - <elementProp name="" elementType="HTTPArgument"> - <boolProp name="HTTPArgument.always_encode">false</boolProp> - <stringProp name="Argument.value"></stringProp> - <stringProp name="Argument.metadata">=</stringProp> - </elementProp> - </collectionProp> - </elementProp> - <stringProp name="HTTPSampler.domain"></stringProp> - <stringProp name="HTTPSampler.port"></stringProp> - <stringProp name="HTTPSampler.connect_timeout"></stringProp> - <stringProp name="HTTPSampler.response_timeout"></stringProp> - <stringProp name="HTTPSampler.protocol">http</stringProp> - <stringProp name="HTTPSampler.contentEncoding">UTF-8</stringProp> - <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/order</stringProp> - <stringProp name="HTTPSampler.method">PUT</stringProp> + <stringProp name="HTTPSampler.path">${base_path}rest/default/V1/carts/mine/payment-information</stringProp> + <stringProp name="HTTPSampler.method">POST</stringProp> <boolProp name="HTTPSampler.follow_redirects">true</boolProp> <boolProp name="HTTPSampler.auto_redirects">false</boolProp> <boolProp name="HTTPSampler.use_keepalive">true</boolProp> @@ -1143,7 +1080,7 @@ <hashTree> <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert success" enabled="true"> <collectionProp name="Asserion.test_strings"> - <stringProp name="890055751">You are signed out.</stringProp> + <stringProp name="1723813687">You are signed out.</stringProp> </collectionProp> <stringProp name="Assertion.test_field">Assertion.response_data</stringProp> <boolProp name="Assertion.assume_success">false</boolProp> diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php index c563b677620382c5b08c868fec60488247f6d359..e342206fe0b6e802e9ccf4e216e16d0cbcddbd22 100755 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php @@ -3657,6 +3657,8 @@ return [ ['Magento\Centinel\Test\TestCase\CentinelPaymentsValidCcTest'], ['Magento\Centinel\CreateOrderTest'], ['Magento\Payment\Model\Checks\PaymentMethodChecksInterface', 'Magento\Payment\Model\MethodInterface'], + ['Magento\Ui\DataProvider\EavValidationRul', 'Magento\Ui\DataProvider\EavValidationRules'], + ['Magento\Framework\View\Element\UiComponent\JsConfigInterface'], ['Magento\GiftMessage\Model\Plugin\TotalsDataProcessorPlugin'], ['Magento\Catalog\Model\Product\Attribute\Backend\Startdate', 'Magento\Catalog\Model\Attribute\Backend\Startdate'], ]; diff --git a/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php b/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php index 3573fdb87f541e900636e9ed6d921649e35fedc7..737a51721f8a75798c56ec4fd6547afed332e3cc 100755 --- a/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php +++ b/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php @@ -577,6 +577,7 @@ abstract class AbstractDb extends \Magento\Framework\Data\Collection $item->setIdFieldName($this->getIdFieldName()); } $item->addData($row); + $this->beforeAddLoadedItem($item); $this->addItem($item); } } @@ -585,6 +586,17 @@ abstract class AbstractDb extends \Magento\Framework\Data\Collection return $this; } + /** + * Let do something before add loaded item in collection + * + * @param \Magento\Framework\Object $item + * @return \Magento\Framework\Object + */ + protected function beforeAddLoadedItem(\Magento\Framework\Object $item) + { + return $item; + } + /** * Returns a collection item that corresponds to the fetched row * and moves the internal data pointer ahead diff --git a/lib/internal/Magento/Framework/Model/AbstractModel.php b/lib/internal/Magento/Framework/Model/AbstractModel.php index 1c702229061d364526c8e48def6afc36be4b1227..72f6357f06c9fd8a59a3afdb75da20bb7219efe9 100644 --- a/lib/internal/Magento/Framework/Model/AbstractModel.php +++ b/lib/internal/Magento/Framework/Model/AbstractModel.php @@ -3,7 +3,6 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Framework\Model; use Magento\Framework\Phrase; @@ -937,4 +936,14 @@ abstract class AbstractModel extends \Magento\Framework\Object { return $this->storedData; } + + /** + * Returns _eventPrefix + * + * @return string + */ + public function getEventPrefix() + { + return $this->_eventPrefix; + } } diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php b/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php index 87732d71a0f068818c993fd836d8baa8bb9d9d3a..824b0d5128a8d3329b0a85037d00cd4cf5b1bd6b 100644 --- a/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php +++ b/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php @@ -13,6 +13,7 @@ use Magento\Framework\Exception\LocalizedException; * Abstract resource model class * @SuppressWarnings(PHPMD.NumberOfChildren) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractResource { @@ -394,6 +395,7 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso * @param \Magento\Framework\Model\AbstractModel $object * @return $this * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws \Exception * @api */ public function save(\Magento\Framework\Model\AbstractModel $object) @@ -401,13 +403,16 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso if ($object->isDeleted()) { return $this->delete($object); } - if (!$object->hasDataChanges()) { - return $this; - } $this->beginTransaction(); try { + if (!$this->isModified($object)) { + $this->processNotModifiedSave($object); + $this->commit(); + $object->setHasDataChanges(false); + return $this; + } $object->validateBeforeSave(); $object->beforeSave(); if ($object->isSaveAllowed()) { @@ -415,53 +420,13 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso $this->_beforeSave($object); $this->_checkUnique($object); $this->objectRelationProcessor->validateDataIntegrity($this->getMainTable(), $object->getData()); - if ($object->getId() !== null && (!$this->_useIsObjectNew || !$object->isObjectNew())) { - $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId()); - /** - * Not auto increment primary key support - */ - if ($this->_isPkAutoIncrement) { - $data = $this->prepareDataForUpdate($object); - if (!empty($data)) { - $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition); - } - } else { - $select = $this->_getWriteAdapter()->select()->from( - $this->getMainTable(), - [$this->getIdFieldName()] - )->where( - $condition - ); - if ($this->_getWriteAdapter()->fetchOne($select) !== false) { - $data = $this->prepareDataForUpdate($object); - if (!empty($data)) { - $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition); - } - } else { - $this->_getWriteAdapter()->insert( - $this->getMainTable(), - $this->_prepareDataForSave($object) - ); - } - } + if ($this->isObjectNotNew($object)) { + $this->updateObject($object); } else { - $bind = $this->_prepareDataForSave($object); - if ($this->_isPkAutoIncrement) { - unset($bind[$this->getIdFieldName()]); - } - $this->_getWriteAdapter()->insert($this->getMainTable(), $bind); - - $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable())); - - if ($this->_useIsObjectNew) { - $object->isObjectNew(false); - } + $this->saveNewObject($object); } - $this->unserializeFields($object); - $this->_afterSave($object); - - $object->afterSave(); + $this->processAfterSaves($object); } $this->addCommitCallback([$object, 'afterCommitCallback'])->commit(); $object->setHasDataChanges(false); @@ -798,4 +763,111 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso return $data; } + + /** + * Check if object is new + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return bool + */ + protected function isObjectNotNew(\Magento\Framework\Model\AbstractModel $object) + { + return $object->getId() !== null && (!$this->_useIsObjectNew || !$object->isObjectNew()); + } + + /** + * Save New Object + * + * @param \Magento\Framework\Model\AbstractModel $object + * @throws LocalizedException + * @return void + */ + protected function saveNewObject(\Magento\Framework\Model\AbstractModel $object) + { + $bind = $this->_prepareDataForSave($object); + if ($this->_isPkAutoIncrement) { + unset($bind[$this->getIdFieldName()]); + } + $this->_getWriteAdapter()->insert($this->getMainTable(), $bind); + + $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable())); + + if ($this->_useIsObjectNew) { + $object->isObjectNew(false); + } + } + + /** + * Update existing object + * + * @param \Magento\Framework\Model\AbstractModel $object + * @throws LocalizedException + * @return void + */ + protected function updateObject(\Magento\Framework\Model\AbstractModel $object) + { + $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId()); + /** + * Not auto increment primary key support + */ + if ($this->_isPkAutoIncrement) { + $data = $this->prepareDataForUpdate($object); + if (!empty($data)) { + $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition); + } + } else { + $select = $this->_getWriteAdapter()->select()->from( + $this->getMainTable(), + [$this->getIdFieldName()] + )->where( + $condition + ); + if ($this->_getWriteAdapter()->fetchOne($select) !== false) { + $data = $this->prepareDataForUpdate($object); + if (!empty($data)) { + $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition); + } + } else { + $this->_getWriteAdapter()->insert( + $this->getMainTable(), + $this->_prepareDataForSave($object) + ); + } + } + } + + /** + * Sequences of after save call + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return void + */ + protected function processAfterSaves(\Magento\Framework\Model\AbstractModel $object) + { + $this->_afterSave($object); + $object->afterSave(); + } + + /** + * Check if object was modified + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return bool + */ + protected function isModified(\Magento\Framework\Model\AbstractModel $object) + { + return $object->hasDataChanges(); + } + + /** + * Process object which was modified + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return $this + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function processNotModifiedSave(\Magento\Framework\Model\AbstractModel $object) + { + return $this; + } } diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/AbstractDb.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/AbstractDb.php new file mode 100644 index 0000000000000000000000000000000000000000..78c6a1b4c05bb70ed2e0f3363b42e0755cde4f89 --- /dev/null +++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/AbstractDb.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Model\Resource\Db\VersionControl; + +/** + * Class AbstractDb with snapshot saving and relation save processing + */ +abstract class AbstractDb extends \Magento\Framework\Model\Resource\Db\AbstractDb +{ + /** + * @var Snapshot + */ + protected $entitySnapshot; + + /** + * @var RelationComposite + */ + protected $entityRelationComposite; + + /** + * @param Snapshot $entitySnapshot + * @param RelationComposite $entityRelationComposite + * @param \Magento\Framework\Model\Resource\Db\Context $context + * @param string $resourcePrefix + */ + public function __construct( + \Magento\Framework\Model\Resource\Db\Context $context, + Snapshot $entitySnapshot, + RelationComposite $entityRelationComposite, + $resourcePrefix = null + ) { + $this->entitySnapshot = $entitySnapshot; + $this->entityRelationComposite = $entityRelationComposite; + parent::__construct($context, $resourcePrefix); + } + + /** + * @inheritdoc + */ + protected function _afterLoad(\Magento\Framework\Model\AbstractModel $object) + { + $this->entitySnapshot->registerSnapshot($object); + return parent::_afterLoad($object); + } + + /** + * @inheritdoc + */ + protected function processAfterSaves(\Magento\Framework\Model\AbstractModel $object) + { + $this->_afterSave($object); + $this->entitySnapshot->registerSnapshot($object); + $object->afterSave(); + $this->entityRelationComposite->processRelations($object); + } + + /** + * @inheritdoc + */ + protected function isModified(\Magento\Framework\Model\AbstractModel $object) + { + return $this->entitySnapshot->isModified($object); + } + + /** + * @inheritdoc + */ + protected function processNotModifiedSave(\Magento\Framework\Model\AbstractModel $object) + { + $this->entityRelationComposite->processRelations($object); + return $this; + } +} diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Collection.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Collection.php new file mode 100644 index 0000000000000000000000000000000000000000..84f2334021e834c56d4aaa436c426a4eaf49d906 --- /dev/null +++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Collection.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Model\Resource\Db\VersionControl; + +/** + * Class Collection + */ +abstract class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection +{ + /** + * @var Snapshot + */ + protected $entitySnapshot; + + /** + * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory + * @param \Psr\Log\LoggerInterface $logger + * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy + * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param Snapshot $entitySnapshot + * @param \Zend_Db_Adapter_Abstract $connection + * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource + */ + public function __construct( + \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory, + \Psr\Log\LoggerInterface $logger, + \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, + \Magento\Framework\Event\ManagerInterface $eventManager, + Snapshot $entitySnapshot, + $connection = null, + \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null + ) { + $this->entitySnapshot = $entitySnapshot; + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $connection, + $resource + ); + } + + /** + * @inheritdoc + */ + public function fetchItem() + { + $item = parent::fetchItem(); + if ($item) { + $this->entitySnapshot->registerSnapshot($item); + } + return $item; + } + + /** + * @inheritdoc + */ + protected function beforeAddLoadedItem(\Magento\Framework\Object $item) + { + $this->entitySnapshot->registerSnapshot($item); + return $item; + } +} diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Metadata.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Metadata.php new file mode 100644 index 0000000000000000000000000000000000000000..b761d22717f2f0ecb5fe99f5b3c15e43405f58c4 --- /dev/null +++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Metadata.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Model\Resource\Db\VersionControl; + +/** + * Class Metadata represents a list of entity fields that are applicable for persistence operations + */ +class Metadata +{ + /** + * @var array + */ + protected $metadataInfo = []; + + /** + * Returns list of entity fields that are applicable for persistence operations + * + * @param \Magento\Framework\Object $entity + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getFields(\Magento\Framework\Object $entity) + { + $entityClass = get_class($entity); + if (!isset($this->metadataInfo[$entityClass])) { + $this->metadataInfo[$entityClass] = + array_fill_keys( + array_keys( + $entity->getResource()->getReadConnection()->describeTable( + $entity->getResource()->getMainTable() + ) + ), + null + ); + } + return $this->metadataInfo[$entityClass]; + } +} diff --git a/app/code/Magento/Sales/Model/Resource/EntityRelationComposite.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationComposite.php similarity index 81% rename from app/code/Magento/Sales/Model/Resource/EntityRelationComposite.php rename to lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationComposite.php index 3c367791a20f82990084b87525e54e77455596e2..42a2496f284447fd7dcec95dda0507c8987df2fc 100644 --- a/app/code/Magento/Sales/Model/Resource/EntityRelationComposite.php +++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationComposite.php @@ -3,16 +3,15 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ +namespace Magento\Framework\Model\Resource\Db\VersionControl; -namespace Magento\Sales\Model\Resource; - -use Magento\Sales\Model\AbstractModel; +use Magento\Framework\Model\AbstractModel; use Magento\Framework\Event\ManagerInterface as EventManager; /** - * Class EntityRelationComposite + * Class RelationComposite */ -class EntityRelationComposite +class RelationComposite { /** * @var array @@ -37,13 +36,15 @@ class EntityRelationComposite } /** + * Process model's relations saves + * * @param AbstractModel $object * @return void */ public function processRelations(AbstractModel $object) { foreach ($this->relationProcessors as $processor) { - /**@var $processor \Magento\Sales\Model\Resource\EntityRelationInterface*/ + /**@var $processor RelationInterface*/ $processor->processRelation($object); } $this->eventManager->dispatch( diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationInterface.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..b16d44509381ae2231c707610f51e6df26daa998 --- /dev/null +++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationInterface.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Model\Resource\Db\VersionControl; + +/** + * Interface RelationInterface + */ +interface RelationInterface +{ + /** + * Process object relations + * + * @param \Magento\Framework\Model\AbstractModel $object + * @return void + */ + public function processRelation(\Magento\Framework\Model\AbstractModel $object); +} diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Snapshot.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Snapshot.php new file mode 100644 index 0000000000000000000000000000000000000000..dc837426020a4361561a6a5d013367bb1f0e659f --- /dev/null +++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Snapshot.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Model\Resource\Db\VersionControl; + +/** + * Class Snapshot register snapshot of entity data, for tracking changes + */ +class Snapshot +{ + /** + * Array of snapshots of entities data + * + * @var array + */ + protected $snapshotData = []; + + /** + * @var Metadata + */ + protected $metadata; + + /** + * Initialization + * + * @param Metadata $metadata + */ + public function __construct( + Metadata $metadata + ) { + $this->metadata = $metadata; + } + + /** + * Register snapshot of entity data, for tracking changes + * + * @param \Magento\Framework\Object $entity + * @return void + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + public function registerSnapshot(\Magento\Framework\Object $entity) + { + $metaData = $this->metadata->getFields($entity); + $filteredData = array_intersect_key($entity->getData(), $metaData); + $data = array_merge($metaData, $filteredData); + $this->snapshotData[get_class($entity)][$entity->getId()] = $data; + } + + /** + * Check is current entity has changes, by comparing current object state with stored snapshot + * + * @param \Magento\Framework\Object $entity + * @return bool + */ + public function isModified(\Magento\Framework\Object $entity) + { + if (!$entity->getId()) { + return true; + } + + $entityClass = get_class($entity); + if (!isset($this->snapshotData[$entityClass][$entity->getId()])) { + return true; + } + foreach ($this->snapshotData[$entityClass][$entity->getId()] as $field => $value) { + if ($entity->getDataByKey($field) != $value) { + return true; + } + } + + return false; + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityMetadataTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/MetadataTest.php similarity index 80% rename from app/code/Magento/Sales/Test/Unit/Model/Resource/EntityMetadataTest.php rename to lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/MetadataTest.php index bfb0c1ab8c0325d064ad3ce6cd663fe07cc86edf..553ea15c2be9a1d8324d10ac14981d10bbc9da29 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityMetadataTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/MetadataTest.php @@ -3,22 +3,22 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Sales\Test\Unit\Model\Resource; +namespace Magento\Framework\Model\Test\Unit\Resource\Db\VersionControl; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** - * Class EntityMetadataTest + * Class Version Control MetadataTest */ -class EntityMetadataTest extends \PHPUnit_Framework_TestCase +class MetadataTest extends \PHPUnit_Framework_TestCase { /** - * @var \Magento\Sales\Model\Resource\EntityMetadata + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Metadata */ protected $entityMetadata; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Sales\Model\AbstractModel + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel */ protected $model; @@ -39,7 +39,7 @@ class EntityMetadataTest extends \PHPUnit_Framework_TestCase { $objectManager = new ObjectManager($this); $this->model = $this->getMock( - 'Magento\Sales\Model\AbstractModel', + 'Magento\Framework\Model\AbstractModel', [], [], '', @@ -63,13 +63,15 @@ class EntityMetadataTest extends \PHPUnit_Framework_TestCase ); $this->model->expects($this->any())->method('getResource')->willReturn($this->resource); $this->resource->expects($this->any())->method('getReadConnection')->willReturn($this->connection); - $this->entityMetadata = $objectManager->getObject('Magento\Sales\Model\Resource\EntityMetadata'); + $this->entityMetadata = $objectManager->getObject( + 'Magento\Framework\Model\Resource\Db\VersionControl\Metadata' + ); } public function testGetFields() { $mainTable = 'main_table'; - $expectedDescribedTable = 'described_table'; + $expectedDescribedTable = ['described_table' => null]; $this->resource->expects($this->any())->method('getMainTable')->willReturn($mainTable); $this->connection->expects($this->once())->method('describeTable')->with($mainTable)->willReturn( $expectedDescribedTable diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityRelationCompositeTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/RelationCompositeTest.php similarity index 56% rename from app/code/Magento/Sales/Test/Unit/Model/Resource/EntityRelationCompositeTest.php rename to lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/RelationCompositeTest.php index 9da63a991cd7e6b5b973b1e2bc429fe4807a1efa..942b5bd8c59238101fa0b3b3ef0255772a878d36 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityRelationCompositeTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/RelationCompositeTest.php @@ -4,25 +4,25 @@ * See COPYING.txt for license details. */ -namespace Magento\Sales\Test\Unit\Model\Resource; +namespace Magento\Framework\Model\Test\Unit\Resource\Db\VersionControl; /** - * Class EntityRelationCompositeTest + * Class RelationCompositeTest */ -class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase +class RelationCompositeTest extends \PHPUnit_Framework_TestCase { /** - * @var \Magento\Sales\Model\Resource\EntityRelationComposite + * @var \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite */ protected $entityRelationComposite; /** - * @var \Magento\Sales\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject */ - protected $salesModelMock; + protected $modelMock; /** - * @var \Magento\Sales\Model\Resource\EntityRelationInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface */ protected $relationProcessorMock; @@ -33,7 +33,7 @@ class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->salesModelMock = $this->getMockBuilder('Magento\Sales\Model\AbstractModel') + $this->modelMock = $this->getMockBuilder('Magento\Framework\Model\AbstractModel') ->disableOriginalConstructor() ->setMethods( [ @@ -41,16 +41,17 @@ class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase ] ) ->getMockForAbstractClass(); - $this->relationProcessorMock = $this->getMockBuilder('Magento\Sales\Model\AbstractModel') + $this->relationProcessorMock = $this->getMockBuilder('Magento\Framework\Model\AbstractModel') ->disableOriginalConstructor() ->getMockForAbstractClass(); $this->eventManagerMock = $this->getMockBuilder('Magento\Framework\Event\ManagerInterface') ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->relationProcessorMock = $this->getMockBuilder('Magento\Sales\Model\Resource\EntityRelationInterface') - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->entityRelationComposite = new \Magento\Sales\Model\Resource\EntityRelationComposite( + $this->relationProcessorMock = $this->getMockBuilder( + 'Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface' + )->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->entityRelationComposite = new \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite( $this->eventManagerMock, [ 'default' => $this->relationProcessorMock @@ -62,18 +63,18 @@ class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase { $this->relationProcessorMock->expects($this->once()) ->method('processRelation') - ->with($this->salesModelMock); - $this->salesModelMock->expects($this->once()) + ->with($this->modelMock); + $this->modelMock->expects($this->once()) ->method('getEventPrefix') - ->willReturn('sales_event_prefix'); + ->willReturn('custom_event_prefix'); $this->eventManagerMock->expects($this->once()) ->method('dispatch') ->with( - 'sales_event_prefix_process_relation', + 'custom_event_prefix_process_relation', [ - 'object' => $this->salesModelMock + 'object' => $this->modelMock ] ); - $this->entityRelationComposite->processRelations($this->salesModelMock); + $this->entityRelationComposite->processRelations($this->modelMock); } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntitySnapshotTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/SnapshotTest.php similarity index 62% rename from app/code/Magento/Sales/Test/Unit/Model/Resource/EntitySnapshotTest.php rename to lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/SnapshotTest.php index 6a7b4c896a0449f535d37589ece506fbc84ea42c..34aa803dae17641c5c679a9adb9078f869e9da31 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntitySnapshotTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/SnapshotTest.php @@ -3,27 +3,27 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Sales\Test\Unit\Model\Resource; +namespace Magento\Framework\Model\Test\Unit\Resource\Db\VersionControl; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** - * Class EntitySnapshotTest + * Class SnapshotTest */ -class EntitySnapshotTest extends \PHPUnit_Framework_TestCase +class SnapshotTest extends \PHPUnit_Framework_TestCase { /** - * @var \Magento\Sales\Model\Resource\EntitySnapshot + * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot */ protected $entitySnapshot; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Sales\Model\Resource\EntityMetadata + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\Resource\Db\VersionControl\Metadata */ protected $entityMetadata; /** - * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Sales\Model\AbstractModel + * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel */ protected $model; @@ -34,24 +34,24 @@ class EntitySnapshotTest extends \PHPUnit_Framework_TestCase { $objectManager = new ObjectManager($this); $this->model = $this->getMock( - 'Magento\Sales\Model\AbstractModel', - [], + 'Magento\Framework\Model\AbstractModel', + ['getId'], [], '', false ); $this->entityMetadata = $this->getMock( - 'Magento\Sales\Model\Resource\EntityMetadata', - [], + 'Magento\Framework\Model\Resource\Db\VersionControl\Metadata', + ['getFields'], [], '', false ); $this->entitySnapshot = $objectManager->getObject( - 'Magento\Sales\Model\Resource\EntitySnapshot', - ['entityMetadata' => $this->entityMetadata] + 'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot', + ['metadata' => $this->entityMetadata] ); } @@ -65,14 +65,16 @@ class EntitySnapshotTest extends \PHPUnit_Framework_TestCase 'custom_not_present_attribute' => '' ]; $fields = [ - 'id', - 'name', - 'description' + 'id' => [], + 'name' => [], + 'description' => [] ]; - $this->model->expects($this->once())->method('getData')->willReturn($data); - $this->model->expects($this->once())->method('getId')->willReturn($entityId); - $this->entityMetadata->expects($this->once())->method('getFields')->with($this->model)->willReturn($fields); + $this->assertTrue($this->entitySnapshot->isModified($this->model)); + $this->model->setData($data); + $this->model->expects($this->any())->method('getId')->willReturn($entityId); + $this->entityMetadata->expects($this->any())->method('getFields')->with($this->model)->willReturn($fields); $this->entitySnapshot->registerSnapshot($this->model); + $this->assertFalse($this->entitySnapshot->isModified($this->model)); } public function testIsModified() @@ -90,15 +92,11 @@ class EntitySnapshotTest extends \PHPUnit_Framework_TestCase 'description' => [] ]; $modifiedData = array_merge($data, ['name' => 'newName']); - $this->model->expects($this->exactly(4))->method('getData')->willReturnOnConsecutiveCalls( - $data, - $modifiedData, - $modifiedData, - $modifiedData - ); $this->model->expects($this->any())->method('getId')->willReturn($entityId); - $this->entityMetadata->expects($this->exactly(4))->method('getFields')->with($this->model)->willReturn($fields); + $this->entityMetadata->expects($this->exactly(2))->method('getFields')->with($this->model)->willReturn($fields); + $this->model->setData($data); $this->entitySnapshot->registerSnapshot($this->model); + $this->model->setData($modifiedData); $this->assertTrue($this->entitySnapshot->isModified($this->model)); $this->entitySnapshot->registerSnapshot($this->model); $this->assertFalse($this->entitySnapshot->isModified($this->model)); diff --git a/lib/internal/Magento/Framework/View/Element/Template.php b/lib/internal/Magento/Framework/View/Element/Template.php index 8e1c8e4cb27946799946680b342aff3ae78949df..a9928ab157baac5bdcbc1a0826a825254813ee5f 100644 --- a/lib/internal/Magento/Framework/View/Element/Template.php +++ b/lib/internal/Magento/Framework/View/Element/Template.php @@ -55,13 +55,6 @@ class Template extends AbstractBlock */ protected $_filesystem; - /** - * View file system - * - * @var \Magento\Framework\View\FileSystem - */ - protected $_viewFileSystem; - /** * Path to template file in theme. * @@ -116,6 +109,16 @@ class Template extends AbstractBlock */ protected $pageConfig; + /** + * @var \Magento\Framework\View\Element\Template\File\Resolver + */ + protected $resolver; + + /** + * @var \Magento\Framework\View\Element\Template\File\Validator + */ + protected $validator; + /** * Constructor * @@ -124,8 +127,9 @@ class Template extends AbstractBlock */ public function __construct(Template\Context $context, array $data = []) { + $this->validator = $context->getValidator(); + $this->resolver = $context->getResolver(); $this->_filesystem = $context->getFilesystem(); - $this->_viewFileSystem = $context->getViewFileSystem(); $this->templateEnginePool = $context->getEnginePool(); $this->_storeManager = $context->getStoreManager(); $this->_appState = $context->getAppState(); @@ -199,8 +203,7 @@ class Template extends AbstractBlock if ($area) { $params['area'] = $area; } - $templateName = $this->_viewFileSystem->getTemplateFileName($template ?: $this->getTemplate(), $params); - return $templateName; + return $this->resolver->getTemplateFileName($template ?: $this->getTemplate(), $params); } /** @@ -246,7 +249,7 @@ class Template extends AbstractBlock ['group' => 'TEMPLATE', 'file_name' => $relativeFilePath] ); - if ($this->isTemplateFileValid($fileName)) { + if ($this->validator->isValid($fileName)) { $extension = pathinfo($fileName, PATHINFO_EXTENSION); $templateEngine = $this->templateEnginePool->get($extension); $html = $templateEngine->render($this->templateContext, $fileName, $this->_viewVars); @@ -312,22 +315,6 @@ class Template extends AbstractBlock ]; } - /** - * Get is allowed symliks flag - * - * @return bool - */ - protected function isAllowSymlinks() - { - if (null === $this->_allowSymlinks) { - $this->_allowSymlinks = $this->_scopeConfig->isSetFlag( - self::XML_PATH_TEMPLATE_ALLOW_SYMLINK, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); - } - return $this->_allowSymlinks; - } - /** * Instantiates filesystem directory * @@ -354,49 +341,4 @@ class Template extends AbstractBlock } return $this->mediaDirectory; } - - /** - * Checks whether the provided file can be rendered. - * - * Available directories which are allowed to be rendered - * (the template file should be located under these directories): - * - app - * - design - * - * @param string $fileName - * @return bool - */ - protected function isTemplateFileValid($fileName) - { - $fileName = str_replace('\\', '/', $fileName); - - $themesDir = $this->_filesystem->getDirectoryRead(DirectoryList::THEMES)->getAbsolutePath(); - $appDir = $this->_filesystem->getDirectoryRead(DirectoryList::APP)->getAbsolutePath(); - $compiledDir = $this->_filesystem->getDirectoryRead(DirectoryList::TEMPLATE_MINIFICATION_DIR) - ->getAbsolutePath(); - return ($this->isPathInDirectory( - $fileName, - $compiledDir - ) || $this->isPathInDirectory( - $fileName, - $appDir - ) || $this->isPathInDirectory( - $fileName, - $themesDir - ) || $this->isAllowSymlinks()) && $this->getRootDirectory()->isFile( - $this->getRootDirectory()->getRelativePath($fileName) - ); - } - - /** - * Checks whether path related to the directory - * - * @param string $path - * @param string $directory - * @return bool - */ - protected function isPathInDirectory($path, $directory) - { - return 0 === strpos($path, $directory); - } } diff --git a/lib/internal/Magento/Framework/View/Element/Template/Context.php b/lib/internal/Magento/Framework/View/Element/Template/Context.php index 6fddcb67280165d4662656a264035f30e95a5a8c..78251c9ec7991dd713211c9663879bde569a5281 100644 --- a/lib/internal/Magento/Framework/View/Element/Template/Context.php +++ b/lib/internal/Magento/Framework/View/Element/Template/Context.php @@ -62,6 +62,17 @@ class Context extends \Magento\Framework\View\Element\Context protected $pageConfig; /** + * @var \Magento\Framework\View\Element\Template\File\Resolver + */ + protected $resolver; + + /** + * @var \Magento\Framework\View\Element\Template\File\Validator + */ + protected $validator; + + /** + * * @param \Magento\Framework\App\RequestInterface $request * @param \Magento\Framework\View\LayoutInterface $layout * @param \Magento\Framework\Event\ManagerInterface $eventManager @@ -85,6 +96,8 @@ class Context extends \Magento\Framework\View\Element\Context * @param \Magento\Framework\App\State $appState * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\View\Page\Config $pageConfig + * @param \Magento\Framework\View\Element\Template\File\Resolver $resolver + * @param \Magento\Framework\View\Element\Template\File\Validator $validator * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -111,7 +124,9 @@ class Context extends \Magento\Framework\View\Element\Context \Magento\Framework\View\TemplateEnginePool $enginePool, \Magento\Framework\App\State $appState, \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Framework\View\Page\Config $pageConfig + \Magento\Framework\View\Page\Config $pageConfig, + \Magento\Framework\View\Element\Template\File\Resolver $resolver, + \Magento\Framework\View\Element\Template\File\Validator $validator ) { parent::__construct( $request, @@ -132,7 +147,8 @@ class Context extends \Magento\Framework\View\Element\Context $localeDate, $inlineTranslation ); - + $this->resolver = $resolver; + $this->validator = $validator; $this->_storeManager = $storeManager; $this->_appState = $appState; $this->_logger = $logger; @@ -142,6 +158,26 @@ class Context extends \Magento\Framework\View\Element\Context $this->pageConfig = $pageConfig; } + /** + * Get template file resolver + * + * @return File\Resolver + */ + public function getResolver() + { + return $this->resolver; + } + + /** + * Get validator + * + * @return File\Validator + */ + public function getValidator() + { + return $this->validator; + } + /** * Get filesystem instance * diff --git a/lib/internal/Magento/Framework/View/Element/Template/File/Resolver.php b/lib/internal/Magento/Framework/View/Element/Template/File/Resolver.php new file mode 100644 index 0000000000000000000000000000000000000000..4bb7e4884a8b17e87deed5597e14eac2b3be9f25 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Element/Template/File/Resolver.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Element\Template\File; + +/** + * Class Resolver + * @package Magento\Framework\View\Element\Template\File + */ +class Resolver +{ + /** + * Template files map + * + * @var [] + */ + protected $_templateFilesMap = []; + + /** + * View filesystem + * + * @var \Magento\Framework\View\FileSystem + */ + protected $_viewFileSystem; + + /** + * Class constructor + * + * @param \Magento\Framework\View\FileSystem $viewFileSystem + */ + public function __construct(\Magento\Framework\View\FileSystem $viewFileSystem) + { + $this->_viewFileSystem = $viewFileSystem; + } + + /** + * Get template filename + * + * @param string $template + * @param [] $params + * @return string|bool + */ + public function getTemplateFileName($template, $params = []) + { + $key = $template . '_' . serialize($params); + if (!isset($this->_templateFilesMap[$key])) { + $this->_templateFilesMap[$key] = $this->_viewFileSystem->getTemplateFileName($template, $params); + } + return $this->_templateFilesMap[$key]; + } +} diff --git a/lib/internal/Magento/Framework/View/Element/Template/File/Validator.php b/lib/internal/Magento/Framework/View/Element/Template/File/Validator.php new file mode 100644 index 0000000000000000000000000000000000000000..101bae7ad7037e583c6d4cbac150402068d1326e --- /dev/null +++ b/lib/internal/Magento/Framework/View/Element/Template/File/Validator.php @@ -0,0 +1,139 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Element\Template\File; + +use \Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Class Validator + * @package Magento\Framework\View\Element\Template\File + */ +class Validator +{ + /** + * Config path to 'Allow Symlinks' template settings + */ + const XML_PATH_TEMPLATE_ALLOW_SYMLINK = 'dev/template/allow_symlink'; + + /** + * Template files map + * + * @var [] + */ + protected $_templatesValidationResults = []; + + /** + * View filesystem + * + * @var \Magento\Framework\FileSystem + */ + protected $_filesystem; + + /** + * Allow symlinks flag + * + * @var bool + */ + protected $_isAllowSymlinks = false; + + /** + * Root directory + * + * @var bool + */ + protected $directory = null; + + /** + * Themes directory + * + * @var string + */ + protected $_themesDir; + + /** + * Application directory + * + * @var string + */ + protected $_appDir; + + /** + * Compiled templates directory + * + * @var string + */ + protected $_compiledDir; + + /** + * Class constructor + * + * @param \Magento\Framework\Filesystem $filesystem + * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfigInterface + * @param string|null $scope + */ + public function __construct( + \Magento\Framework\Filesystem $filesystem, + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfigInterface, + $scope = null + ) { + $this->_filesystem = $filesystem; + $this->_isAllowSymlinks = $scopeConfigInterface->getValue(self::XML_PATH_TEMPLATE_ALLOW_SYMLINK, $scope); + $this->_themesDir = $this->_filesystem->getDirectoryRead(DirectoryList::THEMES)->getAbsolutePath(); + $this->_appDir = $this->_filesystem->getDirectoryRead(DirectoryList::APP)->getAbsolutePath(); + $this->_compiledDir = $this->_filesystem->getDirectoryRead(DirectoryList::TEMPLATE_MINIFICATION_DIR) + ->getAbsolutePath(); + } + + /** + * Checks whether the provided file can be rendered. + * + * Available directories which are allowed to be rendered + * (the template file should be located under these directories): + * - app + * - design + * + * @param string $filename + * @return bool + */ + public function isValid($filename) + { + $filename = str_replace('\\', '/', $filename); + if (!isset($this->_templatesValidationResults[$filename])) { + $this->_templatesValidationResults[$filename] = + ($this->isPathInDirectory($filename, $this->_compiledDir) + || $this->isPathInDirectory($filename, $this->_appDir) + || $this->isPathInDirectory($filename, $this->_themesDir) + || $this->_isAllowSymlinks) + && $this->getRootDirectory()->isFile($this->getRootDirectory()->getRelativePath($filename)); + } + return $this->_templatesValidationResults[$filename]; + } + + /** + * Checks whether path related to the directory + * + * @param string $path + * @param string $directory + * @return bool + */ + protected function isPathInDirectory($path, $directory) + { + return 0 === strpos($path, $directory); + } + + /** + * Instantiates filesystem directory + * + * @return \Magento\Framework\Filesystem\Directory\ReadInterface + */ + protected function getRootDirectory() + { + if (null === $this->directory) { + $this->directory = $this->_filesystem->getDirectoryRead(DirectoryList::ROOT); + } + return $this->directory; + } +} diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Component/Definition.php b/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Component/Definition.php index 7e7e27bed013d0205c3f2f00c2112b9ba635b39e..5ea6d07f40505b7aff8d8d9bfeec2bba237410c4 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Component/Definition.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Component/Definition.php @@ -5,7 +5,9 @@ */ namespace Magento\Framework\View\Element\UiComponent\Config\Provider\Component; +use Magento\Framework\Phrase; use Magento\Framework\Config\CacheInterface; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\View\Element\UiComponent\Config\Converter; use Magento\Framework\View\Element\UiComponent\ArrayObjectFactory; use Magento\Framework\View\Element\UiComponent\Config\UiReaderInterface; @@ -66,9 +68,18 @@ class Definition * * @param string $name * @return array + * @throws LocalizedException */ public function getComponentData($name) { + if (!$this->componentData->offsetExists($name)) { + throw new LocalizedException( + new Phrase( + 'The requested component ("' . $name . '") is not found. ' + . 'Before using, you must add the implementation.' + ) + ); + } return (array) $this->componentData->offsetGet($name); } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/LinkTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/LinkTest.php index 3ff2d6934ce46ce7108dbc886fff3d28def47715..a5792024f66313ad80f7d5d89a605c4990366697 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/LinkTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Html/LinkTest.php @@ -53,8 +53,27 @@ class LinkTest extends \PHPUnit_Framework_TestCase ->method('getUrl') ->will($this->returnArgument('http://site.com/link.html')); + $validtorMock = $this->getMockBuilder('Magento\Framework\View\Element\Template\File\Validator') + ->setMethods(['isValid'])->disableOriginalConstructor()->getMock(); + + $scopeConfigMock = $this->getMockBuilder('Magento\Framework\App\Config') + ->setMethods(['isSetFlag'])->disableOriginalConstructor()->getMock(); + + $resolverMock = $this->getMockBuilder('Magento\Framework\View\Element\Template\File\Resolver') + ->setMethods([])->disableOriginalConstructor()->getMock(); + $contextMock = $this->getMockBuilder('Magento\Framework\View\Element\Template\Context') - ->setMethods(['getEscaper', 'getUrlBuilder'])->disableOriginalConstructor()->getMock(); + ->setMethods(['getEscaper', 'getUrlBuilder', 'getValidator', 'getResolver', 'getScopeConfig']) + ->disableOriginalConstructor() + ->getMock(); + + $contextMock->expects($this->any()) + ->method('getValidator') + ->will($this->returnValue($validtorMock)); + + $contextMock->expects($this->any()) + ->method('getResolver') + ->will($this->returnValue($resolverMock)); $contextMock->expects($this->any()) ->method('getEscaper') @@ -64,6 +83,10 @@ class LinkTest extends \PHPUnit_Framework_TestCase ->method('getUrlBuilder') ->will($this->returnValue($urlBuilderMock)); + $contextMock->expects($this->any()) + ->method('getScopeConfig') + ->will($this->returnValue($scopeConfigMock)); + /** @var \Magento\Framework\View\Element\Html\Link $linkWithAttributes */ $linkWithAttributes = $objectManagerHelper->getObject( 'Magento\Framework\View\Element\Html\Link', diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php index 60e4d21af3ab3a5a1bc4a9274da581ca80bc3d95..6e39e1cb47191b43e72bfb49bcc4493e0c67fe2b 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php @@ -38,6 +38,21 @@ class CookieTest extends \PHPUnit_Framework_TestCase $this->ipValidatorMock = $this->getMockBuilder('Magento\Framework\Validator\Ip') ->disableOriginalConstructor() ->getMock(); + + $validtorMock = $this->getMockBuilder('Magento\Framework\View\Element\Template\File\Validator') + ->setMethods(['isValid'])->disableOriginalConstructor()->getMock(); + + $scopeConfigMock = $this->getMockBuilder('Magento\Framework\App\Config') + ->setMethods(['isSetFlag'])->disableOriginalConstructor()->getMock(); + + $this->contextMock->expects($this->any()) + ->method('getScopeConfig') + ->will($this->returnValue($scopeConfigMock)); + + $this->contextMock->expects($this->any()) + ->method('getValidator') + ->will($this->returnValue($validtorMock)); + $this->model = new \Magento\Framework\View\Element\Js\Cookie( $this->contextMock, $this->sessionConfigMock, diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ResolverTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ResolverTest.php new file mode 100644 index 0000000000000000000000000000000000000000..31dd64c547cd6b2a1984fdae9dd1c40f615fb782 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ResolverTest.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Test\Unit\Element\Template\File; + +/** + * Class ResolverTest + * @package Magento\Framework\View\Test\Unit\Element\Template\File + */ +class ResolverTest extends \PHPUnit_Framework_TestCase +{ + /** + * Resolver object + * + * @var \Magento\Framework\View\Element\Template\File\Resolver + */ + protected $_resolver; + + /** + * Mock for view file system + * + * @var \Magento\Framework\View\FileSystem|\PHPUnit_Framework_MockObject_MockObject + */ + protected $_viewFileSystemMock; + + /** + * Test Setup + * + * @return void + */ + public function setUp() + { + $this->_viewFileSystemMock = $this->getMock('\Magento\Framework\View\FileSystem', [], [], '', false); + $this->_resolver = new \Magento\Framework\View\Element\Template\File\Resolver( + $this->_viewFileSystemMock + ); + } + + /** + * Resolver get template file name test + * + * @return void + */ + public function testGetTemplateFileName() + { + $template = 'template.phtml'; + $this->_viewFileSystemMock->expects($this->once()) + ->method('getTemplateFileName') + ->with($template) + ->will($this->returnValue('path_to' . $template)); + $this->assertEquals('path_to' . $template, $this->_resolver->getTemplateFileName($template)); + $this->assertEquals('path_to' . $template, $this->_resolver->getTemplateFileName($template)); + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ValidatorTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ValidatorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..befcf7e5a8c9f2d7397c049b7b704da5d72e0b6a --- /dev/null +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Template/File/ValidatorTest.php @@ -0,0 +1,141 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\View\Test\Unit\Element\Template\File; + +use \Magento\Framework\App\Filesystem\DirectoryList; +use \Magento\Framework\Filesystem\DriverPool; + +/** + * Class ValidatorTest + * @package Magento\Framework\View\Test\Unit\Element\Template\File + */ +class ValidatorTest extends \PHPUnit_Framework_TestCase +{ + /** + * Resolver object + * + * @var \Magento\Framework\View\Element\Template\File\Validator + */ + protected $_validator; + + /** + * Mock for view file system + * + * @var \Magento\Framework\FileSystem|\PHPUnit_Framework_MockObject_MockObject + */ + protected $_fileSystemMock; + + /** + * Mock for scope config + * + * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $_scopeConfigMock; + + /** + * Mock for root directory reader + * + * @var \Magento\Framework\Filesystem\Directory\ReadInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $rootDirectoryMock; + + /** + * Mock for app directory reader + * + * @var \Magento\Framework\Filesystem\Directory\ReadInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $appDirectoryMock; + + /** + * Mock for themes directory reader + * + * @var \Magento\Framework\Filesystem\Directory\ReadInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $themesDirectoryMock; + + /** + * Mock for compiled directory reader + * + * @var \Magento\Framework\Filesystem\Directory\ReadInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $compiledDirectoryMock; + + /** + * Test Setup + * + * @return void + */ + public function setUp() + { + $this->_fileSystemMock = $this->getMock('\Magento\Framework\Filesystem', [], [], '', false); + $this->_scopeConfigMock = $this->getMock('\Magento\Framework\App\Config\ScopeConfigInterface'); + $this->rootDirectoryMock = $this->getMock('\Magento\Framework\Filesystem\Directory\ReadInterface'); + $this->appDirectoryMock = $this->getMock('\Magento\Framework\Filesystem\Directory\ReadInterface'); + $this->themesDirectoryMock = $this->getMock('\Magento\Framework\Filesystem\Directory\ReadInterface'); + $this->compiledDirectoryMock = $this->getMock('\Magento\Framework\Filesystem\Directory\ReadInterface'); + + $this->_fileSystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->will($this->returnValueMap( + [ + [DirectoryList::ROOT, DriverPool::FILE, $this->rootDirectoryMock], + [DirectoryList::THEMES, DriverPool::FILE, $this->themesDirectoryMock], + [DirectoryList::APP, DriverPool::FILE, $this->appDirectoryMock], + [DirectoryList::TEMPLATE_MINIFICATION_DIR, DriverPool::FILE, $this->compiledDirectoryMock], + ] + )); + + $this->compiledDirectoryMock->expects($this->any()) + ->method('getAbsolutePath') + ->will($this->returnValue('/magento/var/compiled')); + + $this->appDirectoryMock->expects($this->any()) + ->method('getAbsolutePath') + ->will($this->returnValue('/magento/app')); + + $this->themesDirectoryMock->expects($this->any()) + ->method('getAbsolutePath') + ->will($this->returnValue('/magento/themes')); + + $this->_validator = new \Magento\Framework\View\Element\Template\File\Validator( + $this->_fileSystemMock, + $this->_scopeConfigMock + ); + } + + /** + * Test is file valid + * + * @param string $file + * @param bool $expectedResult + * + * @dataProvider testIsValidDataProvider + * + * @return void + */ + public function testIsValid($file, $expectedResult) + { + + $this->rootDirectoryMock->expects($this->any())->method('isFile')->will($this->returnValue(true)); + $this->assertEquals($expectedResult, $this->_validator->isValid($file)); + } + + /** + * Data provider for testIsValid + * + * @return [] + */ + public function testIsValidDataProvider() + { + return [ + 'empty' => ['', false], + '/magento/var/compiled/template.phtml' => ['/magento/var/compiled/template.phtml', true], + '/magento/themes/default/template.phtml' => ['/magento/themes/default/template.phtml', true], + '/magento/app/code/Some/Module/template.phtml' => ['/magento/app/code/Some/Module/template.phtml', true], + '/magento/x' => ['/magento/x', false], + ]; + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/TemplateTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/TemplateTest.php index 0a462c8fd4f453e24df96106c9789d68bb9e09e7..33bba78c6238eee8d64ba66a4a6bde7378986acb 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/TemplateTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/TemplateTest.php @@ -25,9 +25,14 @@ class TemplateTest extends \PHPUnit_Framework_TestCase protected $_templateEngine; /** - * @var \Magento\Framework\View\FileSystem|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\View\Element\Template\File\Resolver|\PHPUnit_Framework_MockObject_MockObject */ - protected $_viewFileSystem; + protected $_resolver; + + /** + * @var \Magento\Framework\View\Element\Template\File\Validator|\PHPUnit_Framework_MockObject_MockObject + */ + protected $_validator; /** * @var \Magento\Framework\Filesystem\Directory\Read|\PHPUnit_Framework_MockObject_MockObject @@ -36,7 +41,21 @@ class TemplateTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->_viewFileSystem = $this->getMock('\Magento\Framework\View\FileSystem', [], [], '', false); + $this->_resolver = $this->getMock( + 'Magento\Framework\View\Element\Template\File\Resolver', + [], + [], + '', + false + ); + + $this->_validator = $this->getMock( + 'Magento\Framework\View\Element\Template\File\Validator', + [], + [], + '', + false + ); $this->rootDirMock = $this->getMock('Magento\Framework\Filesystem\Directory\Read', [], [], '', false); $this->rootDirMock->expects($this->any()) @@ -55,7 +74,10 @@ class TemplateTest extends \PHPUnit_Framework_TestCase [\Magento\Framework\App\Filesystem\DirectoryList::THEMES, DriverPool::FILE, $themesDirMock], [\Magento\Framework\App\Filesystem\DirectoryList::APP, DriverPool::FILE, $appDirMock], [\Magento\Framework\App\Filesystem\DirectoryList::ROOT, DriverPool::FILE, $this->rootDirMock], - [\Magento\Framework\App\Filesystem\DirectoryList::TEMPLATE_MINIFICATION_DIR, DriverPool::FILE, $this->rootDirMock], + [ + \Magento\Framework\App\Filesystem\DirectoryList::TEMPLATE_MINIFICATION_DIR, DriverPool::FILE, + $this->rootDirMock + ], ])); $this->_templateEngine = $this->getMock( @@ -76,7 +98,8 @@ class TemplateTest extends \PHPUnit_Framework_TestCase [ 'filesystem' => $this->_filesystem, 'enginePool' => $this->_templateEngine, - 'viewFileSystem' => $this->_viewFileSystem, + 'resolver' => $this->_resolver, + 'validator' => $this->_validator, 'appState' => $appState, 'data' => ['template' => 'template.phtml', 'module_name' => 'Fixture_Module'] ] @@ -86,7 +109,7 @@ class TemplateTest extends \PHPUnit_Framework_TestCase public function testGetTemplateFile() { $params = ['module' => 'Fixture_Module', 'area' => 'frontend']; - $this->_viewFileSystem->expects($this->once())->method('getTemplateFileName')->with('template.phtml', $params); + $this->_resolver->expects($this->once())->method('getTemplateFileName')->with('template.phtml', $params); $this->_block->getTemplateFile(); } @@ -94,8 +117,8 @@ class TemplateTest extends \PHPUnit_Framework_TestCase { $this->expectOutputString(''); $template = 'themedir/template.phtml'; - $this->rootDirMock->expects($this->once()) - ->method('isFile') + $this->_validator->expects($this->once()) + ->method('isValid') ->with($template) ->will($this->returnValue(true)); @@ -109,11 +132,12 @@ class TemplateTest extends \PHPUnit_Framework_TestCase public function testSetTemplateContext() { $template = 'themedir/template.phtml'; - $this->rootDirMock->expects($this->once()) - ->method('isFile') + $context = new \Magento\Framework\Object(); + $this->_validator->expects($this->once()) + ->method('isValid') ->with($template) ->will($this->returnValue(true)); - $context = new \Magento\Framework\Object(); + $this->_templateEngine->expects($this->once())->method('render')->with($context); $this->_block->setTemplateContext($context); $this->_block->fetchView($template); diff --git a/lib/internal/Magento/Framework/Webapi/Soap/ClientFactory.php b/lib/internal/Magento/Framework/Webapi/Soap/ClientFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..42d62ab67c334df5d03979441cafad633f0b769d --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Soap/ClientFactory.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Webapi\Soap; + +/** + * Class ClientFactory + * @package Magento\Framework\Webapi\Soap + */ +class ClientFactory +{ + /** + * Factory method for \SoapClient + * + * @param string $wsdl + * @param array $options + * @return \SoapClient + */ + public function create($wsdl, array $options = []) + { + return new \SoapClient($wsdl, $options); + } +} diff --git a/lib/web/css/source/components/_modals.less b/lib/web/css/source/components/_modals.less index df5c973eef2de55b58b941178d1acf677ee0a219..a57580c88722424f70b28214ed1500e94a4ed6c0 100644 --- a/lib/web/css/source/components/_modals.less +++ b/lib/web/css/source/components/_modals.less @@ -46,6 +46,7 @@ &._show { visibility: visible; .modal-inner-wrap { + -webkit-transform: translate(0, 0); transform: translate(0, 0); } } @@ -62,6 +63,7 @@ z-index: @modal-slide__z-index; &._show { .modal-inner-wrap { + -webkit-transform: translateX(0); transform: translateX(0); } } @@ -69,9 +71,11 @@ height: 100%; overflow-y: auto; position: static; + -webkit-transform: translateX(100%); transform: translateX(100%); transition-duration: .3s; transition-timing-function: ease-in-out; + -webkit-transition-property: -webkit-transform, visibility; transition-property: transform, visibility; width: auto; } @@ -83,18 +87,24 @@ z-index: @modal-popup__z-index; &._show { .modal-inner-wrap { + -webkit-transform: translateY(0); transform: translateY(0); } } .modal-inner-wrap { + box-sizing: border-box; .vendor-prefix-display(flex); .vendor-prefix-flex-direction(column); height: auto; - margin: @modal-popup__indent-vertical (100% - @modal-popup__width) / 2; + left: 0; + right: 0; + margin: @modal-popup__indent-vertical auto; position: absolute; + -webkit-transform: translateY(-200%); transform: translateY(-200%); transition-duration: .2s; transition-timing-function: ease; + -webkit-transition-property: -webkit-transform, visibility; transition-property: transform, visibility; width: @modal-popup__width; } @@ -102,10 +112,12 @@ // -._has-modal { - height: 100vh; - overflow: hidden; - width: 100vw; +body { + &._has-modal { + height: 100%; + overflow: hidden; + width: 100%; + } } // Modals overlay @@ -156,8 +168,16 @@ // If applied, switching outer popup scroll to inner &._inner-scroll { overflow-y: visible; + .ie10 &, + .ie9 & { + overflow-y: auto; + } .modal-inner-wrap { max-height: 90%; + .ie10 &, + .ie9 & { + max-height: none; + } } .modal-content { overflow-y: auto; diff --git a/lib/web/css/source/lib/_responsive.less b/lib/web/css/source/lib/_responsive.less index 42388a0be5b45753d628afbe2cd916ea13d99a99..105a06e6b5018a5886bc496c713bd3c484a00fc2 100644 --- a/lib/web/css/source/lib/_responsive.less +++ b/lib/web/css/source/lib/_responsive.less @@ -39,6 +39,10 @@ .media-width('max', @screen__m); } + @media only screen and (max-width: @screen__m) { + .media-width('max', (@screen__m + 1)); + } + @media all and (min-width: @screen__s) { .media-width('min', @screen__s); } @@ -56,6 +60,11 @@ .media-width('min', @screen__m); } + @media all and (min-width: (@screen__m + 1)), + print { + .media-width('min', (@screen__m + 1)); + } + @media all and (min-width: @screen__l), print { .media-width('min', @screen__l); diff --git a/lib/web/css/source/lib/variables/_icons.less b/lib/web/css/source/lib/variables/_icons.less index 999e9c2cf7922b5a9acb500e499ba271a116e992..ac6e0c0c9bd0c422c4c6f3fda7cb99f30b197858 100644 --- a/lib/web/css/source/lib/variables/_icons.less +++ b/lib/web/css/source/lib/variables/_icons.less @@ -75,10 +75,11 @@ @icon-comment: '\e620'; @icon-up: '\e621'; @icon-down: '\e622'; -@icon-arrow-up-thin: '\e623'; +@icon-help: '\e623'; @icon-arrow-right-thin: '\e624'; @icon-arrow-left-thin: '\e625'; @icon-arrow-down-thin: '\e626'; @icon-account: '\e627'; @icon-gift-registry: '\e628'; @icon-present: '\e629'; +@icon-arrow-up-thin: '\e633'; diff --git a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.eot b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.eot index 9bc3197afaa63854e2a13d3f79f31488bf1fe4db..806461187aa48e9ad6e425d4308f8f93c61fe3f4 100644 Binary files a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.eot and b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.eot differ diff --git a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.svg b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.svg index 85f6bf6ddeca82ba961382a061b92c7b6da011b7..37d511d157533ea09dca32f6568390647d2540e4 100644 --- a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.svg +++ b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg"><defs><font id="Blank-Theme-Icons" horiz-adv-x="1024"><font-face units-per-em="1024" ascent="960" descent="-64"/><missing-glyph horiz-adv-x="1024"/><glyph unicode=" " d="" horiz-adv-x="512"/><glyph unicode="" d="M676.571 637.696c-59.867 28.197-131.255 2.523-159.415-57.307-1.975-4.133-3.657-9.362-5.157-15.397-1.499 6.034-3.182 11.264-5.157 15.397-28.197 59.831-99.547 85.504-159.415 57.307-59.831-28.197-85.504-99.547-57.271-159.378 28.197-59.867 221.806-231.424 221.806-231.424s0 0.219 0.037 0.585c0.037-0.366 0.037-0.585 0.037-0.585s193.646 171.557 221.806 231.424c28.233 59.831 2.597 131.182-57.271 159.378z"/><glyph unicode="" d="M676.571 637.696c-59.831 28.197-131.218 2.523-159.451-57.307-1.938-4.133-3.657-9.362-5.157-15.397-1.463 6.034-3.182 11.264-5.157 15.397-28.16 59.831-99.547 85.504-159.378 57.307s-85.467-99.547-57.271-159.378 221.806-231.424 221.806-231.424 0 0.219 0.037 0.585c0-0.402 0-0.622 0-0.622s193.646 171.557 221.842 231.424c28.233 59.867 2.597 131.218-57.271 159.415zM690.213 479.232c-25.417-43.776-174.007-184.722-174.007-184.722l-1.573 2.999c0 0-155.465 140.398-181.211 183.991-30.61 51.822-7.753 108.946 38.949 128.439 43.52 18.176 101.888-27.319 123.502-73.143 1.499-3.182 17.627-1.463 18.798-6.107 1.134 4.645 12.727 2.926 14.226 6.107 21.577 45.824 81.042 93.989 128 72.411 46.007-21.138 66.926-72.155 33.317-129.975z"/><glyph unicode="" d="M512 704.11l-296.85-512.256h593.701l-296.85 512.256zM544.219 254.135h-62.757v49.92h62.757v-49.92zM528.713 343.369h-31.269l-20.809 140.654-1.207 72.704h72.521v-72.704l-19.237-140.654z"/><glyph unicode="" d="M628.846 588.544c-34.085 28.343-75.63 42.24-116.773 42.24-47.47 0-94.757-18.578-130.085-54.382l-32.073 29.586-0.585-102.693 110.994-0.658-39.424 41.253c25.198 24.027 58.002 36.315 91.136 36.352 29.842-0.037 59.721-9.947 84.517-30.574 31.488-26.222 47.689-63.744 47.726-101.815 0-5.449-0.366-10.971-1.024-16.457l51.383 9.874c0.073 2.231 0.146 4.425 0.146 6.619 0.037 52.37-22.491 104.521-65.938 140.654zM603.794 352.768c-25.307-24.466-58.405-37.010-91.867-37.047-29.879 0.037-59.721 9.984-84.517 30.574-31.488 26.222-47.689 63.744-47.726 101.778 0 6.327 0.475 12.617 1.353 18.871l-51.602-9.691c-0.146-3.072-0.256-6.107-0.256-9.179-0.037-52.334 22.491-104.521 65.975-140.617 34.048-28.343 75.593-42.24 116.736-42.24h0.11c47.799 0 95.378 18.907 130.743 55.223l33.938-33.829 0.219 106.094-112.055 0.293 38.949-40.229z"/><glyph unicode="" d="M696.942 624.933l-19.273 6.107h-74.496v38.583l-12.544 21.029-22.711 13.495h-111.141l-23.333-13.495-12.581-21.029v-38.619h-73.765l-18.761-6.656-17.189-14.153v-88.869h19.017v-0.073h17.554v-329.435h36.571v0.293h255.415v-0.293h36.571v329.435h18.286v0.073h18.286v86.601l-15.909 17.006zM457.435 667.575h109.129v-36.571h-109.129v36.571zM639.707 228.718h-255.415v292.571h255.415v-292.571zM676.279 557.934h-328.558v36.498h328.558v-36.498zM457.435 483.511h-36.571v-218.587h36.571v218.587zM530.578 483.511h-36.571v-218.587h36.571v218.587zM603.721 483.511h-36.571v-218.587h36.571v218.587z"/><glyph unicode="" d="M804.645 515.401c-1.499 4.681-5.888 7.899-10.789 7.899h-206.958l-64.073 196.754c-1.536 4.645-5.888 7.826-10.825 7.826-4.901 0-9.289-3.182-10.825-7.863l-64.439-196.754h-206.592c-4.901 0-9.289-3.218-10.825-7.863-1.499-4.681 0.146-9.874 4.096-12.763l167.205-121.783-64.439-197.851c-1.536-4.681 0.146-9.838 4.133-12.727 3.95-2.889 9.399-2.889 13.349 0l168.338 122.185 167.936-122.149c2.011-1.463 4.315-2.231 6.693-2.231s4.681 0.768 6.693 2.231c4.023 2.889 5.669 8.009 4.133 12.727l-64.439 197.851 167.57 121.783c3.95 2.889 5.632 8.046 4.059 12.727z"/><glyph unicode="" d="M807.241 415.854v67.145l-9.509 3.145-71.936 23.442-19.2 46.373 36.937 78.080-47.506 47.506-8.923-4.498-67.438-34.304-46.373 19.2-29.111 81.298h-67.182l-26.624-81.445-46.336-19.163-78.043 36.901-47.506-47.506 4.498-8.96 34.267-67.438-19.2-46.336-81.298-29.074v-67.218l9.472-3.072 71.973-23.515 19.163-46.373-36.901-78.080 47.506-47.506 8.887 4.498 67.474 34.304 46.373-19.2 29.111-81.298h67.182l3.072 9.509 23.515 71.936 46.373 19.2 78.080-36.937 47.506 47.506-4.498 8.923-34.304 67.438 19.2 46.373 81.298 29.147zM512 353.938c-51.968 0-94.062 42.13-94.062 94.062 0 52.005 42.094 94.062 94.062 94.062 51.931 0 94.098-42.057 94.098-94.062-0.037-51.931-42.167-94.062-94.098-94.062z"/><glyph unicode="" d="M339.602 539.941l172.398-183.881 172.398 183.881z"/><glyph unicode="" d="M606.939 449.938l-158.391 162.853-27.794-26.075 132.827-136.558-136.521-140.361 27.173-26.587 153.198 157.55-0.146 0.146z"/><glyph unicode="" d="M127.634 740.571v-73.143h768.731v73.143h-768.731zM127.634 411.429h768.731v73.143h-768.731v-73.143zM127.634 155.429h768.731v73.143h-768.731v-73.143z"/><glyph unicode="" d="M512 742.217c-102.437 0-185.417-83.054-185.417-185.454 0-102.437 185.417-403.017 185.417-403.017s185.454 300.581 185.454 403.017c-0.037 102.437-83.017 185.454-185.454 185.454zM512 500.443c-31.122 0-56.357 25.198-56.357 56.357 0 31.086 25.234 56.357 56.357 56.357 31.159 0 56.393-25.271 56.393-56.357-0.037-31.159-25.271-56.357-56.393-56.357z"/><glyph unicode="" d="M219.429 485.595h255.927v254.793h-255.927v-254.793zM548.571 740.389v-109.349h256v109.349h-256zM219.429 156.453h255.927v254.793h-255.927v-254.793zM548.571 484.754h256v109.349h-256v-109.349zM548.571 301.897h256v109.349h-256v-109.349zM548.571 155.611h256v109.349h-256v-109.349z"/><glyph unicode="" d="M579.511 677.010c-30.793 0-57.381-25.161-57.381-55.954 0-28.635 18.907-47.579 47.579-47.579 31.415 0 58.002 23.771 58.002 55.991 0 28.709-20.224 47.543-48.201 47.543zM593.518 336.494c-9.801 0-48.311-59.502-69.266-59.502-5.595 0-8.375 4.937-8.375 9.801 0 11.227 7.68 28.709 11.849 39.205l50.322 136.375c25.198 67.84-6.985 86.016-37.047 86.016-40.558 0-76.946-20.297-104.887-46.848-9.106-9.070-39.863-38.437-39.863-51.054 0-4.133 4.169-9.070 9.106-9.070 12.544 0 46.153 60.855 72.009 60.855 5.595 0 11.886-6.29 6.985-18.871l-48.896-123.173c-4.937-11.849-28.709-69.23-28.709-102.802 0-26.587 17.518-38.437 42.679-38.437 70.656 0 152.43 86.711 152.43 107.008 0 6.29-4.864 10.496-8.338 10.496z"/><glyph unicode="" d="M219.063 593.92h147.017v147.017h-147.017v-147.017zM438.491 593.92h147.017v147.017h-147.017v-147.017zM657.92 740.937v-147.017h147.017v147.017h-147.017zM219.063 374.491h147.017v147.017h-147.017v-147.017zM438.491 374.491h147.017v147.017h-147.017v-147.017zM657.92 374.491h147.017v147.017h-147.017v-147.017zM219.063 155.063h147.017v147.017h-147.017v-147.017zM438.491 155.063h147.017v147.017h-147.017v-147.017zM657.92 155.063h147.017v147.017h-147.017v-147.017z"/><glyph unicode="" d="M711.607 401.591l-5.486-5.522c21.065 27.794 32.878 60.197 32.219 94.72-1.975 99.218-106.679 177.627-233.874 175.141-127.232-2.487-228.791-84.992-226.816-184.21 1.938-99.182 106.679-177.554 233.911-175.067 28.635 0.585 50.432-5.815 75.63 2.121l159.232-78.702c-0.037-0.037-71.058 124.965-34.816 171.52z"/><glyph unicode="" d="M236.946 466.286h550.107v-36.571h-550.107v36.571z"/><glyph unicode="" d="M749.129 663.698c-152.101-93.257-262.473-210.907-312.064-269.934l-121.417 95.159-53.65-43.264 209.847-213.394c36.096 92.489 150.491 273.298 290.158 401.737l-12.873 29.696z"/><glyph unicode="" d="M434.871 259.95c-35.218 0-63.707-28.526-63.707-63.744 0-35.182 28.489-63.671 63.707-63.671 35.182 0 63.707 28.489 63.707 63.671 0 35.218-28.526 63.744-63.707 63.744zM654.848 259.95c-35.218 0-63.707-28.526-63.707-63.744 0-35.182 28.489-63.671 63.707-63.671 35.145 0 63.707 28.489 63.707 63.671 0 35.218-28.562 63.744-63.707 63.744zM784.274 616.741c-163.511 0-427.227 0-427.227 0s-25.929 70.071-49.957 113.371c-24.027 43.227-57.893 32.037-57.893 32.037-26.843 0-39.314-16.055-39.314-42.971 0-26.843 16.457-48.64 43.337-48.64l16.603-14.848 121.929-330.533 356.425-0.256c0 0 65.17 261.705 61.806 251.355 11.959 36.974-3.255 40.485-25.71 40.485zM392.485 492.544c-18.725 0-33.902 15.177-33.902 33.902s15.177 33.902 33.902 33.902 33.902-15.177 33.902-33.902-15.177-33.902-33.902-33.902zM464.933 379.392c-18.725 0-33.902 15.177-33.902 33.902s15.177 33.902 33.902 33.902 33.902-15.177 33.902-33.902-15.177-33.902-33.902-33.902zM502.199 492.544c-18.725 0-33.902 15.177-33.902 33.902s15.177 33.902 33.902 33.902 33.902-15.177 33.902-33.902-15.177-33.902-33.902-33.902zM574.647 379.392c-18.725 0-33.865 15.177-33.865 33.902s15.177 33.902 33.865 33.902 33.938-15.177 33.938-33.902-15.214-33.902-33.938-33.902zM611.913 492.544c-18.725 0-33.938 15.177-33.938 33.902s15.214 33.902 33.938 33.902 33.865-15.177 33.865-33.902-15.141-33.902-33.865-33.902zM684.361 379.392c-18.725 0-33.865 15.177-33.865 33.902s15.141 33.902 33.865 33.902 33.938-15.177 33.938-33.902-15.214-33.902-33.938-33.902zM721.627 492.544c-18.725 0-33.938 15.177-33.938 33.902s15.214 33.902 33.938 33.902 33.865-15.177 33.865-33.902-15.141-33.902-33.865-33.902z"/><glyph unicode="" d="M642.487 578.304c11.959 0 21.65 9.691 21.65 21.65v77.934c0 11.959-9.691 21.65-21.65 21.65-11.922 0-21.65-9.691-21.65-21.65v-77.934c0.037-11.959 9.728-21.65 21.65-21.65zM381.842 578.304c11.922 0 21.65 9.691 21.65 21.65v77.934c0 11.959-9.728 21.65-21.65 21.65-11.959 0-21.65-9.691-21.65-21.65v-77.934c0.037-11.959 9.691-21.65 21.65-21.65zM671.269 636.562v-0.402c8.997-7.973 14.702-19.566 14.702-32.549 0-23.991-19.456-43.447-43.483-43.447-23.991 0-43.447 19.456-43.447 43.447 0 12.946 5.705 24.576 14.702 32.549v0.402h-203.154v-0.402c8.997-7.973 14.702-19.566 14.702-32.549 0-23.991-19.456-43.447-43.447-43.447-24.027 0-43.447 19.456-43.447 43.447 0 12.946 5.669 24.576 14.665 32.549v0.402h-96.841v-440.101h511.561v440.101h-96.512zM732.087 234.569h-437.76v291.694h437.76v-291.694zM619.301 407.113h-55.15v-55.113h55.15v55.113zM619.301 490.021h-55.15v-55.113h55.15v55.113zM619.301 326.51h-55.15v-55.15h55.15v55.15zM696.942 490.021h-55.15v-55.113h55.15v55.113zM696.942 407.113h-55.15v-55.113h55.15v55.113zM386.267 326.51h-55.113v-55.15h55.113v55.15zM463.982 326.51h-55.15v-55.15h55.15v55.15zM463.982 407.113h-55.15v-55.113h55.15v55.113zM386.267 407.113h-55.113v-55.113h55.113v55.113zM541.586 407.113h-55.113v-55.113h55.113v55.113zM541.586 490.021h-55.113v-55.113h55.113v55.113zM463.982 490.021h-55.15v-55.113h55.15v55.113zM541.586 326.51h-55.113v-55.15h55.113v55.15z"/><glyph unicode="" d="M512 677.742l-209.006-253.257h136.338v-206.19h145.298v206.19h136.375z"/><glyph unicode="" d="M584.631 471.515v206.226h-145.298v-206.226h-136.338l209.006-253.221 209.006 253.221z"/><glyph unicode="" d="M836.462 183.918c0 0-109.641 112.677-153.381 156.233-19.054 19.017-32.073 31.927-32.073 31.927 14.848 21.211 26.405 44.361 34.633 69.339s12.361 51.237 12.361 78.848c0 35.621-6.802 69.083-20.334 100.462-13.568 31.305-32 58.697-55.406 82.030-23.369 23.442-50.725 41.874-82.066 55.406-31.305 13.605-64.768 20.37-100.389 20.37-35.584 0-69.047-6.802-100.425-20.37-31.305-13.531-58.551-31.963-81.664-55.406-23.077-23.296-41.435-50.688-54.967-81.993-13.568-31.378-20.334-64.841-20.334-100.462s6.802-69.083 20.334-100.389c13.531-31.305 31.89-58.661 54.967-82.103 23.113-23.333 50.322-41.801 81.664-55.369 31.378-13.568 64.841-20.297 100.425-20.297 27.648 0 53.943 4.023 78.885 12.288s48.091 19.858 69.303 34.706c0 0 11.922-11.959 29.696-29.806 48.421-48.603 155.026-159.159 155.026-159.159 16.018-6.985 41.728 0.439 54.455 11.337s19.858 33.682 9.289 52.407zM612.718 447.013c-9.838-22.747-23.223-42.569-40.155-59.429-16.933-16.933-36.718-30.354-59.429-40.192-22.638-9.874-46.848-14.775-72.521-14.775-26.258 0-50.688 4.937-73.362 14.775s-42.496 23.259-59.429 40.192c-16.896 16.859-30.354 36.681-40.155 59.429-9.838 22.601-14.738 47.104-14.738 73.289 0 25.673 4.901 50.030 14.738 72.997 9.838 22.93 23.259 42.898 40.155 59.794 16.933 16.969 36.754 30.354 59.429 40.155 22.674 9.911 47.104 14.738 73.362 14.738 25.673 0 49.883-4.864 72.521-14.738 22.674-9.801 42.496-23.186 59.429-40.155 16.933-16.933 30.318-36.901 40.155-59.831 9.874-22.967 14.738-47.323 14.738-72.997 0-26.149-4.901-50.651-14.738-73.253z"/><glyph unicode="" d="M695.845 602.661l-29.147 29.111-154.697-154.734-154.734 154.734-29.111-29.111 154.734-154.734-154.624-154.624 29.111-29.074 154.624 154.587 154.661-154.587 29.038 29.074-154.587 154.624z"/><glyph unicode="" d="M470.418 450.158l132.791 136.558-27.794 26.075-158.354-162.853 9.618-9.033-0.11-0.146 153.234-157.55 27.136 26.587z"/><glyph unicode="" d="M512 539.941l-172.398-183.881h344.795z"/><glyph unicode="" d="M392.119 622.043v-348.087l239.726 174.043z"/><glyph unicode="" d="M392.119 448l239.726-174.043v348.087z"/><glyph unicode="" d="M237.714 191.159h73.728v513.682h-73.728v-513.682zM786.286 703.086h-440.283v-292.169h440.283l-148.078 144.128 148.078 148.041z"/><glyph unicode="" d="M787.054 466.359h-256.219v256.695h-36.571v-256.695h-257.317v-36.571h257.317v-256.841h36.571v256.841h256.219z"/><glyph unicode="" d="M769.134 594.286v36.571h-513.17v-25.271l-1.097-1.097 1.097-1.097v-9.106h0.622v-292.571h-0.622v-8.558l-1.097-1.097 1.097-1.097v-25.819h513.17v36.571h-0.585v292.571h0.585zM703.89 301.714h-387.657l119.881 119.881-25.856 25.856-117.138-117.138v236.361l220.014-217.088 25.856 25.856-1.39 1.353 194.377 194.341v-245.87l-122.149 122.149-25.856-25.856 119.918-119.845zM317.221 594.286h386.158l-191.781-191.781-194.377 191.781z"/><glyph unicode="" d="M310.747 210.359h109.166v328.485h-109.166v-328.485zM604.050 355.584v-145.225h109.202v145.225h-109.202zM457.399 210.359h109.202v475.319h-109.202v-475.319z"/><glyph unicode="" d="M310.747 210.359h109.166v328.485h-109.166v-328.485zM347.941 503.625h36.864v-256.768h-36.864v256.768zM604.050 355.584v-145.225h109.202v145.225h-109.202zM677.339 246.711h-36.827v71.863h36.827v-71.863zM457.399 210.359h109.202v475.319h-109.202v-475.319zM494.263 649.838h36.827v-402.834h-36.827v402.834z"/><glyph unicode="" d="M519.57 665.893c-127.232 2.487-231.936-75.922-233.911-175.141-0.695-34.487 11.154-66.926 32.219-94.72l-5.486 5.522c36.242-46.519-34.816-171.52-34.816-171.52l159.232 78.702c25.161-7.936 46.994-1.536 75.63-2.121 127.232-2.487 231.973 75.886 233.911 175.067 2.011 99.255-99.511 181.723-226.779 184.21z"/><glyph unicode="" d="M514.158 489.582l136.558-132.791 26.075 27.794-162.853 158.354-166.729-162.743 26.587-27.136z"/><glyph unicode="" d="M509.842 406.418l-136.558 132.791-26.075-27.794 162.853-158.354 166.729 162.743-26.587 27.136z"/><glyph unicode="" d="M938.824 426.028l-0.504 106.238-426.32 426.322-426.322-426.322-0.504-106.238 389.444 389.442v-880.006h74.764v880.006z"/><glyph unicode="" d="M1.994 518.75h748.928l-283.278 291.206h200.254l354.108-363.956-354.108-363.956h-200.254l283.278 291.174h-748.928v145.532z"/><glyph unicode="" d="M1022.006 375.25h-748.928l283.278-291.206h-200.254l-354.108 363.956 354.108 363.956h200.254l-283.278-291.174h748.928v-145.532z"/><glyph unicode="" d="M85.174 468.026l0.504-106.238 426.322-426.324 426.32 426.324 0.504 106.238-389.444-389.444 0.002 880.006h-74.764v-880.004z"/><glyph unicode="" d="M511.963 831.086c-211.529 0-383.049-171.52-383.049-383.086s171.483-383.086 383.049-383.086c211.602 0 383.086 171.483 383.086 383.086s-171.483 383.086-383.086 383.086zM511.963 794.514c191.086 0 346.514-155.429 346.514-346.514 0-79.909-27.429-153.344-73.070-212.041-5.486 1.975-11.008 3.84-16.274 6.107-34.926 14.629-73.801 31.781-108.654 46.153-9.911 2.706-19.931 5.413-29.842 8.155-11.849 8.155-23.589 35.365-29.915 48.933-6.29 0.914-12.654 1.792-19.017 2.633 0.914 20.992 13.934 22.126 19.017 38.071 4.498 14.080 0.512 32.439 7.57 45.495 4.937 9.070 16.128 9.070 21.65 16.933 5.083 6.985 8.411 19.273 9.984 27.941 2.853 15.799 5.339 37.339-2.158 53.029-4.279 8.96-6.985 9.874-8.229 20.736-1.426 13.275 3.913 56.43 4.133 65.755 0.512 24.21-0.073 26.149-5.925 49.737 0 0-7.058 21.358-18.213 27.831l-22.272 3.803-13.714 12.727c-55.369 34.085-114.761 10.167-146.505-2.67-45.824-14.885-74.789-59.758-54.565-155.538 3.474-16.421-8.96-23.698-8.155-32.658 1.829-19.566 2.158-66.487 20.59-78.080 1.719-1.061 14.811-4.352 14.738-3.438 1.792-19.017 3.621-38.071 5.376-57.015 4.608-12.654 15.689-14.080 18.907-31.927l-14.153-3.438c-6.363-13.568-17.993-40.777-29.879-48.933-9.947-2.706-19.931-5.413-29.879-8.155-34.889-14.373-73.691-31.488-108.654-46.153-1.902-0.768-3.877-1.39-5.815-2.158-43.776 58.112-70.071 130.011-70.071 208.165 0 191.086 155.429 346.514 346.478 346.514z"/><glyph unicode="" d="M427.703 653.019c0-10.569-8.558-19.090-19.090-19.090h-11.154c-10.533 0-19.090 8.521-19.090 19.090v68.462c0 10.533 8.594 19.090 19.090 19.090h11.154c10.533 0 19.090-8.558 19.090-19.090v-68.462zM645.778 653.019c0-10.569-8.521-19.090-19.054-19.090h-11.154c-10.533 0-19.054 8.521-19.054 19.090v68.462c-0.037 10.533 8.485 19.090 19.054 19.090h11.154c10.533 0 19.054-8.558 19.054-19.090v-68.462zM675.182 481.317l-38.729 31.598-152.795-187.282-81.518 64.805-28.891-36.242 120.21-95.634zM758.784 687.982h-71.351v-29.769c0-31.634-25.746-57.344-57.271-57.344h-11.227c-31.598 0-57.271 25.71-57.271 57.344v29.769h-97.682v-29.769c0-31.634-25.71-57.344-57.307-57.344h-11.154c-31.598 0-57.307 25.71-57.307 57.344v29.769h-72.96c-10.533 0-19.090-8.521-19.090-19.054v-494.373c-0.037-10.569 8.558-19.127 19.090-19.127h493.531c10.533 0 19.054 8.558 19.054 19.090v494.409c0 10.533-8.521 19.054-19.054 19.054zM720.567 240.677c0-10.569-8.558-19.090-19.090-19.090h-378.917c-10.569 0-19.090 8.521-19.090 19.090v288.11c0 10.569 8.521 19.054 19.090 19.054h378.88c10.533 0 19.090-8.485 19.090-19.054v-288.11z"/><glyph unicode="" d="M391.863 554.203h-128.219c-10.35 0-18.761-8.375-18.761-18.725v-91.429c0-10.35 8.375-18.725 18.761-18.725h128.219c10.35 0 18.761 8.375 18.761 18.725v91.429c0 10.386-8.375 18.725-18.761 18.725zM391.863 387.511h-90.734c-10.35 0-18.761-8.375-18.761-18.725v-194.633c0-10.35 8.411-18.725 18.761-18.725h90.734c10.35 0 18.761 8.375 18.761 18.725v194.633c0 10.35-8.375 18.725-18.761 18.725zM760.357 554.203h-279.845c-10.35 0-18.725-8.375-18.725-18.725v-91.429c0-10.35 8.375-18.725 18.725-18.725h279.845c10.313 0 18.725 8.375 18.725 18.725v91.429c-0.037 10.386-8.411 18.725-18.725 18.725zM721.701 385.573h-240.64c-10.313 0-18.725-8.375-18.725-18.761v-192.695c0-10.35 8.375-18.725 18.725-18.725h240.64c10.35 0 18.725 8.375 18.725 18.725v192.695c0 10.35-8.375 18.761-18.725 18.761zM507.355 575.634c21.87-3.986 42.971-6.327 62.647-6.327 99.072 0 152.832 53.248 153.088 103.387 0.183 32.293-23.698 67.291-78.117 67.84-72.923 0-118.089-51.493-141.605-89.71-23.918 38.107-69.266 88.576-142.373 88.576-52.882-0.549-76.763-35.547-76.581-67.84 0.256-50.139 54.016-103.424 153.088-103.424 0.037 0 0.037 0 0.037 0 21.394 0 44.398 2.414 68.425 7.241l1.39 0.256zM645.998 693.723c9.143-0.073 30.354-2.304 30.245-20.773-0.11-23.589-33.17-56.795-106.24-56.795-10.057 0-20.553 0.658-31.525 1.938 16.567 29.294 51.566 75.63 107.52 75.63zM437.504 614.985v0c-73.106 0-106.167 33.207-106.277 56.795-0.11 18.469 21.102 20.699 31.305 20.809 55.259 0 90.039-46.373 106.496-75.666-10.935-1.28-21.467-1.938-31.525-1.938z"/></font></defs></svg> +<svg xmlns="http://www.w3.org/2000/svg"><defs><font horiz-adv-x="1024"><font-face units-per-em="1024" ascent="960" descent="-64" /><missing-glyph horiz-adv-x="1024" /><glyph unicode=" " d="" horiz-adv-x="512" /><glyph unicode="" d="M676.571 637.696c-59.867 28.197-131.255 2.523-159.415-57.307-1.975-4.133-3.657-9.362-5.157-15.397-1.499 6.034-3.182 11.264-5.157 15.397-28.197 59.831-99.547 85.504-159.415 57.307-59.831-28.197-85.504-99.547-57.271-159.378 28.197-59.867 221.806-231.424 221.806-231.424s0 0.219 0.037 0.585c0.037-0.366 0.037-0.585 0.037-0.585s193.646 171.557 221.806 231.424c28.233 59.831 2.597 131.182-57.271 159.378z" /><glyph unicode="" d="M676.571 637.696c-59.831 28.197-131.218 2.523-159.451-57.307-1.938-4.133-3.657-9.362-5.157-15.397-1.463 6.034-3.182 11.264-5.157 15.397-28.16 59.831-99.547 85.504-159.378 57.307s-85.467-99.547-57.271-159.378 221.806-231.424 221.806-231.424 0 0.219 0.037 0.585c0-0.402 0-0.622 0-0.622s193.646 171.557 221.842 231.424c28.233 59.867 2.597 131.218-57.271 159.415zM690.213 479.232c-25.417-43.776-174.007-184.722-174.007-184.722l-1.573 2.999c0 0-155.465 140.398-181.211 183.991-30.61 51.822-7.753 108.946 38.949 128.439 43.52 18.176 101.888-27.319 123.502-73.143 1.499-3.182 17.627-1.463 18.798-6.107 1.134 4.645 12.727 2.926 14.226 6.107 21.577 45.824 81.042 93.989 128 72.411 46.007-21.138 66.926-72.155 33.317-129.975z" /><glyph unicode="" d="M512 704.11l-296.85-512.256h593.701l-296.85 512.256zM544.219 254.135h-62.757v49.92h62.757v-49.92zM528.713 343.369h-31.269l-20.809 140.654-1.207 72.704h72.521v-72.704l-19.237-140.654z" /><glyph unicode="" d="M628.846 588.544c-34.085 28.343-75.63 42.24-116.773 42.24-47.47 0-94.757-18.578-130.085-54.382l-32.073 29.586-0.585-102.693 110.994-0.658-39.424 41.253c25.198 24.027 58.002 36.315 91.136 36.352 29.842-0.037 59.721-9.947 84.517-30.574 31.488-26.222 47.689-63.744 47.726-101.815 0-5.449-0.366-10.971-1.024-16.457l51.383 9.874c0.073 2.231 0.146 4.425 0.146 6.619 0.037 52.37-22.491 104.521-65.938 140.654zM603.794 352.768c-25.307-24.466-58.405-37.010-91.867-37.047-29.879 0.037-59.721 9.984-84.517 30.574-31.488 26.222-47.689 63.744-47.726 101.778 0 6.327 0.475 12.617 1.353 18.871l-51.602-9.691c-0.146-3.072-0.256-6.107-0.256-9.179-0.037-52.334 22.491-104.521 65.975-140.617 34.048-28.343 75.593-42.24 116.736-42.24h0.11c47.799 0 95.378 18.907 130.743 55.223l33.938-33.829 0.219 106.094-112.055 0.293 38.949-40.229z" /><glyph unicode="" d="M696.942 624.933l-19.273 6.107h-74.496v38.583l-12.544 21.029-22.711 13.495h-111.141l-23.333-13.495-12.581-21.029v-38.619h-73.765l-18.761-6.656-17.189-14.153v-88.869h19.017v-0.073h17.554v-329.435h36.571v0.293h255.415v-0.293h36.571v329.435h18.286v0.073h18.286v86.601l-15.909 17.006zM457.435 667.575h109.129v-36.571h-109.129v36.571zM639.707 228.718h-255.415v292.571h255.415v-292.571zM676.279 557.934h-328.558v36.498h328.558v-36.498zM457.435 483.511h-36.571v-218.587h36.571v218.587zM530.578 483.511h-36.571v-218.587h36.571v218.587zM603.721 483.511h-36.571v-218.587h36.571v218.587z" /><glyph unicode="" d="M804.645 515.401c-1.499 4.681-5.888 7.899-10.789 7.899h-206.958l-64.073 196.754c-1.536 4.645-5.888 7.826-10.825 7.826-4.901 0-9.289-3.182-10.825-7.863l-64.439-196.754h-206.592c-4.901 0-9.289-3.218-10.825-7.863-1.499-4.681 0.146-9.874 4.096-12.763l167.205-121.783-64.439-197.851c-1.536-4.681 0.146-9.838 4.133-12.727 3.95-2.889 9.399-2.889 13.349 0l168.338 122.185 167.936-122.149c2.011-1.463 4.315-2.231 6.693-2.231s4.681 0.768 6.693 2.231c4.023 2.889 5.669 8.009 4.133 12.727l-64.439 197.851 167.57 121.783c3.95 2.889 5.632 8.046 4.059 12.727z" /><glyph unicode="" d="M807.241 415.854v67.145l-9.509 3.145-71.936 23.442-19.2 46.373 36.937 78.080-47.506 47.506-8.923-4.498-67.438-34.304-46.373 19.2-29.111 81.298h-67.182l-26.624-81.445-46.336-19.163-78.043 36.901-47.506-47.506 4.498-8.96 34.267-67.438-19.2-46.336-81.298-29.074v-67.218l9.472-3.072 71.973-23.515 19.163-46.373-36.901-78.080 47.506-47.506 8.887 4.498 67.474 34.304 46.373-19.2 29.111-81.298h67.182l3.072 9.509 23.515 71.936 46.373 19.2 78.080-36.937 47.506 47.506-4.498 8.923-34.304 67.438 19.2 46.373 81.298 29.147zM512 353.938c-51.968 0-94.062 42.13-94.062 94.062 0 52.005 42.094 94.062 94.062 94.062 51.931 0 94.098-42.057 94.098-94.062-0.037-51.931-42.167-94.062-94.098-94.062z" /><glyph unicode="" d="M339.602 539.941l172.398-183.881 172.398 183.881z" /><glyph unicode="" d="M606.939 449.938l-158.391 162.853-27.794-26.075 132.827-136.558-136.521-140.361 27.173-26.587 153.198 157.55-0.146 0.146z" /><glyph unicode="" d="M127.634 740.571v-73.143h768.731v73.143h-768.731zM127.634 411.429h768.731v73.143h-768.731v-73.143zM127.634 155.429h768.731v73.143h-768.731v-73.143z" /><glyph unicode="" d="M512 742.217c-102.437 0-185.417-83.054-185.417-185.454 0-102.437 185.417-403.017 185.417-403.017s185.454 300.581 185.454 403.017c-0.037 102.437-83.017 185.454-185.454 185.454zM512 500.443c-31.122 0-56.357 25.198-56.357 56.357 0 31.086 25.234 56.357 56.357 56.357 31.159 0 56.393-25.271 56.393-56.357-0.037-31.159-25.271-56.357-56.393-56.357z" /><glyph unicode="" d="M219.429 485.595h255.927v254.793h-255.927v-254.793zM548.571 740.389v-109.349h256v109.349h-256zM219.429 156.453h255.927v254.793h-255.927v-254.793zM548.571 484.754h256v109.349h-256v-109.349zM548.571 301.897h256v109.349h-256v-109.349zM548.571 155.611h256v109.349h-256v-109.349z" /><glyph unicode="" d="M579.511 677.010c-30.793 0-57.381-25.161-57.381-55.954 0-28.635 18.907-47.579 47.579-47.579 31.415 0 58.002 23.771 58.002 55.991 0 28.709-20.224 47.543-48.201 47.543zM593.518 336.494c-9.801 0-48.311-59.502-69.266-59.502-5.595 0-8.375 4.937-8.375 9.801 0 11.227 7.68 28.709 11.849 39.205l50.322 136.375c25.198 67.84-6.985 86.016-37.047 86.016-40.558 0-76.946-20.297-104.887-46.848-9.106-9.070-39.863-38.437-39.863-51.054 0-4.133 4.169-9.070 9.106-9.070 12.544 0 46.153 60.855 72.009 60.855 5.595 0 11.886-6.29 6.985-18.871l-48.896-123.173c-4.937-11.849-28.709-69.23-28.709-102.802 0-26.587 17.518-38.437 42.679-38.437 70.656 0 152.43 86.711 152.43 107.008 0 6.29-4.864 10.496-8.338 10.496z" /><glyph unicode="" d="M219.063 593.92h147.017v147.017h-147.017v-147.017zM438.491 593.92h147.017v147.017h-147.017v-147.017zM657.92 740.937v-147.017h147.017v147.017h-147.017zM219.063 374.491h147.017v147.017h-147.017v-147.017zM438.491 374.491h147.017v147.017h-147.017v-147.017zM657.92 374.491h147.017v147.017h-147.017v-147.017zM219.063 155.063h147.017v147.017h-147.017v-147.017zM438.491 155.063h147.017v147.017h-147.017v-147.017zM657.92 155.063h147.017v147.017h-147.017v-147.017z" /><glyph unicode="" d="M711.607 401.591l-5.486-5.522c21.065 27.794 32.878 60.197 32.219 94.72-1.975 99.218-106.679 177.627-233.874 175.141-127.232-2.487-228.791-84.992-226.816-184.21 1.938-99.182 106.679-177.554 233.911-175.067 28.635 0.585 50.432-5.815 75.63 2.121l159.232-78.702c-0.037-0.037-71.058 124.965-34.816 171.52z" /><glyph unicode="" d="M236.946 466.286h550.107v-36.571h-550.107v36.571z" /><glyph unicode="" d="M749.129 663.698c-152.101-93.257-262.473-210.907-312.064-269.934l-121.417 95.159-53.65-43.264 209.847-213.394c36.096 92.489 150.491 273.298 290.158 401.737l-12.873 29.696z" /><glyph unicode="" d="M434.871 259.95c-35.218 0-63.707-28.526-63.707-63.744 0-35.182 28.489-63.671 63.707-63.671 35.182 0 63.707 28.489 63.707 63.671 0 35.218-28.526 63.744-63.707 63.744zM654.848 259.95c-35.218 0-63.707-28.526-63.707-63.744 0-35.182 28.489-63.671 63.707-63.671 35.145 0 63.707 28.489 63.707 63.671 0 35.218-28.562 63.744-63.707 63.744zM784.274 616.741c-163.511 0-427.227 0-427.227 0s-25.929 70.071-49.957 113.371c-24.027 43.227-57.893 32.037-57.893 32.037-26.843 0-39.314-16.055-39.314-42.971 0-26.843 16.457-48.64 43.337-48.64l16.603-14.848 121.929-330.533 356.425-0.256c0 0 65.17 261.705 61.806 251.355 11.959 36.974-3.255 40.485-25.71 40.485zM392.485 492.544c-18.725 0-33.902 15.177-33.902 33.902s15.177 33.902 33.902 33.902 33.902-15.177 33.902-33.902-15.177-33.902-33.902-33.902zM464.933 379.392c-18.725 0-33.902 15.177-33.902 33.902s15.177 33.902 33.902 33.902 33.902-15.177 33.902-33.902-15.177-33.902-33.902-33.902zM502.199 492.544c-18.725 0-33.902 15.177-33.902 33.902s15.177 33.902 33.902 33.902 33.902-15.177 33.902-33.902-15.177-33.902-33.902-33.902zM574.647 379.392c-18.725 0-33.865 15.177-33.865 33.902s15.177 33.902 33.865 33.902 33.938-15.177 33.938-33.902-15.214-33.902-33.938-33.902zM611.913 492.544c-18.725 0-33.938 15.177-33.938 33.902s15.214 33.902 33.938 33.902 33.865-15.177 33.865-33.902-15.141-33.902-33.865-33.902zM684.361 379.392c-18.725 0-33.865 15.177-33.865 33.902s15.141 33.902 33.865 33.902 33.938-15.177 33.938-33.902-15.214-33.902-33.938-33.902zM721.627 492.544c-18.725 0-33.938 15.177-33.938 33.902s15.214 33.902 33.938 33.902 33.865-15.177 33.865-33.902-15.141-33.902-33.865-33.902z" /><glyph unicode="" d="M642.487 578.304c11.959 0 21.65 9.691 21.65 21.65v77.934c0 11.959-9.691 21.65-21.65 21.65-11.922 0-21.65-9.691-21.65-21.65v-77.934c0.037-11.959 9.728-21.65 21.65-21.65zM381.842 578.304c11.922 0 21.65 9.691 21.65 21.65v77.934c0 11.959-9.728 21.65-21.65 21.65-11.959 0-21.65-9.691-21.65-21.65v-77.934c0.037-11.959 9.691-21.65 21.65-21.65zM671.269 636.562v-0.402c8.997-7.973 14.702-19.566 14.702-32.549 0-23.991-19.456-43.447-43.483-43.447-23.991 0-43.447 19.456-43.447 43.447 0 12.946 5.705 24.576 14.702 32.549v0.402h-203.154v-0.402c8.997-7.973 14.702-19.566 14.702-32.549 0-23.991-19.456-43.447-43.447-43.447-24.027 0-43.447 19.456-43.447 43.447 0 12.946 5.669 24.576 14.665 32.549v0.402h-96.841v-440.101h511.561v440.101h-96.512zM732.087 234.569h-437.76v291.694h437.76v-291.694zM619.301 407.113h-55.15v-55.113h55.15v55.113zM619.301 490.021h-55.15v-55.113h55.15v55.113zM619.301 326.51h-55.15v-55.15h55.15v55.15zM696.942 490.021h-55.15v-55.113h55.15v55.113zM696.942 407.113h-55.15v-55.113h55.15v55.113zM386.267 326.51h-55.113v-55.15h55.113v55.15zM463.982 326.51h-55.15v-55.15h55.15v55.15zM463.982 407.113h-55.15v-55.113h55.15v55.113zM386.267 407.113h-55.113v-55.113h55.113v55.113zM541.586 407.113h-55.113v-55.113h55.113v55.113zM541.586 490.021h-55.113v-55.113h55.113v55.113zM463.982 490.021h-55.15v-55.113h55.15v55.113zM541.586 326.51h-55.113v-55.15h55.113v55.15z" /><glyph unicode="" d="M512 677.742l-209.006-253.257h136.338v-206.19h145.298v206.19h136.375z" /><glyph unicode="" d="M584.631 471.515v206.226h-145.298v-206.226h-136.338l209.006-253.221 209.006 253.221z" /><glyph unicode="" d="M836.462 183.918c0 0-109.641 112.677-153.381 156.233-19.054 19.017-32.073 31.927-32.073 31.927 14.848 21.211 26.405 44.361 34.633 69.339s12.361 51.237 12.361 78.848c0 35.621-6.802 69.083-20.334 100.462-13.568 31.305-32 58.697-55.406 82.030-23.369 23.442-50.725 41.874-82.066 55.406-31.305 13.605-64.768 20.37-100.389 20.37-35.584 0-69.047-6.802-100.425-20.37-31.305-13.531-58.551-31.963-81.664-55.406-23.077-23.296-41.435-50.688-54.967-81.993-13.568-31.378-20.334-64.841-20.334-100.462s6.802-69.083 20.334-100.389c13.531-31.305 31.89-58.661 54.967-82.103 23.113-23.333 50.322-41.801 81.664-55.369 31.378-13.568 64.841-20.297 100.425-20.297 27.648 0 53.943 4.023 78.885 12.288s48.091 19.858 69.303 34.706c0 0 11.922-11.959 29.696-29.806 48.421-48.603 155.026-159.159 155.026-159.159 16.018-6.985 41.728 0.439 54.455 11.337s19.858 33.682 9.289 52.407zM612.718 447.013c-9.838-22.747-23.223-42.569-40.155-59.429-16.933-16.933-36.718-30.354-59.429-40.192-22.638-9.874-46.848-14.775-72.521-14.775-26.258 0-50.688 4.937-73.362 14.775s-42.496 23.259-59.429 40.192c-16.896 16.859-30.354 36.681-40.155 59.429-9.838 22.601-14.738 47.104-14.738 73.289 0 25.673 4.901 50.030 14.738 72.997 9.838 22.93 23.259 42.898 40.155 59.794 16.933 16.969 36.754 30.354 59.429 40.155 22.674 9.911 47.104 14.738 73.362 14.738 25.673 0 49.883-4.864 72.521-14.738 22.674-9.801 42.496-23.186 59.429-40.155 16.933-16.933 30.318-36.901 40.155-59.831 9.874-22.967 14.738-47.323 14.738-72.997 0-26.149-4.901-50.651-14.738-73.253z" /><glyph unicode="" d="M695.845 602.661l-29.147 29.111-154.697-154.734-154.734 154.734-29.111-29.111 154.734-154.734-154.624-154.624 29.111-29.074 154.624 154.587 154.661-154.587 29.038 29.074-154.587 154.624z" /><glyph unicode="" d="M470.418 450.158l132.791 136.558-27.794 26.075-158.354-162.853 9.618-9.033-0.11-0.146 153.234-157.55 27.136 26.587z" /><glyph unicode="" d="M512 539.941l-172.398-183.881h344.795z" /><glyph unicode="" d="M392.119 622.043v-348.087l239.726 174.043z" /><glyph unicode="" d="M392.119 448l239.726-174.043v348.087z" /><glyph unicode="" d="M237.714 191.159h73.728v513.682h-73.728v-513.682zM786.286 703.086h-440.283v-292.169h440.283l-148.078 144.128 148.078 148.041z" /><glyph unicode="" d="M787.054 466.359h-256.219v256.695h-36.571v-256.695h-257.317v-36.571h257.317v-256.841h36.571v256.841h256.219z" /><glyph unicode="" d="M769.134 594.286v36.571h-513.17v-25.271l-1.097-1.097 1.097-1.097v-9.106h0.622v-292.571h-0.622v-8.558l-1.097-1.097 1.097-1.097v-25.819h513.17v36.571h-0.585v292.571h0.585zM703.89 301.714h-387.657l119.881 119.881-25.856 25.856-117.138-117.138v236.361l220.014-217.088 25.856 25.856-1.39 1.353 194.377 194.341v-245.87l-122.149 122.149-25.856-25.856 119.918-119.845zM317.221 594.286h386.158l-191.781-191.781-194.377 191.781z" /><glyph unicode="" d="M310.747 210.359h109.166v328.485h-109.166v-328.485zM604.050 355.584v-145.225h109.202v145.225h-109.202zM457.399 210.359h109.202v475.319h-109.202v-475.319z" /><glyph unicode="" d="M310.747 210.359h109.166v328.485h-109.166v-328.485zM347.941 503.625h36.864v-256.768h-36.864v256.768zM604.050 355.584v-145.225h109.202v145.225h-109.202zM677.339 246.711h-36.827v71.863h36.827v-71.863zM457.399 210.359h109.202v475.319h-109.202v-475.319zM494.263 649.838h36.827v-402.834h-36.827v402.834z" /><glyph unicode="" d="M519.57 665.893c-127.232 2.487-231.936-75.922-233.911-175.141-0.695-34.487 11.154-66.926 32.219-94.72l-5.486 5.522c36.242-46.519-34.816-171.52-34.816-171.52l159.232 78.702c25.161-7.936 46.994-1.536 75.63-2.121 127.232-2.487 231.973 75.886 233.911 175.067 2.011 99.255-99.511 181.723-226.779 184.21z" /><glyph unicode="" d="M514.158 489.582l136.558-132.791 26.075 27.794-162.853 158.354-166.729-162.743 26.587-27.136z" /><glyph unicode="" d="M509.842 406.418l-136.558 132.791-26.075-27.794 162.853-158.354 166.729 162.743-26.587 27.136z" /><glyph unicode="" d="M512 52.005c-218.77 0-396.032 177.298-396.032 395.995s177.262 395.995 396.032 395.995c218.661 0 396.032-177.298 396.032-395.995s-177.371-395.995-396.032-395.995zM512 796.087c-191.89 0-348.087-156.197-348.087-348.087 0-191.927 156.197-348.087 348.087-348.087s348.050 156.16 348.050 348.087c-0.037 191.927-156.16 348.087-348.050 348.087zM611.328 442.441l-24.101-18.761c-13.166-10.24-21.87-22.126-26.185-35.84-2.743-8.558-4.681-18.907-4.901-37.12h-92.343c1.353 38.473 5.413 61.842 11.301 76.581 5.925 14.592 21.102 31.488 45.531 50.578l24.795 19.383c8.192 6.181 14.738 12.91 19.785 20.187 8.997 12.471 13.495 26.222 13.495 41.216 0 17.262-5.010 32.987-15.104 47.214-10.057 14.226-28.453 21.321-55.259 21.321-26.295 0-44.946-8.777-55.918-26.295s-16.384-33.463-16.384-52.37h-98.523c2.706 64.805 25.234 108.544 67.73 135.57 26.843 17.298 59.794 25.929 98.889 25.929 51.383 0 94.025-12.288 128-36.827 34.011-24.503 53.87-74.935 53.87-123.173 0-29.55-10.24-40.338-25.051-60.599-8.558-12.288-25.125-27.941-49.627-46.994zM561.042 202.423h-98.231v98.487h98.231v-98.487z" /><glyph unicode="" d="M1.994 518.75h748.928l-283.278 291.206h200.254l354.108-363.956-354.108-363.956h-200.254l283.278 291.174h-748.928v145.532z" /><glyph unicode="" d="M1022.006 375.25h-748.928l283.278-291.206h-200.254l-354.108 363.956 354.108 363.956h200.254l-283.278-291.174h748.928v-145.532z" /><glyph unicode="" d="M85.174 468.026l0.504-106.238 426.322-426.324 426.32 426.324 0.504 106.238-389.444-389.444 0.002 880.006h-74.764v-880.004z" /><glyph unicode="" d="M511.963 831.086c-211.529 0-383.049-171.52-383.049-383.086s171.483-383.086 383.049-383.086c211.602 0 383.086 171.483 383.086 383.086s-171.483 383.086-383.086 383.086zM511.963 794.514c191.086 0 346.514-155.429 346.514-346.514 0-79.909-27.429-153.344-73.070-212.041-5.486 1.975-11.008 3.84-16.274 6.107-34.926 14.629-73.801 31.781-108.654 46.153-9.911 2.706-19.931 5.413-29.842 8.155-11.849 8.155-23.589 35.365-29.915 48.933-6.29 0.914-12.654 1.792-19.017 2.633 0.914 20.992 13.934 22.126 19.017 38.071 4.498 14.080 0.512 32.439 7.57 45.495 4.937 9.070 16.128 9.070 21.65 16.933 5.083 6.985 8.411 19.273 9.984 27.941 2.853 15.799 5.339 37.339-2.158 53.029-4.279 8.96-6.985 9.874-8.229 20.736-1.426 13.275 3.913 56.43 4.133 65.755 0.512 24.21-0.073 26.149-5.925 49.737 0 0-7.058 21.358-18.213 27.831l-22.272 3.803-13.714 12.727c-55.369 34.085-114.761 10.167-146.505-2.67-45.824-14.885-74.789-59.758-54.565-155.538 3.474-16.421-8.96-23.698-8.155-32.658 1.829-19.566 2.158-66.487 20.59-78.080 1.719-1.061 14.811-4.352 14.738-3.438 1.792-19.017 3.621-38.071 5.376-57.015 4.608-12.654 15.689-14.080 18.907-31.927l-14.153-3.438c-6.363-13.568-17.993-40.777-29.879-48.933-9.947-2.706-19.931-5.413-29.879-8.155-34.889-14.373-73.691-31.488-108.654-46.153-1.902-0.768-3.877-1.39-5.815-2.158-43.776 58.112-70.071 130.011-70.071 208.165 0 191.086 155.429 346.514 346.478 346.514z" /><glyph unicode="" d="M427.703 653.019c0-10.569-8.558-19.090-19.090-19.090h-11.154c-10.533 0-19.090 8.521-19.090 19.090v68.462c0 10.533 8.594 19.090 19.090 19.090h11.154c10.533 0 19.090-8.558 19.090-19.090v-68.462zM645.778 653.019c0-10.569-8.521-19.090-19.054-19.090h-11.154c-10.533 0-19.054 8.521-19.054 19.090v68.462c-0.037 10.533 8.485 19.090 19.054 19.090h11.154c10.533 0 19.054-8.558 19.054-19.090v-68.462zM675.182 481.317l-38.729 31.598-152.795-187.282-81.518 64.805-28.891-36.242 120.21-95.634zM758.784 687.982h-71.351v-29.769c0-31.634-25.746-57.344-57.271-57.344h-11.227c-31.598 0-57.271 25.71-57.271 57.344v29.769h-97.682v-29.769c0-31.634-25.71-57.344-57.307-57.344h-11.154c-31.598 0-57.307 25.71-57.307 57.344v29.769h-72.96c-10.533 0-19.090-8.521-19.090-19.054v-494.373c-0.037-10.569 8.558-19.127 19.090-19.127h493.531c10.533 0 19.054 8.558 19.054 19.090v494.409c0 10.533-8.521 19.054-19.054 19.054zM720.567 240.677c0-10.569-8.558-19.090-19.090-19.090h-378.917c-10.569 0-19.090 8.521-19.090 19.090v288.11c0 10.569 8.521 19.054 19.090 19.054h378.88c10.533 0 19.090-8.485 19.090-19.054v-288.11z" /><glyph unicode="" d="M391.863 554.203h-128.219c-10.35 0-18.761-8.375-18.761-18.725v-91.429c0-10.35 8.375-18.725 18.761-18.725h128.219c10.35 0 18.761 8.375 18.761 18.725v91.429c0 10.386-8.375 18.725-18.761 18.725zM391.863 387.511h-90.734c-10.35 0-18.761-8.375-18.761-18.725v-194.633c0-10.35 8.411-18.725 18.761-18.725h90.734c10.35 0 18.761 8.375 18.761 18.725v194.633c0 10.35-8.375 18.725-18.761 18.725zM760.357 554.203h-279.845c-10.35 0-18.725-8.375-18.725-18.725v-91.429c0-10.35 8.375-18.725 18.725-18.725h279.845c10.313 0 18.725 8.375 18.725 18.725v91.429c-0.037 10.386-8.411 18.725-18.725 18.725zM721.701 385.573h-240.64c-10.313 0-18.725-8.375-18.725-18.761v-192.695c0-10.35 8.375-18.725 18.725-18.725h240.64c10.35 0 18.725 8.375 18.725 18.725v192.695c0 10.35-8.375 18.761-18.725 18.761zM507.355 575.634c21.87-3.986 42.971-6.327 62.647-6.327 99.072 0 152.832 53.248 153.088 103.387 0.183 32.293-23.698 67.291-78.117 67.84-72.923 0-118.089-51.493-141.605-89.71-23.918 38.107-69.266 88.576-142.373 88.576-52.882-0.549-76.763-35.547-76.581-67.84 0.256-50.139 54.016-103.424 153.088-103.424 0.037 0 0.037 0 0.037 0 21.394 0 44.398 2.414 68.425 7.241l1.39 0.256zM645.998 693.723c9.143-0.073 30.354-2.304 30.245-20.773-0.11-23.589-33.17-56.795-106.24-56.795-10.057 0-20.553 0.658-31.525 1.938 16.567 29.294 51.566 75.63 107.52 75.63zM437.504 614.985v0c-73.106 0-106.167 33.207-106.277 56.795-0.11 18.469 21.102 20.699 31.305 20.809 55.259 0 90.039-46.373 106.496-75.666-10.935-1.28-21.467-1.938-31.525-1.938z" /><glyph unicode="" d="M938.824 426.028l-0.504 106.238-426.32 426.322-426.322-426.322-0.504-106.238 389.444 389.442v-880.006h74.764v880.006z" /></font></defs></svg> \ No newline at end of file diff --git a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.ttf b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.ttf index eaec02d1df42b6b0208db02f1da2a3fb3bcae7fd..6fabe5c3e89948ff20801ea1e43e18b15c9c4da1 100644 Binary files a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.ttf and b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.ttf differ diff --git a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff index e9e8395b2574bc6cfbb3c2606213ca204179bf51..a8e688940c486205bcbc8bb9b787af33c1a8db86 100644 Binary files a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff and b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff differ diff --git a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff2 b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff2 index 1d60f2f95c0facb689b7a0079cfb2b2312bcab17..e1fc31afbdaf56fd0fc3cfb09180f52be6f1b569 100644 Binary files a/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff2 and b/lib/web/fonts/Blank-Theme-Icons/Blank-Theme-Icons.woff2 differ diff --git a/lib/web/fonts/Blank-Theme-Icons/selection.json b/lib/web/fonts/Blank-Theme-Icons/selection.json index e3a71a30c6ae96426ed01b4041c20ae392e1e909..2e8beab777f8a696acbbbb6d6b4ce523f9d2f481 100644 --- a/lib/web/fonts/Blank-Theme-Icons/selection.json +++ b/lib/web/fonts/Blank-Theme-Icons/selection.json @@ -1,6 +1,34 @@ { "IcoMoonType": "selection", "icons": [ + { + "icon": { + "paths": [ + "M512 907.995c-218.77 0-396.032-177.298-396.032-395.995s177.262-395.995 396.032-395.995c218.661 0 396.032 177.298 396.032 395.995s-177.371 395.995-396.032 395.995zM512 163.913c-191.89 0-348.087 156.197-348.087 348.087 0 191.927 156.197 348.087 348.087 348.087s348.050-156.16 348.050-348.087c-0.037-191.927-156.16-348.087-348.050-348.087zM611.328 517.559l-24.101 18.761c-13.166 10.24-21.87 22.126-26.185 35.84-2.743 8.558-4.681 18.907-4.901 37.12h-92.343c1.353-38.473 5.413-61.842 11.301-76.581 5.925-14.592 21.102-31.488 45.531-50.578l24.795-19.383c8.192-6.181 14.738-12.91 19.785-20.187 8.997-12.471 13.495-26.222 13.495-41.216 0-17.262-5.010-32.987-15.104-47.214-10.057-14.226-28.453-21.321-55.259-21.321-26.295 0-44.946 8.777-55.918 26.295s-16.384 33.463-16.384 52.37h-98.523c2.706-64.805 25.234-108.544 67.73-135.57 26.843-17.298 59.794-25.929 98.889-25.929 51.383 0 94.025 12.288 128 36.827 34.011 24.503 53.87 74.935 53.87 123.173 0 29.55-10.24 40.338-25.051 60.599-8.558 12.288-25.125 27.941-49.627 46.994zM561.042 757.577h-98.231v-98.487h98.231v98.487z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "grid": 0, + "tags": [ + "help" + ] + }, + "attrs": [ + {} + ], + "properties": { + "order": 44, + "id": 37, + "prevSize": 32, + "code": 58915, + "name": "help" + }, + "setIdx": 0, + "setId": 1, + "iconIdx": 0 + }, { "icon": { "paths": [ @@ -36,7 +64,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 0 + "iconIdx": 1 }, { "icon": { @@ -76,7 +104,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 1 + "iconIdx": 2 }, { "icon": { @@ -100,7 +128,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 2 + "iconIdx": 3 }, { "icon": { @@ -118,13 +146,13 @@ "order": 36, "id": 3, "prevSize": 32, - "code": 58915, + "code": 58931, "name": "arrow-up-thin", "ligatures": "" }, "setIdx": 0, "setId": 1, - "iconIdx": 3 + "iconIdx": 4 }, { "icon": { @@ -148,7 +176,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 4 + "iconIdx": 5 }, { "icon": { @@ -172,7 +200,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 5 + "iconIdx": 6 }, { "icon": { @@ -196,7 +224,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 6 + "iconIdx": 7 }, { "icon": { @@ -220,7 +248,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 7 + "iconIdx": 8 }, { "icon": { @@ -244,7 +272,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 8 + "iconIdx": 9 }, { "icon": { @@ -268,7 +296,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 9 + "iconIdx": 10 }, { "icon": { @@ -292,7 +320,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 10 + "iconIdx": 11 }, { "icon": { @@ -316,7 +344,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 11 + "iconIdx": 12 }, { "icon": { @@ -340,7 +368,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 12 + "iconIdx": 13 }, { "icon": { @@ -364,7 +392,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 13 + "iconIdx": 14 }, { "icon": { @@ -388,7 +416,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 14 + "iconIdx": 15 }, { "icon": { @@ -412,7 +440,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 15 + "iconIdx": 16 }, { "icon": { @@ -436,7 +464,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 16 + "iconIdx": 17 }, { "icon": { @@ -460,7 +488,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 17 + "iconIdx": 18 }, { "icon": { @@ -484,7 +512,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 18 + "iconIdx": 19 }, { "icon": { @@ -508,7 +536,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 19 + "iconIdx": 20 }, { "icon": { @@ -532,7 +560,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 20 + "iconIdx": 21 }, { "icon": { @@ -556,7 +584,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 21 + "iconIdx": 22 }, { "icon": { @@ -580,7 +608,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 22 + "iconIdx": 23 }, { "icon": { @@ -604,7 +632,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 23 + "iconIdx": 24 }, { "icon": { @@ -628,7 +656,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 24 + "iconIdx": 25 }, { "icon": { @@ -652,7 +680,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 25 + "iconIdx": 26 }, { "icon": { @@ -676,7 +704,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 26 + "iconIdx": 27 }, { "icon": { @@ -700,7 +728,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 27 + "iconIdx": 28 }, { "icon": { @@ -724,7 +752,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 28 + "iconIdx": 29 }, { "icon": { @@ -748,7 +776,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 29 + "iconIdx": 30 }, { "icon": { @@ -772,7 +800,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 30 + "iconIdx": 31 }, { "icon": { @@ -796,7 +824,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 31 + "iconIdx": 32 }, { "icon": { @@ -820,7 +848,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 32 + "iconIdx": 33 }, { "icon": { @@ -844,7 +872,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 33 + "iconIdx": 34 }, { "icon": { @@ -868,7 +896,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 34 + "iconIdx": 35 }, { "icon": { @@ -892,7 +920,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 35 + "iconIdx": 36 }, { "icon": { @@ -916,7 +944,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 36 + "iconIdx": 37 }, { "icon": { @@ -940,7 +968,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 37 + "iconIdx": 38 }, { "icon": { @@ -964,7 +992,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 38 + "iconIdx": 39 }, { "icon": { @@ -988,7 +1016,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 39 + "iconIdx": 40 }, { "icon": { @@ -1012,7 +1040,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 40 + "iconIdx": 41 }, { "icon": { @@ -1036,7 +1064,7 @@ }, "setIdx": 0, "setId": 1, - "iconIdx": 41 + "iconIdx": 42 } ], "height": 1024, diff --git a/lib/web/mage/dropdown.js b/lib/web/mage/dropdown.js index 61e44e1ee501264a5757973d94e7e6bade643118..dbf04d0da9387841fa28ab1050894fcf3b5fb236 100644 --- a/lib/web/mage/dropdown.js +++ b/lib/web/mage/dropdown.js @@ -36,6 +36,7 @@ define([ autoSize: false, draggable: false, resizable: false, + bodyClass: '', buttons: [ { 'class': "action close", @@ -111,6 +112,9 @@ define([ if(_self.options.parentClass) { $(_self.options.appendTo).addClass(_self.options.parentClass); } + if(_self.options.bodyClass) { + $('body').addClass(_self.options.bodyClass); + } if (_self.options.shadowHinter) { _self._setShadowHinterPosition(); @@ -132,6 +136,9 @@ define([ if(this.options.parentClass) { $(this.options.appendTo).removeClass(this.options.parentClass); } + if(this.options.bodyClass) { + $('body').removeClass(this.options.bodyClass); + } if(timer) { clearTimeout(timer); } diff --git a/lib/web/mage/loader.js b/lib/web/mage/loader.js index a4bfc58b7859edd2cff3c200bd37a67733fc32c7..455ba80c692df017ad30293b761036b0b54f9f56 100644 --- a/lib/web/mage/loader.js +++ b/lib/web/mage/loader.js @@ -194,18 +194,10 @@ define([ }, _onAjaxComplete: function (e, jqxhr, settings) { - var ariaSelected = $('[aria-selected="true"]'); - $(this.options.defaultContainer) .removeClass(this.options.loadingClass) .attr('aria-busy', false); - // ARIA support - if (ariaSelected.length) { - ariaSelected.first().focus(); - $(this.options.defaultContainer).addClass('_keyfocus'); - } - if (settings && settings.showLoader) { this._getJqueryObj(settings.loaderContext).trigger('processStop'); } diff --git a/lib/web/mage/storage.js b/lib/web/mage/storage.js index ea0b6b432ba9d0b8316b1f714c92c50e697f3d62..3c6bd89ca1ebf0de4d964a4533cf9ffd1ff8e20d 100644 --- a/lib/web/mage/storage.js +++ b/lib/web/mage/storage.js @@ -2,34 +2,83 @@ * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*global define*/ define(['jquery', 'mage/url'], function ($, urlBuilder) { - "use strict"; + 'use strict'; + return { - get: function (url, contentType) { + /** + * Perform asynchronous GET request to server. + * @param {String} url + * @param {Boolean} global + * @param {String} contentType + * @returns {Deferred} + */ + get: function (url, global, contentType) { + global = global === undefined ? true : global; contentType = contentType || 'application/json'; + return $.ajax({ url: urlBuilder.build(url), type: 'GET', - async: false, + global: global, contentType: contentType }); }, - post: function(url, data, contentType) { + /** + * Perform asynchronous POST request to server. + * @param {String} url + * @param {String} data + * @param {Boolean} global + * @param {String} contentType + * @returns {Deferred} + */ + post: function (url, data, global, contentType) { + global = global === undefined ? true : global; contentType = contentType || 'application/json'; + return $.ajax({ url: urlBuilder.build(url), type: 'POST', data: data, + global: global, contentType: contentType }); }, - put: function(url, data, contentType) { + /** + * Perform asynchronous PUT request to server. + * @param {String} url + * @param {String} data + * @param {Boolean} global + * @param {String} contentType + * @returns {Deferred} + */ + put: function(url, data, global, contentType) { + global = global === undefined ? true : global; contentType = contentType || 'application/json'; + return $.ajax({ url: urlBuilder.build(url), type: 'PUT', data: data, + global: global, + contentType: contentType + }); + }, + /** + * Perform asynchronous DELETE request to server. + * @param {String} url + * @param {Boolean} global + * @param {String} contentType + * @returns {Deferred} + */ + delete: function(url, global, contentType) { + global = global === undefined ? true : global; + contentType = contentType || 'application/json'; + + return $.ajax({ + url: urlBuilder.build(url), + type: 'DELETE', + global: global, contentType: contentType }); }