Skip to content

Commit f52dc52

Browse files
committed
Merge remote-tracking branch 'origin/ACP2E-4270' into PR_2025_10_24_muntianu
2 parents 0ba5385 + 3a23292 commit f52dc52

File tree

6 files changed

+283
-13
lines changed

6 files changed

+283
-13
lines changed

app/code/Magento/Paypal/Model/Payflowpro.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,18 @@ public function getConfig()
604604
return $this->config;
605605
}
606606

607+
/**
608+
* @inheritdoc
609+
*/
610+
public function setStore($storeId)
611+
{
612+
parent::setStore($storeId);
613+
if ($this->config) {
614+
$storeId = $this->storeManager->getStore($this->getStore())->getId();
615+
$this->config->setStoreId($storeId);
616+
}
617+
}
618+
607619
/**
608620
* @inheritdoc
609621
*

app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Magento\Framework\HTTP\LaminasClient;
1616
use Magento\Framework\HTTP\LaminasClientFactory;
1717
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
18+
use Magento\Framework\TestFramework\Unit\Matcher\MethodInvokedAtIndex;
1819
use Magento\Payment\Model\Info;
1920
use Magento\Payment\Model\InfoInterface;
2021
use Magento\Payment\Model\Method\ConfigInterface;
@@ -481,16 +482,17 @@ public function testRefund(): void
481482
*/
482483
protected function initStoreMock(): void
483484
{
484-
$storeId = 27;
485-
$storeMock = $this->getMockBuilder(Store::class)->disableOriginalConstructor()
486-
->onlyMethods(['getId'])
487-
->getMock();
488-
$this->storeManagerMock->expects(static::once())
485+
$this->storeManagerMock->expects(static::any())
489486
->method('getStore')
490-
->willReturn($storeMock);
491-
$storeMock->expects(static::once())
492-
->method('getId')
493-
->willReturn($storeId);
487+
->willReturnCallback(
488+
function ($storeId) {
489+
$storeMock = $this->createPartialMock(Store::class, ['getId']);
490+
$storeMock->expects(static::once())
491+
->method('getId')
492+
->willReturn($storeId === null ? 1 : $storeId);
493+
return $storeMock;
494+
}
495+
);
494496
}
495497

496498
/**
@@ -806,4 +808,20 @@ public static function dataProviderMapGatewayResponse(): array
806808
]
807809
];
808810
}
811+
812+
public function testSetStore(): void
813+
{
814+
$storeId = 2;
815+
$this->initStoreMock();
816+
$this->configMock->expects($this->exactly(2))
817+
->method('setStoreId');
818+
$this->configMock->expects(new MethodInvokedAtIndex(0))
819+
->method('setStoreId')
820+
->with(1);
821+
$this->configMock->expects(new MethodInvokedAtIndex(1))
822+
->method('setStoreId')
823+
->with($storeId);
824+
$this->payflowpro->getConfig();
825+
$this->payflowpro->setStore($storeId);
826+
}
809827
}

app/code/Magento/Vault/Model/Method/Vault.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
use Magento\Framework\Serialize\Serializer\Json;
2626

2727
/**
28-
* Class Vault
28+
* Vault payment method
2929
*
3030
* @SuppressWarnings(PHPMD.ExcessivePublicCount)
3131
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -38,7 +38,7 @@ class Vault implements VaultPaymentInterface
3838
/**
3939
* @deprecated
4040
*/
41-
const TOKEN_METADATA_KEY = 'token_metadata';
41+
public const TOKEN_METADATA_KEY = 'token_metadata';
4242

