Skip to content

Commit 3655fae

Browse files
committed
feat: added customer vault token route
1 parent d0cb467 commit 3655fae

File tree

11 files changed

+224
-85
lines changed

11 files changed

+224
-85
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 9.6.6
2+
- PPI-1044 - Added a store api endpoint route that returns the vault token from the customer
3+
14
# 9.6.5
25
- PPI-1025 - Improves the performance of the installment banner in the Storefront
36
- PPI-1043 - Fixes an issue, where a payment method is toggled twice in the Administration

CHANGELOG_de-DE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 9.6.6
2+
- PPI-1044 - Fügt eine Store-API hinzufügt, die den vault token vom Kunden zurück gibt
3+
14
# 9.6.5
25
- PPI-1025 - Verbessert die Performance des Ratenzahlungsbanners in der Storefront
36
- PPI-1043 - Behebt ein Problem, bei dem eine Zahlungsmethode doppelt umgeschalten wurde
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* (c) shopware AG <[email protected]>
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
8+
namespace Swag\PayPal\Checkout\SalesChannel;
9+
10+
use OpenApi\Attributes as OA;
11+
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
12+
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
13+
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
14+
use Shopware\Core\Framework\Log\Package;
15+
use Shopware\Core\System\SalesChannel\SalesChannelContext;
16+
use Swag\PayPal\DataAbstractionLayer\VaultToken\VaultTokenEntity;
17+
use Swag\PayPal\RestApi\V1\Resource\TokenResourceInterface;
18+
use Symfony\Component\HttpFoundation\JsonResponse;
19+
use Symfony\Component\HttpFoundation\Response;
20+
use Symfony\Component\Routing\Attribute\Route;
21+
22+
#[Package('checkout')]
23+
#[Route(defaults: ['_routeScope' => ['store-api']])]
24+
readonly class CustomerVaultTokenRoute
25+
{
26+
/**
27+
* @internal
28+
*/
29+
public function __construct(
30+
private EntityRepository $vaultRepository,
31+
private TokenResourceInterface $tokenResource,
32+
) {
33+
}
34+
35+
#[OA\Get(
36+
path: '/paypal/vault-token',
37+
operationId: 'getPayPalCustomerVaultToken',
38+
description: 'Tries to get the customer vault token',
39+
tags: ['Store API', 'PayPal'],
40+
responses: [new OA\Response(
41+
response: Response::HTTP_OK,
42+
description: 'The customer vault token or null',
43+
content: new OA\JsonContent(properties: [new OA\Property(
44+
property: 'token',
45+
type: 'string'
46+
)])
47+
)],
48+
)]
49+
#[Route(path: '/store-api/paypal/vault-token', name: 'store-api.paypal.vault.token', defaults: ['_loginRequired' => true], methods: ['GET'])]
50+
public function getVaultToken(SalesChannelContext $context): JsonResponse
51+
{
52+
$customer = $context->getCustomer();
53+
if ($customer === null || $customer->getGuest() === true) {
54+
return new JsonResponse(['token' => null]);
55+
}
56+
57+
$criteria = new Criteria();
58+
$criteria->addFilter(new EqualsFilter('mainMapping.customerId', $customer->getId()));
59+
$criteria->addFilter(new EqualsFilter('mainMapping.paymentMethodId', $context->getPaymentMethod()->getId()));
60+
61+
/** @var VaultTokenEntity|null $vault */
62+
$vault = $this->vaultRepository->search($criteria, $context->getContext())->first();
63+
64+
if ($vault !== null) {
65+
return new JsonResponse(
66+
['token' => $this->tokenResource->getUserIdToken($context->getSalesChannelId(), $vault->getTokenCustomer())->getIdToken()]
67+
);
68+
}
69+
70+
return new JsonResponse(
71+
['token' => $this->tokenResource->getUserIdToken($context->getSalesChannelId())->getIdToken()]
72+
);
73+
}
74+
}

