diff --git a/app/code/Magento/Payment/Plugin/PaymentConfigurationProcess.php b/app/code/Magento/Payment/Plugin/PaymentConfigurationProcess.php
new file mode 100644
index 0000000000000..ff5d7b356e604
--- /dev/null
+++ b/app/code/Magento/Payment/Plugin/PaymentConfigurationProcess.php
@@ -0,0 +1,73 @@
+paymentMethodList = $paymentMethodList;
+ $this->storeManager = $storeManager;
+ }
+
+ /**
+ * Checkout LayoutProcessor before process plugin.
+ *
+ * @param \Magento\Checkout\Block\Checkout\LayoutProcessor $processor
+ * @param array $jsLayout
+ * @return array
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeProcess(\Magento\Checkout\Block\Checkout\LayoutProcessor $processor, $jsLayout)
+ {
+ $configuration = &$jsLayout['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'];
+
+ if (!isset($configuration)) {
+ return [$jsLayout];
+ }
+
+ $storeId = $this->storeManager->getStore()->getId();
+ $activePaymentMethodList = $this->paymentMethodList->getActiveList($storeId);
+ $getCodeFunc = function ($method) {
+ return $method->getCode();
+ };
+ $activePaymentMethodCodes = array_map($getCodeFunc, $activePaymentMethodList);
+
+ foreach ($configuration as $paymentGroup => $groupConfig) {
+ $notActivePaymentMethodCodes = array_diff(array_keys($groupConfig['methods']), $activePaymentMethodCodes);
+ foreach ($notActivePaymentMethodCodes as $notActivePaymentMethodCode) {
+ unset($configuration[$paymentGroup]['methods'][$notActivePaymentMethodCode]);
+ }
+ if (empty($configuration[$paymentGroup]['methods'])) {
+ unset($configuration[$paymentGroup]);
+ }
+ }
+
+ return [$jsLayout];
+ }
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Plugin/PaymentConfigurationProcessTest.php b/app/code/Magento/Payment/Test/Unit/Plugin/PaymentConfigurationProcessTest.php
new file mode 100644
index 0000000000000..646c7bcb670c3
--- /dev/null
+++ b/app/code/Magento/Payment/Test/Unit/Plugin/PaymentConfigurationProcessTest.php
@@ -0,0 +1,146 @@
+storeManager = $this
+ ->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getStore'])
+ ->getMockForAbstractClass();
+ $this->store = $this
+ ->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getId'])
+ ->getMockForAbstractClass();
+ $this->paymentMethodList = $this
+ ->getMockBuilder(\Magento\Payment\Api\PaymentMethodListInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getActiveList'])
+ ->getMockForAbstractClass();
+ $this->layoutProcessor = $this
+ ->getMockBuilder(\Magento\Checkout\Block\Checkout\LayoutProcessor::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['process'])
+ ->getMockForAbstractClass();
+
+ $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+ $this->plugin = $objectManagerHelper->getObject(
+ \Magento\Payment\Plugin\PaymentConfigurationProcess::class,
+ [
+ 'paymentMethodList' => $this->paymentMethodList,
+ 'storeManager' => $this->storeManager
+ ]
+ );
+ }
+
+ /**
+ * @param array $jsLayout
+ * @param array $activePaymentList
+ * @param array $expectedResult
+ * @dataProvider beforeProcessDataProvider
+ */
+ public function testBeforeProcess($jsLayout, $activePaymentList, $expectedResult)
+ {
+ $this->store->expects($this->once())->method('getId')->willReturn(1);
+ $this->storeManager->expects($this->once())->method('getStore')->willReturn($this->store);
+ $this->paymentMethodList->expects($this->once())
+ ->method('getActiveList')
+ ->with(1)
+ ->willReturn($activePaymentList);
+
+ $result = $this->plugin->beforeProcess($this->layoutProcessor, $jsLayout);
+ $this->assertEquals($result[0], $expectedResult);
+ }
+
+ /**
+ * Data provider for BeforeProcess.
+ *
+ * @return array
+ */
+ public function beforeProcessDataProvider()
+ {
+ $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'] = [
+ 'braintree' => [
+ 'methods' => [
+ 'braintree_paypal' => [],
+ 'braintree' => []
+ ]
+ ],
+ 'paypal-payments' => [
+ 'methods' => [
+ 'payflowpro' => [],
+ 'payflow_link' => []
+ ]
+ ]
+ ];
+ $result1['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'] = [];
+ $result2['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'] = [
+ 'braintree' => [
+ 'methods' => [
+ 'braintree' => [],
+ 'braintree_paypal' => []
+ ]
+ ]
+ ];
+
+ $braintreePaymentMethod = $this
+ ->getMockBuilder(\Magento\Payment\Api\Data\PaymentMethodInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getCode'])
+ ->getMockForAbstractClass();
+ $braintreePaypalPaymentMethod = $this
+ ->getMockBuilder(\Magento\Payment\Api\Data\PaymentMethodInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getCode'])
+ ->getMockForAbstractClass();
+
+ $braintreePaymentMethod->expects($this->any())->method('getCode')->willReturn('braintree');
+ $braintreePaypalPaymentMethod->expects($this->any())->method('getCode')->willReturn('braintree_paypal');
+
+ return [
+ [$jsLayout, [], $result1],
+ [$jsLayout, [$braintreePaymentMethod, $braintreePaypalPaymentMethod], $result2]
+ ];
+ }
+}
diff --git a/app/code/Magento/Payment/etc/frontend/di.xml b/app/code/Magento/Payment/etc/frontend/di.xml
index d86147b109366..e3d9c3593c6c4 100644
--- a/app/code/Magento/Payment/etc/frontend/di.xml
+++ b/app/code/Magento/Payment/etc/frontend/di.xml
@@ -19,4 +19,7 @@
+
+
+
diff --git a/app/code/Magento/Vault/Plugin/PaymentVaultConfigurationProcess.php b/app/code/Magento/Vault/Plugin/PaymentVaultConfigurationProcess.php
new file mode 100644
index 0000000000000..d0fa85925afbe
--- /dev/null
+++ b/app/code/Magento/Vault/Plugin/PaymentVaultConfigurationProcess.php
@@ -0,0 +1,93 @@
+vaultPaymentList = $vaultPaymentList;
+ $this->paymentMethodList = $paymentMethodList;
+ $this->storeManager = $storeManager;
+ }
+
+ /**
+ * Checkout LayoutProcessor before process plugin.
+ *
+ * @param \Magento\Checkout\Block\Checkout\LayoutProcessor $processor
+ * @param array $jsLayout
+ * @return array
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeProcess(\Magento\Checkout\Block\Checkout\LayoutProcessor $processor, $jsLayout)
+ {
+ $configuration = &$jsLayout['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'];
+
+ if (!isset($configuration)) {
+ return [$jsLayout];
+ }
+
+ $storeId = $this->storeManager->getStore()->getId();
+ $activePaymentMethodList = $this->paymentMethodList->getActiveList($storeId);
+ $activeVaultList = $this->vaultPaymentList->getActiveList($storeId);
+ $getCodeFunc = function ($method) {
+ return $method->getCode();
+ };
+ $getProviderCodeFunc = function ($method) {
+ return $method->getProviderCode();
+ };
+ $activePaymentMethodCodes = array_map($getCodeFunc, $activePaymentMethodList);
+ $activeVaultProviderCodes = array_map($getProviderCodeFunc, $activeVaultList);
+ $activePaymentMethodCodes = array_merge(
+ $activePaymentMethodCodes,
+ $activeVaultProviderCodes
+ );
+
+ foreach ($configuration as $paymentGroup => $groupConfig) {
+ $notActivePaymentMethodCodes = array_diff(array_keys($groupConfig['methods']), $activePaymentMethodCodes);
+ foreach ($notActivePaymentMethodCodes as $notActivePaymentMethodCode) {
+ unset($configuration[$paymentGroup]['methods'][$notActivePaymentMethodCode]);
+ }
+ if ($paymentGroup === 'vault' && !empty($activeVaultProviderCodes)) {
+ continue;
+ }
+ if (empty($configuration[$paymentGroup]['methods'])) {
+ unset($configuration[$paymentGroup]);
+ }
+ }
+
+ return [$jsLayout];
+ }
+}
diff --git a/app/code/Magento/Vault/Test/Unit/Plugin/PaymentVaultConfigurationProcessTest.php b/app/code/Magento/Vault/Test/Unit/Plugin/PaymentVaultConfigurationProcessTest.php
new file mode 100644
index 0000000000000..ea23616887018
--- /dev/null
+++ b/app/code/Magento/Vault/Test/Unit/Plugin/PaymentVaultConfigurationProcessTest.php
@@ -0,0 +1,158 @@
+storeManager = $this
+ ->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getStore'])
+ ->getMockForAbstractClass();
+ $this->store = $this
+ ->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getId'])
+ ->getMockForAbstractClass();
+ $this->vaultList = $this
+ ->getMockBuilder(\Magento\Vault\Api\PaymentMethodListInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getActiveList'])
+ ->getMockForAbstractClass();
+ $this->paymentMethodList = $this
+ ->getMockBuilder(\Magento\Payment\Api\PaymentMethodListInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getActiveList'])
+ ->getMockForAbstractClass();
+ $this->layoutProcessor = $this
+ ->getMockBuilder(\Magento\Checkout\Block\Checkout\LayoutProcessor::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['process'])
+ ->getMockForAbstractClass();
+
+ $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+ $this->plugin = $objectManagerHelper->getObject(
+ \Magento\Vault\Plugin\PaymentVaultConfigurationProcess::class,
+ [
+ 'vaultPaymentList' => $this->vaultList,
+ 'paymentMethodList' => $this->paymentMethodList,
+ 'storeManager' => $this->storeManager
+ ]
+ );
+ }
+
+ /**
+ * @param array $jsLayout
+ * @param array $activeVaultList
+ * @param array $activePaymentList
+ * @param array $expectedResult
+ * @dataProvider beforeProcessDataProvider
+ */
+ public function testBeforeProcess($jsLayout, $activeVaultList, $activePaymentList, $expectedResult)
+ {
+ $this->store->expects($this->once())->method('getId')->willReturn(1);
+ $this->storeManager->expects($this->once())->method('getStore')->willReturn($this->store);
+ $this->vaultList->expects($this->once())->method('getActiveList')->with(1)->willReturn($activeVaultList);
+ $this->paymentMethodList->expects($this->once())
+ ->method('getActiveList')
+ ->with(1)
+ ->willReturn($activePaymentList);
+ $result = $this->plugin->beforeProcess($this->layoutProcessor, $jsLayout);
+ $this->assertEquals($result[0], $expectedResult);
+ }
+
+ /**
+ * Data provider for BeforeProcess.
+ *
+ * @return array
+ */
+ public function beforeProcessDataProvider()
+ {
+ $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'] = [
+ 'vault' => [
+ 'methods' => []
+ ],
+ 'braintree' => [
+ 'methods' => [
+ 'braintree_paypal' => [],
+ 'braintree' => []
+ ]
+ ],
+ 'paypal-payments' => [
+ 'methods' => [
+ 'payflowpro' => [],
+ 'payflow_link' => []
+ ]
+ ]
+ ];
+ $result1['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'] = [];
+ $result2['components']['checkout']['children']['steps']['children']['billing-step']
+ ['children']['payment']['children']['renders']['children'] = [
+ 'vault' => [
+ 'methods' => []
+ ],
+ 'braintree' => [
+ 'methods' => [
+ 'braintree_paypal' => []
+ ]
+ ]
+ ];
+
+ $vaultPaymentMethod = $this
+ ->getMockBuilder(\Magento\Vault\Api\PaymentMethodListInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getCode', 'getProviderCode'])
+ ->getMockForAbstractClass();
+
+ $vaultPaymentMethod->expects($this->any())->method('getCode')->willReturn('braintree_paypal_vault');
+ $vaultPaymentMethod->expects($this->any())->method('getProviderCode')->willReturn('braintree_paypal');
+
+ return [
+ [$jsLayout, [], [], $result1],
+ [$jsLayout, [$vaultPaymentMethod], [$vaultPaymentMethod], $result2]
+ ];
+ }
+}
diff --git a/app/code/Magento/Vault/etc/frontend/di.xml b/app/code/Magento/Vault/etc/frontend/di.xml
index faa72294f6ba8..598a30aa1c73b 100644
--- a/app/code/Magento/Vault/etc/frontend/di.xml
+++ b/app/code/Magento/Vault/etc/frontend/di.xml
@@ -19,4 +19,8 @@
Magento\Customer\Model\Session
+
+
+
+