4343
/**
4444
* @var string
@@ -202,6 +202,7 @@ public function getTitle()
202202
public function setStore($storeId)
203203
{
204204
$this->storeId = (int)$storeId;
205+
$this->vaultProvider->setStore($storeId);
205206
}
206207

207208
/**
@@ -488,6 +489,7 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount)
488489
);
489490

490491
$payment->setMethod($this->vaultProvider->getCode());
492+
return $this;
491493
}
492494

493495
/**
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Vault\Test\Fixture;
10+
11+
use Magento\Framework\DataObject;
12+
use Magento\Framework\Encryption\EncryptorInterface;
13+
use Magento\TestFramework\Fixture\DataFixtureInterface;
14+
use Magento\Vault\Api\Data\PaymentTokenFactoryInterface;
15+
use Magento\Vault\Api\PaymentTokenRepositoryInterface;
16+
use Magento\Vault\Model\PaymentTokenFactory;
17+
18+
/**
19+
* Create a payment token for a customer
20+
*
21+
* Example: Basic usage. This will create a payment token for a customer
22+
* ```php
23+
* #[
24+
* DataFixture(CustomerFixture::class, as: 'customer'),
25+
* DataFixture(PaymentTokenFixture::class, ['customer_id' => '$customer.id$'], as: 'token'),
26+
* DataFixture(
27+
* SetPaymentMethodFixture::class,
28+
* [
29+
* 'cart_id' => '$cart.id$',
30+
* 'method' => [
31+
* 'method' => 'payflowpro_cc_vault',
32+
* 'additional_data' => [
33+
* 'public_hash' => '$token.public_hash$',
34+
* 'customer_id' => '$customer.id$',
35+
* ]
36+
* ]
37+
* ]
38+
* )
39+
* ]
40+
* ```
41+
*/
42+
class PaymentToken implements DataFixtureInterface
43+
{
44+
private const DEFAULT_DATA = [
45+
'entity_id' => null,
46+
'customer_id' => null,
47+
'website_id' => null,
48+
'public_hash' => null,
49+
'payment_method_code' => null,
50+
'type' => PaymentTokenFactoryInterface::TOKEN_TYPE_CREDIT_CARD,
51+
'expires_at' => null,
52+
'created_at' => null,
53+
'gateway_token' => null,
54+
'token_details' => null,
55+
'is_visible' => true,
56+
'is_active' => true,
57+
];
58+
59+
/**
60+
* @param PaymentTokenRepositoryInterface $paymentTokenRepository
61+
* @param PaymentTokenFactory $paymentTokenFactory
62+
* @param EncryptorInterface $encryptor
63+
*/
64+
public function __construct(
65+
private readonly PaymentTokenRepositoryInterface $paymentTokenRepository,
66+
private readonly PaymentTokenFactory $paymentTokenFactory,
67+
private readonly EncryptorInterface $encryptor
68+
) {
69+
}
70+
71+
/**
72+
* @inheritDoc
73+
*/
74+
public function apply(array $data = []): ?DataObject
75+
{
76+
$data = array_merge(
77+
self::DEFAULT_DATA,
78+
[
79+
'expires_at' => strtotime('+1 year'),
80+
'public_hash' => $this->encryptor->hash(uniqid((string) $data['customer_id']))
81+
],
82+
$data
83+
);
84+
$token = $this->paymentTokenFactory->create($data['type']);
85+
$token->addData($data);
86+
$this->paymentTokenRepository->save($token);
87+
return $token;
88+
}
89+
}

app/code/Magento/Vault/Test/Unit/Model/Method/VaultTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,4 +393,20 @@ public static function internalUsageDataProvider()
393393
['configValue' => null, 'paymentValue' => null, 'expected' => false],
394394
];
395395
}
396+
397+
public function testSetStore(): void
398+
{
399+
$storeId = 2;
400+
/** @var Vault $model */
401+
$model = $this->objectManager->getObject(
402+
Vault::class,
403+
[
404+
'vaultProvider' => $this->vaultProvider,
405+
]
406+
);
407+
$this->vaultProvider->expects($this->once())
408+
->method('setStore')
409+
->willReturn($storeId);
410+
$model->setStore($storeId);
411+
}
396412
}

dev/tests/integration/testsuite/Magento/Paypal/Model/Payflow/TransparentTest.php

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,48 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2020 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

88
namespace Magento\Paypal\Model\Payflow;
99