src/Resources/Schema/StoreApi/openapi.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,33 @@
166166
}
167167
}
168168
},
169+
"/paypal/vault-token": {
170+
"get": {
171+
"tags": [
172+
"Store API",
173+
"PayPal"
174+
],
175+
"description": "Tries to get the customer vault token",
176+
"operationId": "getPayPalCustomerVaultToken",
177+
"responses": {
178+
"200": {
179+
"description": "The customer vault token or null",
180+
"content": {
181+
"application/json": {
182+
"schema": {
183+
"properties": {
184+
"token": {
185+
"type": "string"
186+
}
187+
},
188+
"type": "object"
189+
}
190+
}
191+
}
192+
}
193+
}
194+
}
195+
},
169196
"/paypal/payment-method-eligibility": {
170197
"post": {
171198
"tags": [

src/Resources/config/services/checkout.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
<argument type="service" id="Shopware\Core\Checkout\Payment\Cart\PaymentTransactionStructFactory"/>
4646
</service>
4747

48+
<service id="Swag\PayPal\Checkout\SalesChannel\CustomerVaultTokenRoute" public="true">
49+
<argument type="service" id="swag_paypal_vault_token.repository"/>
50+
<argument type="service" id="Swag\PayPal\RestApi\V1\Resource\TokenResource" />
51+
</service>
52+
4853
<service id="Swag\PayPal\Checkout\SalesChannel\FilteredPaymentMethodRoute"
4954
decorates="Shopware\Core\Checkout\Payment\SalesChannel\PaymentMethodRoute"
5055
decoration-priority="-1500"

src/Resources/config/services/storefront.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@
7777
<service id="Swag\PayPal\Storefront\Data\Service\PayLaterCheckoutDataService" public="true" parent="Swag\PayPal\Storefront\Data\Service\AbstractCheckoutDataService" />
7878
<service id="Swag\PayPal\Storefront\Data\Service\SEPACheckoutDataService" public="true" parent="Swag\PayPal\Storefront\Data\Service\AbstractCheckoutDataService" />
7979
<service id="Swag\PayPal\Storefront\Data\Service\SPBCheckoutDataService" public="true" parent="Swag\PayPal\Storefront\Data\Service\AbstractCheckoutDataService">
80-
<argument type="service" id="Swag\PayPal\Storefront\Data\Service\VaultDataService"/>
80+
<argument type="service" id="Swag\PayPal\Checkout\SalesChannel\CustomerVaultTokenRoute"/>
8181
</service>
8282
<service id="Swag\PayPal\Storefront\Data\Service\VenmoCheckoutDataService" public="true" parent="Swag\PayPal\Storefront\Data\Service\AbstractCheckoutDataService">
83-
<argument type="service" id="Swag\PayPal\Storefront\Data\Service\VaultDataService"/>
83+
<argument type="service" id="Swag\PayPal\Checkout\SalesChannel\CustomerVaultTokenRoute"/>
8484
</service>
8585

8686
<service id="Swag\PayPal\Storefront\Data\CheckoutDataSubscriber">

src/Storefront/Data/Service/SPBCheckoutDataService.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Shopware\Core\System\SalesChannel\SalesChannelContext;
1414
use Shopware\Core\System\SystemConfig\SystemConfigService;
1515
use Swag\PayPal\Checkout\ExpressCheckout\SalesChannel\ExpressPrepareCheckoutRoute;
16+
use Swag\PayPal\Checkout\SalesChannel\CustomerVaultTokenRoute;
1617
use Swag\PayPal\Checkout\SPBCheckout\SPBCheckoutButtonData;
1718
use Swag\PayPal\Setting\Service\CredentialsUtilInterface;
1819
use Swag\PayPal\Setting\Settings;
@@ -37,7 +38,7 @@ public function __construct(
3738
RouterInterface $router,
3839
SystemConfigService $systemConfigService,
3940
CredentialsUtilInterface $credentialsUtil,
40-
private readonly VaultDataService $vaultDataService,
41+
private readonly CustomerVaultTokenRoute $customerVaultTokenRoute,
4142
) {
4243
parent::__construct($paymentMethodDataRegistry, $localeCodeProvider, $router, $systemConfigService, $credentialsUtil);
4344
}
@@ -75,7 +76,12 @@ public function buildCheckoutData(
7576
'useAlternativePaymentMethods' => $this->systemConfigService->getBool(Settings::SPB_ALTERNATIVE_PAYMENT_METHODS_ENABLED, $salesChannelId),
7677
'disabledAlternativePaymentMethods' => $this->getDisabledAlternativePaymentMethods($price, $currency->getIsoCode()),
7778
'showPayLater' => $this->systemConfigService->getBool(Settings::SPB_SHOW_PAY_LATER, $salesChannelId),
78-
'userIdToken' => $this->vaultDataService->getUserIdToken($context),
79+
'userIdToken' => \json_decode(
80+
(string) $this->customerVaultTokenRoute->getVaultToken($context)->getContent(),
81+
true,
82+
512,
83+
\JSON_THROW_ON_ERROR
84+
)['token'],
7985
]));
8086
}
8187

src/Storefront/Data/Service/VaultDataService.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public function buildData(SalesChannelContext $context): ?VaultData
6161
return $struct;
6262
}
6363