10+
use Laminas\Http\Response;
11+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
1012
use Magento\Checkout\Api\PaymentInformationManagementInterface;
13+
use Magento\Checkout\Test\Fixture\SetBillingAddress as SetBillingAddressFixture;
14+
use Magento\Checkout\Test\Fixture\SetDeliveryMethod as SetDeliveryMethodFixture;
15+
use Magento\Checkout\Test\Fixture\SetGuestEmail as SetGuestEmailFixture;
16+
use Magento\Checkout\Test\Fixture\SetPaymentMethod as SetPaymentMethodFixture;
17+
use Magento\Checkout\Test\Fixture\SetShippingAddress as SetShippingAddressFixture;
18+
use Magento\Customer\Test\Fixture\Customer as CustomerFixture;
1119
use Magento\Framework\Api\SearchCriteriaBuilder;
20+
use Magento\Framework\HTTP\LaminasClient;
21+
use Magento\Framework\HTTP\LaminasClientFactory;
22+
use Magento\Payment\Model\MethodInterface;
1223
use Magento\Paypal\Model\Config;
24+
use Magento\Paypal\Model\Payflow\Service\Gateway;
1325
use Magento\Paypal\Model\Payflowpro;
26+
use Magento\Quote\Api\CartManagementInterface;
1427
use Magento\Quote\Api\CartRepositoryInterface;
1528
use Magento\Quote\Api\Data\CartInterface;
29+
use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
30+
use Magento\Quote\Test\Fixture\CustomerCart as CustomerCartFixture;
1631
use Magento\Sales\Api\Data\TransactionInterface;
1732
use Magento\Sales\Api\OrderManagementInterface;
1833
use Magento\Sales\Api\OrderRepositoryInterface;
1934
use Magento\Sales\Api\TransactionRepositoryInterface;
2035
use Magento\Sales\Model\Order;
36+
use Magento\Store\Model\ScopeInterface;
37+
use Magento\Store\Test\Fixture\Store as StoreFixture;
38+
use Magento\TestFramework\Fixture\Config as ConfigFixture;
39+
use Magento\TestFramework\Fixture\DataFixture;
40+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
41+
use Magento\TestFramework\Fixture\DbIsolation;
2142
use Magento\TestFramework\Helper\Bootstrap;
2243
use Magento\TestFramework\ObjectManager;
44+
use Magento\Vault\Model\Method\Vault;
45+
use Magento\Vault\Test\Fixture\PaymentToken as PaymentTokenFixture;
2346
use PHPUnit\Framework\TestCase;
2447

2548
/**
@@ -88,6 +111,78 @@ public function testPlaceOrderSuspectedFraud(): void
88111
);
89112
}
90113

114+
#[
115+
DbIsolation(false),
116+
DataFixture(StoreFixture::class, ['code' => 'test_vault_store'], as: 'store2'),
117+
ConfigFixture('payment/payflowpro/active', '1', ScopeInterface::SCOPE_STORE, 'default'),
118+
ConfigFixture('payment/payflowpro/cctypes', '1', ScopeInterface::SCOPE_STORE, 'default'),
119+
ConfigFixture('payment/payflowpro/payment_action', 'Authorization', ScopeInterface::SCOPE_STORE, 'default'),
120+
ConfigFixture('payment/payflowpro/allowspecific', '1', ScopeInterface::SCOPE_STORE, 'default'),
121+
ConfigFixture('payment/payflowpro/specificcountry', 'US', ScopeInterface::SCOPE_STORE, 'default'),
122+
ConfigFixture('payment/payflowpro_cc_vault/active', '1', ScopeInterface::SCOPE_STORE, 'default'),
123+
// second store config
124+
ConfigFixture('payment/payflowpro/active', '1', ScopeInterface::SCOPE_STORE, 'test_vault_store'),
125+
ConfigFixture('payment/payflowpro/cctypes', '1', ScopeInterface::SCOPE_STORE, 'test_vault_store'),
126+
ConfigFixture('payment/payflowpro/payment_action', 'Sale', ScopeInterface::SCOPE_STORE, 'test_vault_store'),
127+
ConfigFixture('payment/payflowpro/allowspecific', '1', ScopeInterface::SCOPE_STORE, 'test_vault_store'),
128+
ConfigFixture('payment/payflowpro/specificcountry', 'UK', ScopeInterface::SCOPE_STORE, 'test_vault_store'),
129+
ConfigFixture('payment/payflowpro_cc_vault/active', '1', ScopeInterface::SCOPE_STORE, 'test_vault_store'),
130+
131+
DataFixture(CustomerFixture::class, as: 'customer'),
132+
DataFixture(CustomerCartFixture::class, ['customer_id' => '$customer.id$'], as: 'cart'),
133+
DataFixture(ProductFixture::class, as:'product'),
134+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$']),
135+
DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$cart.id$']),
136+
DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$cart.id$']),
137+
DataFixture(SetGuestEmailFixture::class, ['cart_id' => '$cart.id$']),
138+
DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$cart.id$']),
139+
DataFixture(
140+
PaymentTokenFixture::class,
141+
['customer_id' => '$customer.id$', 'payment_method_code' => 'payflowpro'],
142+
as: 'token'
143+
),
144+
DataFixture(
145+
SetPaymentMethodFixture::class,
146+
[
147+
'cart_id' => '$cart.id$',
148+
'method' => [
149+
'method' => 'payflowpro_cc_vault',
150+
'additional_data' => [
151+
'public_hash' => '$token.public_hash$',
152+
'customer_id' => '$customer.id$',
153+
]
154+
]
155+
]
156+
),
157+
]
158+
public function testStoreConfiguration(): void
159+
{
160+
$fixtures = DataFixtureStorageManager::getStorage();
161+
$cartRepository = $this->objectManager->get(CartRepositoryInterface::class);
162+
$cart = $fixtures->get('cart');
163+
$store = $fixtures->get('store2');
164+
$cart = $cartRepository->get($cart->getId());
165+
$cart->setStoreId($store->getId());
166+
$this->assertNotEmpty($cart->getPayment()->getMethod());
167+
$this->assertEquals('payflowpro_cc_vault', $cart->getPayment()->getMethod());
168+
$paymentMethodInstance = $cart->getPayment()->getMethodInstance();
169+
$this->assertInstanceOf(Vault::class, $paymentMethodInstance);
170+
$this->assertTrue(
171+
$paymentMethodInstance->canUseForCountry('UK')
172+
);
173+
$this->assertEquals(
174+
MethodInterface::ACTION_AUTHORIZE_CAPTURE,
175+
$paymentMethodInstance->getConfigPaymentAction()
176+
);
177+
$this->mockPaymentGateway($cart);
178+
$cartManagement = $this->objectManager->create(CartManagementInterface::class);
179+
$orderId = $cartManagement->placeOrder($cart->getId());
180+
$transactions = $this->getPaymentTransactionList((int) $orderId);
181+
$this->assertCount(1, $transactions);
182+
$transaction = array_pop($transactions);
183+
$this->assertEquals(TransactionInterface::TYPE_CAPTURE, $transaction->getTxnType());
184+
}
185+
91186
/**
92187
* Retrieves quote by provided order ID.
93188
*
@@ -164,4 +259,42 @@ private function getOrderComment(int $orderId): string
164259

165260
return $comment ? $comment->getComment() : '';
166261
}
262+
263+
private function mockPaymentGateway(CartInterface $cart): Gateway
264+
{
265+
$responseArray = [
266+
'RESULT' => '0',
267+
'pnref' => 'A30A3E5DDE34',
268+
'respmsg' => 'Approved',
269+
'authcode' => '421PNI',
270+
'avsaddr' => 'N',
271+
'avszip' => 'N',
272+
'txid' => '011144228158206',
273+
'hostcode' => 'A',
274+
'procavs' => 'N',
275+
'visacardlevel' => '12',
276+
'transtime' => date('Y-m-d H:i:s'),
277+
'firstname' => $cart->getBillingAddress()->getFirstname(),
278+
'lastname' => $cart->getBillingAddress()->getLastname(),
279+
'amt' => $cart->getShippingAddress()->getGrandTotal(),
280+
'acct' => '1234',
281+
'expdate' => date('Y-m-d H:i:s', strtotime('+1 hour')),
282+
'cardtype' => '0',
283+
'iavs' => 'N',
284+
'result_code' => '0',
285+
];
286+
$clientFactory = $this->createMock(LaminasClientFactory::class);
287+
$client = $this->createMock(LaminasClient::class);
288+
$clientResponse = $this->createMock(Response::class);
289+
$clientFactory->method('create')->willReturn($client);
290+
$client->method('send')->willReturn($clientResponse);
291+
$clientResponse->method('getBody')->willReturn(http_build_query($responseArray));
292+
$gatewayMock = $this->objectManager->get(Gateway::class);
293+
$reflection = new \ReflectionClass($gatewayMock);
294+
$property = $reflection->getProperty('httpClientFactory');
295+
$property->setAccessible(true);
296+
$property->setValue($gatewayMock, $clientFactory);
297+
298+
return $gatewayMock;
299+
}
167300
}

0 commit comments

Comments
 (0)