64+
/**
65+
* @deprecated tag:v10.0.0 - Will be removed. Use `CustomerVaultTokenRoute::getVaultToken` instead
66+
*/
6467
public function getUserIdToken(SalesChannelContext $context): ?string
6568
{
6669
$customer = $context->getCustomer();

src/Storefront/Data/Service/VenmoCheckoutDataService.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Shopware\Core\Framework\Log\Package;
1313
use Shopware\Core\System\SalesChannel\SalesChannelContext;
1414
use Shopware\Core\System\SystemConfig\SystemConfigService;
15+
use Swag\PayPal\Checkout\SalesChannel\CustomerVaultTokenRoute;
1516
use Swag\PayPal\Setting\Service\CredentialsUtilInterface;
1617
use Swag\PayPal\Storefront\Data\Struct\VenmoCheckoutData;
1718
use Swag\PayPal\Util\Lifecycle\Method\PaymentMethodDataRegistry;
@@ -31,7 +32,7 @@ public function __construct(
3132
RouterInterface $router,
3233
SystemConfigService $systemConfigService,
3334
CredentialsUtilInterface $credentialsUtil,
34-
private readonly VaultDataService $vaultDataService,
35+
private readonly CustomerVaultTokenRoute $customerVaultTokenRoute,
3536
) {
3637
parent::__construct($paymentMethodDataRegistry, $localeCodeProvider, $router, $systemConfigService, $credentialsUtil);
3738
}
@@ -41,7 +42,12 @@ public function buildCheckoutData(SalesChannelContext $context, ?Cart $cart = nu
4142
$data = $this->getBaseData($context, $order);
4243

4344
return (new VenmoCheckoutData())->assign(\array_merge($data, [
44-
'userIdToken' => $this->vaultDataService->getUserIdToken($context),
45+
'userIdToken' => \json_decode(
46+
(string) $this->customerVaultTokenRoute->getVaultToken($context)->getContent(),
47+
true,
48+
512,
49+
\JSON_THROW_ON_ERROR
50+
)['token'],
4551
]));
4652
}
4753

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* (c) shopware AG <[email protected]>
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
8+
namespace Swag\PayPal\Test\Checkout\SalesChannel;
9+
10+
use PHPUnit\Framework\MockObject\MockObject;
11+
use PHPUnit\Framework\TestCase;
12+
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
13+
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
14+
use Shopware\Core\Framework\Log\Package;
15+
use Shopware\Core\Test\Generator;
16+
use Swag\PayPal\Checkout\SalesChannel\CustomerVaultTokenRoute;
17+
use Swag\PayPal\DataAbstractionLayer\VaultToken\VaultTokenEntity;
18+
use Swag\PayPal\RestApi\V1\Api\Token;
19+
use Swag\PayPal\RestApi\V1\Resource\TokenResourceInterface;
20+
use Swag\PayPal\Test\Helper\SalesChannelContextTrait;
21+
22+
/**
23+
* @internal
24+
*/
25+
#[Package('checkout')]
26+
class CustomerVaultTokenRouteTest extends TestCase
27+
{
28+
use SalesChannelContextTrait;
29+
30+
private EntityRepository&MockObject $repository;
31+
32+
private TokenResourceInterface&MockObject $tokenResource;
33+
34+
private CustomerVaultTokenRoute $route;
35+
36+
protected function setUp(): void
37+
{
38+
$this->repository = $this->createMock(EntityRepository::class);
39+
$this->tokenResource = $this->createMock(TokenResourceInterface::class);
40+
41+
$this->route = new CustomerVaultTokenRoute($this->repository, $this->tokenResource);
42+
}
43+
44+
public function testGetVaultTokenWithoutCustomer(): void
45+
{
46+
$salesChannelContext = Generator::generateSalesChannelContext();
47+
$salesChannelContext->assign(['customer' => null]);
48+
49+
$response = $this->route->getVaultToken($salesChannelContext);
50+
51+
static::assertSame(
52+
'{"token":null}',
53+
(string) $response->getContent()
54+
);
55+
}
56+
57+
public function testGetVaultTokenWithGuestCustomer(): void
58+
{
59+
$salesChannelContext = Generator::generateSalesChannelContext();
60+
$salesChannelContext->getCustomer()?->setGuest(true);
61+
62+
$response = $this->route->getVaultToken($salesChannelContext);
63+
64+
static::assertSame(
65+
'{"token":null}',
66+
(string) $response->getContent()
67+
);
68+
}
69+
70+
public function testGetVaultToken(): void
71+
{
72+
$salesChannelContext = Generator::generateSalesChannelContext();
73+
$salesChannelContext->getCustomer()?->setGuest(false);
74+
75+
$entitySearchResult = $this->createMock(EntitySearchResult::class);
76+
$this->repository->expects(static::once())->method('search')->willReturn($entitySearchResult);
77+
$entitySearchResult->expects(static::once())->method('first')->willReturn(new VaultTokenEntity());
78+
79+
$token = new Token();
80+
$token->assign(['idToken' => 'dummy-token', 'expiresIn' => 45000]);
81+
82+
$this->tokenResource->expects(static::once())->method('getUserIdToken')->willReturn($token);
83+
84+
$response = $this->route->getVaultToken($salesChannelContext);
85+
86+
static::assertSame(
87+
$token->getIdToken(),
88+
\json_decode((string) $response->getContent(), true, 512, \JSON_THROW_ON_ERROR)['token']
89+
);
90+
}
91+
}

0 commit comments

Comments
 (0)