Release 6.1.17

This commit is contained in:
andrewrowanwallee
2025-11-03 13:29:47 +01:00
parent 1393f4ff7c
commit 68592a9409
19 changed files with 844 additions and 422 deletions
+5
View File
@@ -1,3 +1,8 @@
# 6.1.17
- Sales channels now support different spaces
- Upgraded SDK to include latest fallback CA Bundle
- Fixed error screen when returning from portal on failed payment
# 6.1.16 # 6.1.16
- Fixed issue with pending orders remaining open - Fixed issue with pending orders remaining open
+5
View File
@@ -1,3 +1,8 @@
# 6.1.17
- Vertriebskanäle unterstützen jetzt verschiedene Bereiche
- SDK aktualisiert und enthält nun das neueste CA-Fallback-Bundle
- Fehlerbildschirm beim Zurückkehren vom Portal nach fehlgeschlagener Zahlung behoben
# 6.1.16 # 6.1.16
- Problem behoben, bei dem die Versandkosten nicht korrekt verarbeitet wurden - Problem behoben, bei dem die Versandkosten nicht korrekt verarbeitet wurden
+4 -4
View File
@@ -14,10 +14,10 @@ The VR Payment Payment Plugin integrates modern payment processing into Shopware
## Documentation ## Documentation
- For English documentation click [here](@WalleeDocPath(/docs/en/documentation.html)) - For English documentation click [here](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/6.1.17/docs/en/documentation.html)
- Für die deutsche Dokumentation klicken Sie [hier](@WalleeDocPath(/docs/de/documentation.html)) - Für die deutsche Dokumentation klicken Sie [hier](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/6.1.17/docs/de/documentation.html)
- Pour la documentation Française, cliquez [ici](@WalleeDocPath(/docs/fr/documentation.html)) - Pour la documentation Française, cliquez [ici](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/6.1.17/docs/fr/documentation.html)
- Per la documentazione in tedesco, clicca [qui](@WalleeDocPath(/docs/it/documentation.html)) - Per la documentazione in tedesco, clicca [qui](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/6.1.17/docs/it/documentation.html)
## Installation ## Installation
+1 -1
View File
@@ -59,5 +59,5 @@
"vrpayment/sdk": "^4.0.0" "vrpayment/sdk": "^4.0.0"
}, },
"type": "shopware-platform-plugin", "type": "shopware-platform-plugin",
"version": "6.1.16" "version": "6.1.17"
} }
@@ -251,9 +251,9 @@ class PaymentMethodConfigurationService {
{ {
$data = []; $data = [];
$paymentMethodData = []; $paymentMethodData = [];
$salesChannelPaymentMethodData = [];
$criteria = (new Criteria())->addFilter(new EqualsFilter('state', 'ACTIVE')); $criteria = (new Criteria())->addFilter(new EqualsFilter('state', 'ACTIVE'))
->addFilter(new EqualsFilter('spaceId', $this->getSpaceId()));
/** /**
* @var $vRPaymentPMConfigurationRepository * @var $vRPaymentPMConfigurationRepository
@@ -276,7 +276,7 @@ class PaymentMethodConfigurationService {
]; ];
$paymentMethodData[] = [ $paymentMethodData[] = [
'id' => $paymentMethodConfigurationEntity->getId(), 'id' => $paymentMethodConfigurationEntity->getPaymentMethodId(),
'active' => false, 'active' => false,
]; ];
} }
@@ -349,35 +349,68 @@ class PaymentMethodConfigurationService {
*/ */
foreach ($paymentMethodConfigurations as $paymentMethodConfiguration) { foreach ($paymentMethodConfigurations as $paymentMethodConfiguration) {
$paymentMethodConfigurationEntity = $this->getPaymentMethodConfigurationEntity( $entity = $this->getPaymentMethodConfigurationEntity(
$paymentMethodConfiguration->getSpaceId(), $paymentMethodConfiguration->getSpaceId(),
$paymentMethodConfiguration->getId(), $paymentMethodConfiguration->getId(),
$context $context
); );
$id = is_null($paymentMethodConfigurationEntity) ? Uuid::randomHex() : $paymentMethodConfigurationEntity->getId();
$configId = $entity ? $entity->getId() : Uuid::randomHex();
$technicalName = $paymentMethodConfiguration->getName();
$paymentMethodId = $this->getOrCreatePaymentMethodId(
$technicalName,
VRPaymentPaymentHandler::class,
$context
);
$data = [ $data = [
'id' => $id, 'id' => $configId,
'paymentMethodConfigurationId' => $paymentMethodConfiguration->getId(), 'paymentMethodConfigurationId' => $paymentMethodConfiguration->getId(),
'paymentMethodId' => $id, 'paymentMethodId' => $paymentMethodId,
'data' => json_decode(strval($paymentMethodConfiguration), true), 'data' => json_decode(strval($paymentMethodConfiguration), true),
'sortOrder' => $paymentMethodConfiguration->getSortOrder(), 'sortOrder' => $paymentMethodConfiguration->getSortOrder(),
'spaceId' => $paymentMethodConfiguration->getSpaceId(), 'spaceId' => $paymentMethodConfiguration->getSpaceId(),
'state' => CreationEntityState::ACTIVE, 'state' => CreationEntityState::ACTIVE,
]; ];
$this->upsertPaymentMethod($id, $paymentMethodConfiguration, $context);
try { try {
$this->container->get(PaymentMethodConfigurationEntityDefinition::ENTITY_NAME . '.repository')->upsert([$data], $context); $this->upsertPaymentMethod($paymentMethodId, $paymentMethodConfiguration, $context);
$this->container
->get(PaymentMethodConfigurationEntityDefinition::ENTITY_NAME . '.repository')
->upsert([$data], $context);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->error($e->getMessage(), [$e->getTraceAsString()]); $this->logger->error($e->getMessage(), [$e->getTraceAsString()]);
} }
} }
} }
private function getOrCreatePaymentMethodId(string $technicalName, string $handlerIdentifier, Context $context): string
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('technicalName', $technicalName));
$criteria->setLimit(1);
$existing = $this->paymentMethodRepository->search($criteria, $context)->first();
if ($existing !== null) {
return $existing->getId();
}
$paymentMethodId = Uuid::randomHex();
$this->paymentMethodRepository->upsert([[
'id' => $paymentMethodId,
'handlerIdentifier' => $handlerIdentifier,
'technicalName' => $technicalName,
'name' => $technicalName,
'active' => false,
]], $context);
return $paymentMethodId;
}
/** /**
* Fetch active merchant payment methods from VRPayment API * Fetch active merchant payment methods from VRPayment API
* *
@@ -482,8 +515,7 @@ class PaymentMethodConfigurationService {
string $id, string $id,
PaymentMethodConfiguration $paymentMethodConfiguration, PaymentMethodConfiguration $paymentMethodConfiguration,
Context $context Context $context
): void ): void {
{
/** @var PluginIdProvider $pluginIdProvider */ /** @var PluginIdProvider $pluginIdProvider */
$pluginIdProvider = $this->container->get(PluginIdProvider::class); $pluginIdProvider = $this->container->get(PluginIdProvider::class);
$pluginId = $pluginIdProvider->getPluginIdByBaseClass( $pluginId = $pluginIdProvider->getPluginIdByBaseClass(
@@ -499,18 +531,19 @@ class PaymentMethodConfigurationService {
'afterOrderEnabled' => true, 'afterOrderEnabled' => true,
'active' => true, 'active' => true,
'translations' => $this->getPaymentMethodConfigurationTranslation($paymentMethodConfiguration, $context), 'translations' => $this->getPaymentMethodConfigurationTranslation($paymentMethodConfiguration, $context),
'technicalName' => $paymentMethodConfiguration->getName(),
]; ];
$data['mediaId'] = $this->upsertMedia($id, $paymentMethodConfiguration, $context); $mediaId = $this->upsertMedia($id, $paymentMethodConfiguration, $context);
if ($mediaId) {
$data = array_filter($data); $data['mediaId'] = $mediaId;
}
try { try {
$this->paymentMethodRepository->upsert([$data], $context); $this->paymentMethodRepository->upsert([$data], $context);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->error($e->getMessage(), [$e->getTraceAsString()]); $this->logger->error($e->getMessage(), [$e->getTraceAsString()]);
} }
} }
/** /**
@@ -612,46 +645,58 @@ class PaymentMethodConfigurationService {
* *
* @return string|null * @return string|null
*/ */
/**
* Upload or update Payment Method icons
*/
protected function upsertMedia(string $id, PaymentMethodConfiguration $paymentMethodConfiguration, Context $context): ?string protected function upsertMedia(string $id, PaymentMethodConfiguration $paymentMethodConfiguration, Context $context): ?string
{ {
try { try {
$existingRecord = $this->getMediaDefaultFolderForPaymentMethod($paymentMethodConfiguration, $context); $folderKey = 'payment_method_' . $paymentMethodConfiguration->getId();
if ($existingRecord->count() > 0) { // Check existing default folder
$id = $existingRecord->first()->getId(); $criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('entity', $folderKey));
$existingFolder = $this->mediaDefaultFolderRepository->search($criteria, $context);
$folderId = $id;
if ($existingFolder->count() > 0) {
$folderId = $existingFolder->first()->getId();
} }
// Ensure default folder
$this->mediaDefaultFolderRepository->upsert([ $this->mediaDefaultFolderRepository->upsert([
[ [
'id' => $id, 'id' => $folderId,
'associationFields' => [], 'associationFields' => [],
'entity' => 'payment_method_' . $paymentMethodConfiguration->getId(), 'entity' => $folderKey,
], ],
], $context); ], $context);
// Ensure media folder
$this->mediaFolderRepository->upsert([ $this->mediaFolderRepository->upsert([
[ [
'id' => $id, 'id' => $folderId,
'defaultFolderId' => $id, 'defaultFolderId' => $folderId,
'name' => $paymentMethodConfiguration->getName(), 'name' => $paymentMethodConfiguration->getName(),
'useParentConfiguration' => false, 'useParentConfiguration' => false,
'configuration' => [], 'configuration' => [],
], ],
], $context); ], $context);
/** // Media insert/update
* @var \Shopware\Core\Content\Media\MediaDefinition
*/
$mediaDefinition = $this->container->get(MediaDefinition::class); $mediaDefinition = $this->container->get(MediaDefinition::class);
$this->mediaSerializer->setRegistry($this->serializerRegistry); $this->mediaSerializer->setRegistry($this->serializerRegistry);
$data = [ $data = [
'id' => $id, 'id' => $id,
'title' => $paymentMethodConfiguration->getName(), 'title' => $paymentMethodConfiguration->getName(),
'url' => $paymentMethodConfiguration->getResolvedImageUrl(), 'url' => $paymentMethodConfiguration->getResolvedImageUrl(),
'mediaFolderId' => $id, 'mediaFolderId' => $folderId,
]; ];
$data = $this->mediaSerializer->deserialize(new Config([], [], []), $mediaDefinition, $data); $data = $this->mediaSerializer->deserialize(new Config([], [], []), $mediaDefinition, $data);
$this->mediaRepository->upsert([$data], $context); $this->mediaRepository->upsert([$data], $context);
return $id; return $id;
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->critical($e->getMessage(), [$e->getTraceAsString()]); $this->logger->critical($e->getMessage(), [$e->getTraceAsString()]);
@@ -15,6 +15,7 @@ use Shopware\Core\{
System\SalesChannel\SalesChannelContext System\SalesChannel\SalesChannelContext
}; };
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent; use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Shopware\Storefront\Page\Account\Order\AccountEditOrderPageLoadedEvent;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use VRPayment\Sdk\{ use VRPayment\Sdk\{
Model\AddressCreate, Model\AddressCreate,
@@ -46,6 +47,9 @@ use VRPaymentPayment\Core\{
Util\Payload\TransactionPayload Util\Payload\TransactionPayload
}; };
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Framework\Struct\ArrayEntity;
/** /**
* Class TransactionService * Class TransactionService
* *
@@ -180,10 +184,19 @@ class TransactionService
$transaction->getOrderTransaction()->getPaymentMethodId(), $transaction->getOrderTransaction()->getPaymentMethodId(),
$transaction->getOrder()->getSalesChannelId() $transaction->getOrder()->getSalesChannelId()
); );
$_SESSION['transactionId'] = null; $salesChannelContext->getContext()->addExtension(
$_SESSION['arrayOfPossibleMethods'] = null; 'checkoutState',
$_SESSION['addressCheck'] = null; new ArrayEntity([
$_SESSION['currencyCheck'] = null; 'transactionId' => null,
'addressHash' => null,
'currency' => null,
])
);
$salesChannelContext->getContext()->addExtension(
'possibleMethods',
new ArrayEntity(['ids' => []])
);
$this->holdDelivery($transaction->getOrder()->getId(), $salesChannelContext->getContext()); $this->holdDelivery($transaction->getOrder()->getId(), $salesChannelContext->getContext());
@@ -478,14 +491,18 @@ class TransactionService
/** /**
* @param SalesChannelContext $salesChannelContext * @param SalesChannelContext $salesChannelContext
* @param CheckoutConfirmPageLoadedEvent|null $event * @param $event
* @return int * @return int
*/ */
public function createPendingTransaction(SalesChannelContext $salesChannelContext, ?CheckoutConfirmPageLoadedEvent $event = null): int
public function createPendingTransaction(SalesChannelContext $salesChannelContext, $event = null): int
{ {
$expiredTransaction = true; $expiredTransaction = true;
$transactionId = $_SESSION['transactionId'] ?? null; $transactionId = $_SESSION['transactionId'] ?? null;
$settings = $this->settingsService->getValidSettings($salesChannelContext->getSalesChannel()->getId()); $settings = $this->settingsService->getValidSettings($salesChannelContext->getSalesChannel()->getId());
if (!$settings) {
throw new \Exception('Space settings not configured');
}
if ($transactionId) { if ($transactionId) {
$transactionService = $settings->getApiClient()->getTransactionService(); $transactionService = $settings->getApiClient()->getTransactionService();
@@ -494,6 +511,7 @@ class TransactionService
TransactionState::DECLINE, TransactionState::DECLINE,
TransactionState::FAILED, TransactionState::FAILED,
TransactionState::VOIDED, TransactionState::VOIDED,
null
]; ];
if (!in_array($pendingTransaction->getState(), $failedStates)) { if (!in_array($pendingTransaction->getState(), $failedStates)) {
$expiredTransaction = false; $expiredTransaction = false;
@@ -567,6 +585,7 @@ class TransactionService
$lineItems = []; $lineItems = [];
if ($event) { if ($event) {
if ($event instanceof CheckoutConfirmPageLoadedEvent) {
$cartLineItems = $event->getPage()->getCart()->getLineItems()->getElements(); $cartLineItems = $event->getPage()->getCart()->getLineItems()->getElements();
foreach ($cartLineItems as $cartLineItem) { foreach ($cartLineItems as $cartLineItem) {
if ($cartLineItem->getType() === CustomProductsLineItemTypes::LINE_ITEM_TYPE_CUSTOMIZED_PRODUCTS) { if ($cartLineItem->getType() === CustomProductsLineItemTypes::LINE_ITEM_TYPE_CUSTOMIZED_PRODUCTS) {
@@ -574,6 +593,12 @@ class TransactionService
} }
$lineItems[] = $this->createTempLineItem($cartLineItem); $lineItems[] = $this->createTempLineItem($cartLineItem);
} }
} elseif ($event instanceof AccountEditOrderPageLoadedEvent) {
$order = $event->getPage()->getOrder();
foreach ($order->getLineItems() as $orderLineItem) {
$lineItems[] = $this->createTempLineItem($orderLineItem);
}
}
} }
$customerId = ""; $customerId = "";
@@ -731,14 +756,26 @@ class TransactionService
* @param LineItem $productData * @param LineItem $productData
* @return LineItemCreate * @return LineItemCreate
*/ */
private function createTempLineItem(LineItem $productData): LineItemCreate private function createTempLineItem($productData): LineItemCreate
{ {
$lineItem = new LineItemCreate(); $lineItem = new LineItemCreate();
if ($productData instanceof LineItem) {
$lineItem->setName($productData->getLabel()); $lineItem->setName($productData->getLabel());
$lineItem->setUniqueId($productData->getId()); $lineItem->setUniqueId($productData->getId());
$lineItem->setSku($productData->getId()); $lineItem->setSku($productData->getReferencedId() ?? $productData->getId());
$lineItem->setQuantity($productData->getQuantity()); $lineItem->setQuantity($productData->getQuantity());
$lineItem->setAmountIncludingTax($productData->getPrice()->getUnitPrice()); $lineItem->setAmountIncludingTax($productData->getPrice()->getUnitPrice());
} elseif ($productData instanceof OrderLineItemEntity) {
$lineItem->setName($productData->getLabel());
$lineItem->setUniqueId($productData->getId());
$lineItem->setSku($productData->getProductId() ?? $productData->getIdentifier() ?? $productData->getId());
$lineItem->setQuantity($productData->getQuantity());
$lineItem->setAmountIncludingTax($productData->getUnitPrice());
} else {
throw new \InvalidArgumentException('Unsupported line item type: ' . get_class($productData));
}
$lineItem->setType(LineItemType::PRODUCT); $lineItem->setType(LineItemType::PRODUCT);
return $lineItem; return $lineItem;
@@ -226,6 +226,14 @@ class WebHookController extends AbstractController {
$this->settings = $this->settingsService->getSettings($salesChannelId); $this->settings = $this->settingsService->getSettings($salesChannelId);
$signature = $request->server->get('HTTP_X_SIGNATURE'); $signature = $request->server->get('HTTP_X_SIGNATURE');
$requestJson = json_decode($request->getContent(), true); $requestJson = json_decode($request->getContent(), true);
if ($requestJson['eventId'] == null && $requestJson['entityId'] == null && $requestJson['listenerEntityId'] == null && $requestJson['listenerEntityId'] == null && $requestJson['listenerEntityTechnicalName'] == null && $requestJson['spaceId'] == null) {
throw new \InvalidArgumentException('Empty webhook');
}
if (!$this->settings->getSpaceId() || !$this->settings->getUserId() || !$this->settings->getApplicationKey()) {
throw new \InvalidArgumentException('Not correct webhook configuration for salesChannelId: ' . $salesChannelId . ' Debug: ' . var_dump($requestJson));
}
$apiClient = $this->settings->getApiClient(); $apiClient = $this->settings->getApiClient();
$callBackData->assign($requestJson); $callBackData->assign($requestJson);
@@ -2,8 +2,12 @@
namespace VRPaymentPayment\Core\Storefront\Checkout\Controller; namespace VRPaymentPayment\Core\Storefront\Checkout\Controller;
use Psr\Log\LoggerInterface; use Psr\{
Log\LoggerInterface,
Cache\CacheItemPoolInterface
};
use Shopware\Core\{ use Shopware\Core\{
Checkout\Payment\PaymentException,
Checkout\Cart\Cart, Checkout\Cart\Cart,
Checkout\Cart\CartException, Checkout\Cart\CartException,
Checkout\Cart\LineItemFactoryRegistry, Checkout\Cart\LineItemFactoryRegistry,
@@ -35,9 +39,13 @@ use Shopware\Storefront\{
use Symfony\Component\{ use Symfony\Component\{
HttpFoundation\Request, HttpFoundation\Request,
HttpFoundation\Response, HttpFoundation\Response,
HttpFoundation\RedirectResponse,
Routing\Attribute\Route, Routing\Attribute\Route,
Routing\Generator\UrlGeneratorInterface Routing\Generator\UrlGeneratorInterface,
Cache\Adapter\FilesystemAdapter,
DependencyInjection\ParameterBag\ParameterBagInterface
}; };
use Symfony\Contracts\Cache\ItemInterface;
use VRPayment\Sdk\{ use VRPayment\Sdk\{
Model\Transaction, Model\Transaction,
Model\TransactionState Model\TransactionState
@@ -51,7 +59,6 @@ use VRPaymentPayment\Core\{
Util\Payload\TransactionPayload Util\Payload\TransactionPayload
}; };
/** /**
* Class CheckoutController * Class CheckoutController
* *
@@ -114,6 +121,11 @@ class CheckoutController extends StorefrontController {
*/ */
private $orderRoute; private $orderRoute;
/**
* @var \Psr\Cache\CacheItemPoolInterface
*/
private CacheItemPoolInterface $cache;
/** /**
* PaymentController constructor. * PaymentController constructor.
* *
@@ -125,6 +137,7 @@ class CheckoutController extends StorefrontController {
* @param \Shopware\Core\Checkout\Order\SalesChannel\AbstractOrderRoute $orderRoute * @param \Shopware\Core\Checkout\Order\SalesChannel\AbstractOrderRoute $orderRoute
* @param \Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStateHandler $orderTransactionStateHandler * @param \Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStateHandler $orderTransactionStateHandler
* @param \Shopware\Core\System\StateMachine\StateMachineRegistry $stateMachineRegistry * @param \Shopware\Core\System\StateMachine\StateMachineRegistry $stateMachineRegistry
* @param Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface $params
*/ */
public function __construct( public function __construct(
LineItemFactoryRegistry $lineItemFactoryRegistry, LineItemFactoryRegistry $lineItemFactoryRegistry,
@@ -134,7 +147,8 @@ class CheckoutController extends StorefrontController {
GenericPageLoaderInterface $genericLoader, GenericPageLoaderInterface $genericLoader,
AbstractOrderRoute $orderRoute, AbstractOrderRoute $orderRoute,
OrderTransactionStateHandler $orderTransactionStateHandler, OrderTransactionStateHandler $orderTransactionStateHandler,
StateMachineRegistry $stateMachineRegistry StateMachineRegistry $stateMachineRegistry,
ParameterBagInterface $params
) )
{ {
$this->cartService = $cartService; $this->cartService = $cartService;
@@ -145,6 +159,7 @@ class CheckoutController extends StorefrontController {
$this->orderRoute = $orderRoute; $this->orderRoute = $orderRoute;
$this->orderTransactionStateHandler = $orderTransactionStateHandler; $this->orderTransactionStateHandler = $orderTransactionStateHandler;
$this->stateMachineRegistry = $stateMachineRegistry; $this->stateMachineRegistry = $stateMachineRegistry;
$this->cache = new FilesystemAdapter('vrpayment', 0, rtrim($params->get('kernel.cache_dir'), '/') . '/vrpayment-cache');
} }
/** /**
@@ -386,6 +401,32 @@ class CheckoutController extends StorefrontController {
if($orderEntity->getSalesChannelId() !== $salesChannelContext->getSalesChannelId()) { if($orderEntity->getSalesChannelId() !== $salesChannelContext->getSalesChannelId()) {
$this->settings = $this->settingsService->getSettings($orderEntity->getSalesChannelId()); $this->settings = $this->settingsService->getSettings($orderEntity->getSalesChannelId());
$trans = $this->getTransaction($orderId, $salesChannelContext->getContext()); $trans = $this->getTransaction($orderId, $salesChannelContext->getContext());
// Adoption in case of duplicate requests
// Get order specific value from cache
$cacheKey = 'vrpayment_recreate_order_' . $orderId;
$isFound = $this->cache->get($cacheKey, function (ItemInterface $item) {
$item->expiresAfter(10);
return false;
});
// If value is found in cache - send user directly to successful checkout confirmation page for unpaid transactions
if ($isFound === true && in_array($trans->getState(), [TransactionState::FAILED])) {
$unpaidUrl = $this->getUnpaidUrlFromToken($trans->getSuccessUrl())
?? $this->buildUnpaidUrl($orderEntity->getSalesChannelId(), $salesChannelContext, $orderId);
if ($unpaidUrl) {
return new RedirectResponse(
$unpaidUrl . (parse_url($unpaidUrl, \PHP_URL_QUERY) ? '&' : '?') . 'error-code=' . PaymentException::PAYMENT_CUSTOMER_CANCELED_EXTERNAL
);
}
}
// Cache order specific value for some time on first request
$this->cache->delete($cacheKey);
$this->cache->get($cacheKey, function (ItemInterface $item) {
$item->expiresAfter(10);
return true;
});
return $this->redirect($trans->getSuccessUrl()); return $this->redirect($trans->getSuccessUrl());
} }
// End Adoption for Headless Storefronts // End Adoption for Headless Storefronts
@@ -459,6 +500,74 @@ class CheckoutController extends StorefrontController {
return $this->redirectToRoute('frontend.checkout.confirm.page'); return $this->redirectToRoute('frontend.checkout.confirm.page');
} }
/**
* Tries to return successful checkout confirmation url for unpaid transactions.
*
* It achieves that by getting payment token from successUrl, parsing and decoding
* it, and finally reading the claims.
*
* @param string $successUrl
*
* @return string|null
*/
private function getUnpaidUrlFromToken(string $successUrl): ?string {
$query = [];
parse_str((string) parse_url($successUrl, PHP_URL_QUERY), $query);
$jwt = $query['_sw_payment_token'] ?? null;
if (!$jwt) {
return null;
}
$data = explode('.', $jwt, 3);
if (count($data) !== 3) {
return null;
}
[, $c, ] = $data;
try {
$urlSafeData = strtr($c, '-_', '+/');
$paddedData = str_pad($urlSafeData, \strlen($urlSafeData) % 4, '=');
$decoded = base64_decode($paddedData, true);
if (!$decoded) {
return null;
}
$claims = json_decode(json: $decoded, associative: true, flags: JSON_THROW_ON_ERROR);
$unpaidUrl = $claims['eul'] ?? null;
return $unpaidUrl;
} catch (\Throwable $e) {
$this->logger->warning("CheckoutController::getUnpaidUrlFromToken - JWT parse failed: {errorMessage}", [
'errorMessage' => $e->getMessage(),
]);
return null;
}
}
/**
* Tries to return successful checkout confirmation url for unpaid transactions.
*
* It achieves that by fetching headless storefront's base url,
* and building custom url.
*
* @param string $salesChannelId
* @param SalesChannelContext $salesChannelContext
* @param string $orderId
*
* @return string|null
*/
private function buildUnpaidUrl(string $salesChannelId, SalesChannelContext $salesChannelContext, string $orderId): ?string {
$salesChannelDomainRepo = $this->container->get('sales_channel_domain.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('salesChannelId', $salesChannelId))->setLimit(10);
$domain = $salesChannelDomainRepo->search($criteria, $salesChannelContext->getContext())->first();
if(!$domain) {
return null;
}
$baseUrl = rtrim($domain->getUrl(), '/');
return sprintf('%s/checkout/success/%s/unpaid', $baseUrl, $orderId);
}
/** /**
* @param OrderLineItemCollection $orderItems * @param OrderLineItemCollection $orderItems
* *
@@ -7,11 +7,18 @@ use Shopware\Core\{Checkout\Order\Aggregate\OrderTransaction\OrderTransactionCol
Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStates, Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStates,
Checkout\Order\OrderEntity, Checkout\Order\OrderEntity,
Content\MailTemplate\Service\Event\MailBeforeValidateEvent}; Content\MailTemplate\Service\Event\MailBeforeValidateEvent};
use Shopware\Core\Checkout\Payment\PaymentMethodCollection;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\MultiFilter;
use Shopware\Core\System\SalesChannel\SalesChannelContext; use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Page\Account\Order\AccountEditOrderPageLoadedEvent;
use Shopware\Storefront\Page\Account\PaymentMethod\AccountPaymentMethodPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent; use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use VRPaymentPayment\Core\{Api\Transaction\Service\OrderMailService, use VRPaymentPayment\Core\{Api\Transaction\Service\TransactionService,
Api\Transaction\Service\TransactionService,
Checkout\PaymentHandler\VRPaymentPaymentHandler, Checkout\PaymentHandler\VRPaymentPaymentHandler,
Settings\Service\SettingsService, Settings\Service\SettingsService,
Settings\Struct\Settings, Settings\Struct\Settings,
@@ -31,6 +38,7 @@ use VRPaymentPayment\Sdk\{Model\AddressCreate,
Model\Transaction, Model\Transaction,
Model\TransactionCreate, Model\TransactionCreate,
Model\TransactionPending}; Model\TransactionPending};
use Shopware\Core\Framework\Struct\ArrayEntity;
/** /**
* Class CheckoutSubscriber * Class CheckoutSubscriber
@@ -65,6 +73,9 @@ class CheckoutSubscriber implements EventSubscriberInterface
*/ */
private $paymentMethodUtil; private $paymentMethodUtil;
/** @var EntityRepository */
private EntityRepository $paymentMethodRepository;
/** /**
* CheckoutSubscriber constructor. * CheckoutSubscriber constructor.
* *
@@ -73,12 +84,13 @@ class CheckoutSubscriber implements EventSubscriberInterface
* @param \VRPaymentPayment\Core\Settings\Service\SettingsService $settingsService * @param \VRPaymentPayment\Core\Settings\Service\SettingsService $settingsService
* @param \VRPaymentPayment\Core\Util\PaymentMethodUtil $paymentMethodUtil * @param \VRPaymentPayment\Core\Util\PaymentMethodUtil $paymentMethodUtil
*/ */
public function __construct(PaymentMethodConfigurationService $paymentMethodConfigurationService, TransactionService $transactionService, SettingsService $settingsService, PaymentMethodUtil $paymentMethodUtil) public function __construct(PaymentMethodConfigurationService $paymentMethodConfigurationService, TransactionService $transactionService, SettingsService $settingsService, PaymentMethodUtil $paymentMethodUtil, EntityRepository $paymentMethodRepository)
{ {
$this->paymentMethodConfigurationService = $paymentMethodConfigurationService; $this->paymentMethodConfigurationService = $paymentMethodConfigurationService;
$this->transactionService = $transactionService; $this->transactionService = $transactionService;
$this->settingsService = $settingsService; $this->settingsService = $settingsService;
$this->paymentMethodUtil = $paymentMethodUtil; $this->paymentMethodUtil = $paymentMethodUtil;
$this->paymentMethodRepository = $paymentMethodRepository;
} }
/** /**
@@ -99,7 +111,9 @@ class CheckoutSubscriber implements EventSubscriberInterface
public static function getSubscribedEvents(): array public static function getSubscribedEvents(): array
{ {
return [ return [
CheckoutConfirmPageLoadedEvent::class => ['onConfirmPageLoaded', 1], CheckoutConfirmPageLoadedEvent::class => 'onCheckoutConfirmLoaded',
AccountEditOrderPageLoadedEvent::class => 'onAccountOrderEditLoaded',
AccountPaymentMethodPageLoadedEvent::class => 'onAccountPaymentMethodLoaded',
MailBeforeValidateEvent::class => ['onMailBeforeValidate', 1], MailBeforeValidateEvent::class => ['onMailBeforeValidate', 1],
]; ];
} }
@@ -153,9 +167,10 @@ class CheckoutSubscriber implements EventSubscriberInterface
} }
/** /**
* @param \Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent $event * @param CheckoutConfirmPageLoadedEvent $event
* @return void
*/ */
public function onConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event): void public function onCheckoutConfirmLoaded(CheckoutConfirmPageLoadedEvent $event): void
{ {
try { try {
$salesChannelContext = $event->getSalesChannelContext(); $salesChannelContext = $event->getSalesChannelContext();
@@ -168,7 +183,7 @@ class CheckoutSubscriber implements EventSubscriberInterface
$createdTransactionId = $this->transactionService->createPendingTransaction($salesChannelContext, $event); $createdTransactionId = $this->transactionService->createPendingTransaction($salesChannelContext, $event);
$this->updateTempTransactionIfNeeded($salesChannelContext, $createdTransactionId); $this->updateTempTransactionIfNeeded($salesChannelContext, $createdTransactionId);
$this->getAvailablePaymentMethods($settings, $createdTransactionId); $this->getAvailablePaymentMethods($settings, $createdTransactionId, $salesChannelContext);
$this->setPossiblePaymentMethods($settings->getSpaceId(), $event); $this->setPossiblePaymentMethods($settings->getSpaceId(), $event);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->error($e->getMessage()); $this->logger->error($e->getMessage());
@@ -176,10 +191,74 @@ class CheckoutSubscriber implements EventSubscriberInterface
} }
} }
/**
* @param AccountEditOrderPageLoadedEvent $event
* @return void
*/
public function onAccountOrderEditLoaded(AccountEditOrderPageLoadedEvent $event): void
{
try {
$this->handlePaymentMethodFiltering($event);
} catch (\Throwable $e) {
$this->logger->error($e->getMessage());
$this->removeVRPaymentPaymentMethodFromConfirmPage($event);
}
}
/**
* @param AccountPaymentMethodPageLoadedEvent $event
* @return void
*/
public function onAccountPaymentMethodLoaded(AccountPaymentMethodPageLoadedEvent $event): void
{
try {
$this->handlePaymentMethodFiltering($event);
} catch (\Throwable $e) {
$this->logger->error($e->getMessage());
$this->removeVRPaymentPaymentMethodFromConfirmPage($event);
}
}
/** /**
* @param \Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent $event * @param \Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent $event
*/ */
private function removeVRPaymentPaymentMethodFromConfirmPage(CheckoutConfirmPageLoadedEvent $event): void public function onConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event): void
{
try {
$this->handlePaymentMethodFiltering($event);
} catch (\Throwable $e) {
$this->logger->error($e->getMessage());
$this->removeVRPaymentPaymentMethodFromConfirmPage($event);
}
}
/**
* @param $event
* @return void
*/
private function handlePaymentMethodFiltering($event): void
{
$salesChannelContext = $event->getSalesChannelContext();
$settings = $this->settingsService->getValidSettings($salesChannelContext->getSalesChannel()->getId());
if (is_null($settings)) {
$this->logger->notice('Removing payment methods because settings are invalid');
$this->removeVRPaymentPaymentMethodFromConfirmPage($event);
return;
}
$createdTransactionId = $this->transactionService->createPendingTransaction($salesChannelContext, $event);
$this->updateTempTransactionIfNeeded($salesChannelContext, $createdTransactionId);
$this->getAvailablePaymentMethods($settings, $createdTransactionId, $salesChannelContext);
$this->setPossiblePaymentMethods($settings->getSpaceId(), $event);
}
/**
* @param $event
* @return void
*/
private function removeVRPaymentPaymentMethodFromConfirmPage($event): void
{ {
$paymentMethodCollection = $event->getPage()->getPaymentMethods(); $paymentMethodCollection = $event->getPage()->getPaymentMethods();
$paymentMethodIds = $this->paymentMethodUtil->getVRPaymentPaymentMethodIds($event->getContext()); $paymentMethodIds = $this->paymentMethodUtil->getVRPaymentPaymentMethodIds($event->getContext());
@@ -193,7 +272,7 @@ class CheckoutSubscriber implements EventSubscriberInterface
* @param int $createdTransactionId * @param int $createdTransactionId
* @return void * @return void
*/ */
private function getAvailablePaymentMethods(Settings $settings, int $createdTransactionId): void private function getAvailablePaymentMethods(Settings $settings, int $createdTransactionId, SalesChannelContext $salesChannelContext): void
{ {
$transactionService = $settings->getApiClient()->getTransactionService(); $transactionService = $settings->getApiClient()->getTransactionService();
$possiblePaymentMethods = $transactionService->fetchPaymentMethods( $possiblePaymentMethods = $transactionService->fetchPaymentMethods(
@@ -203,9 +282,13 @@ class CheckoutSubscriber implements EventSubscriberInterface
); );
$arrayOfPossibleMethods = []; $arrayOfPossibleMethods = [];
foreach ($possiblePaymentMethods as $possiblePaymentMethod) { foreach ($possiblePaymentMethods as $possiblePaymentMethod) {
$arrayOfPossibleMethods[] = $possiblePaymentMethod->getid(); $arrayOfPossibleMethods[] = $possiblePaymentMethod->getId();
} }
$_SESSION['arrayOfPossibleMethods'] = $arrayOfPossibleMethods;
$salesChannelContext->getContext()->addExtension(
'possibleMethods',
new ArrayEntity(['ids' => $arrayOfPossibleMethods])
);
} }
/** /**
@@ -213,26 +296,55 @@ class CheckoutSubscriber implements EventSubscriberInterface
* @param CheckoutConfirmPageLoadedEvent $event * @param CheckoutConfirmPageLoadedEvent $event
* @return void * @return void
*/ */
private function setPossiblePaymentMethods(int $spaceId, CheckoutConfirmPageLoadedEvent $event): void private function setPossiblePaymentMethods(int $spaceId, $event): void
{ {
$localPaymentMethods = []; $paymentIds = [];
$paymentMethodConfigurations = $this->paymentMethodConfigurationService->getAllPaymentMethodConfigurations($spaceId, $event->getSalesChannelContext()->getContext()); $paymentMethodCollection = $event->getPage()->getPaymentMethods();
foreach ($paymentMethodConfigurations as $paymentMethodConfiguration) {
$localPaymentMethods[$paymentMethodConfiguration->getId()] = $paymentMethodConfiguration->getPaymentMethodConfigurationId(); foreach ($paymentMethodCollection as $paymentMethodCollectionItem) {
$isVRPaymentPM = VRPaymentPaymentHandler::class === $paymentMethodCollectionItem->getHandlerIdentifier();
if (!$isVRPaymentPM) {
$paymentIds[] = $paymentMethodCollectionItem->getId();
}
} }
$paymentMethodCollection = $event->getPage()->getPaymentMethods(); $allowedWLMethods = [];
foreach ($paymentMethodCollection as $paymentMethodCollectionItem) { $paymentMethodConfigurations = $this->paymentMethodConfigurationService
$isVRPaymentPM = VRPaymentPaymentHandler::class == $paymentMethodCollectionItem->getHandlerIdentifier(); ->getAllPaymentMethodConfigurations($spaceId, $event->getSalesChannelContext()->getContext());
if (!$isVRPaymentPM) {
foreach ($paymentMethodConfigurations as $paymentMethodConfiguration) {
if ($paymentMethodConfiguration->getPaymentMethod() === null) {
continue; continue;
} }
$paymentMethodConfigurationId = $localPaymentMethods[$paymentMethodCollectionItem->getId()]; $pmId = $paymentMethodConfiguration->getPaymentMethod()->getId();
if (!\in_array($paymentMethodConfigurationId, $_SESSION['arrayOfPossibleMethods'])) { $pmConfigId = $paymentMethodConfiguration->getPaymentMethodConfigurationId();
$paymentMethodCollection->remove($paymentMethodCollectionItem->getId()); $allowedIds = $this->getAllowedPaymentMethodIds($event->getSalesChannelContext());
if ($paymentMethodConfiguration->getSpaceId() === $spaceId
&& \in_array($pmConfigId, $allowedIds, true)) {
$allowedWLMethods[] = $pmId;
} }
} }
$allPaymentIds = array_unique(array_merge($paymentIds, $allowedWLMethods));
$collection = new PaymentMethodCollection();
if (!empty($allPaymentIds)) {
$criteria = new Criteria($allPaymentIds);
$criteria->addFilter(new EqualsFilter('active', true));
$criteria->addFilter(
new EqualsFilter('salesChannels.id', $event->getSalesChannelContext()->getSalesChannelId())
);
$result = $this->paymentMethodRepository->search($criteria, $event->getContext());
foreach ($result->getEntities() as $method) {
if (!$collection->has($method->getId())) {
$collection->add($method);
}
}
}
$event->getPage()->setPaymentMethods($collection);
} }
/** /**
@@ -242,19 +354,43 @@ class CheckoutSubscriber implements EventSubscriberInterface
*/ */
private function updateTempTransactionIfNeeded(SalesChannelContext $salesChannelContext, int $createdTransactionId): void private function updateTempTransactionIfNeeded(SalesChannelContext $salesChannelContext, int $createdTransactionId): void
{ {
$addressCheck = $_SESSION['addressCheck'] ?? null; $ctx = $salesChannelContext->getContext();
$currencyCheck = $_SESSION['currencyCheck'] ?? null;
/** @var ArrayEntity|null $ext */
$ext = $ctx->getExtension('checkoutState');
$oldAddressHash = $ext instanceof ArrayEntity ? $ext->get('addressHash') : null;
$oldCurrency = $ext instanceof ArrayEntity ? $ext->get('currency') : null;
$customer = $salesChannelContext->getCustomer(); $customer = $salesChannelContext->getCustomer();
$addressHash = md5(json_encode((array) $customer)); $addressHash = md5(json_encode((array) $customer));
$currency = $salesChannelContext->getCurrency()->getIsoCode(); $currency = $salesChannelContext->getCurrency()->getIsoCode();
if (($addressCheck && $currencyCheck) && $addressCheck !== $addressHash || $currencyCheck !== $currency) {
$needsUpdate = ($oldAddressHash !== $addressHash) || ($oldCurrency !== $currency);
if ($needsUpdate) {
if ($createdTransactionId) { if ($createdTransactionId) {
$this->transactionService->updateTempTransaction($salesChannelContext, $createdTransactionId); $this->transactionService->updateTempTransaction($salesChannelContext, $createdTransactionId);
} }
$_SESSION['arrayOfPossibleMethods'] = null;
$_SESSION['addressCheck'] = $addressHash; $ctx->addExtension('possibleMethods', new ArrayEntity(['ids' => []]));
$_SESSION['currencyCheck'] = $currency; $ctx->addExtension(
'checkoutState',
new ArrayEntity([
'addressHash' => $addressHash,
'currency' => $currency,
])
);
} }
} }
/**
* @param SalesChannelContext $salesChannelContext
* @return array
*/
private function getAllowedPaymentMethodIds(SalesChannelContext $salesChannelContext): array
{
$ext = $salesChannelContext->getContext()->getExtension('possibleMethods');
return $ext instanceof ArrayEntity ? ($ext->get('ids') ?? []) : [];
}
} }
+58 -5
View File
@@ -3,6 +3,7 @@
namespace VRPaymentPayment\Core\Util\Analytics; namespace VRPaymentPayment\Core\Util\Analytics;
use VRPayment\Sdk\ApiClient; use VRPayment\Sdk\ApiClient;
use Shopware\Core\Kernel;
/** /**
* Class Analytics * Class Analytics
@@ -19,26 +20,78 @@ class Analytics {
/** /**
* @return array * @return array
*/ */
public static function getDefaultData() public static function getDefaultData(): array
{ {
$shopwareVersion = self::getShopwareVersion();
return [ return [
self::SHOP_SYSTEM => 'shopware', self::SHOP_SYSTEM => 'shopware',
self::SHOP_SYSTEM_VERSION => '6', self::SHOP_SYSTEM_VERSION => $shopwareVersion,
self::SHOP_SYSTEM_AND_VERSION => 'shopware-6', self::SHOP_SYSTEM_AND_VERSION => 'shopware-' . $shopwareVersion,
self::PLUGIN_SYSTEM_VERSION => '6.1.16', self::PLUGIN_SYSTEM_VERSION => '6.1.17',
]; ];
} }
/** /**
* @param \VRPayment\Sdk\ApiClient $apiClient * @param \VRPayment\Sdk\ApiClient $apiClient
*/ */
public static function addHeaders(ApiClient &$apiClient) public static function addHeaders(ApiClient &$apiClient): void
{ {
$data = self::getDefaultData(); $data = self::getDefaultData();
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
$apiClient->addDefaultHeader($key, $value); $apiClient->addDefaultHeader($key, $value);
} }
} }
/**
* Reads Shopware version and caches it for performance.
*
* @return string
*/
public static function getShopwareVersion(): string
{
static $cachedVersion = null;
if ($cachedVersion !== null) {
return $cachedVersion;
} }
$basePath = dirname(__DIR__, 7);
$installedFile = $basePath . '/vendor/composer/installed.php';
if (is_file($installedFile)) {
$installed = include $installedFile;
$packages = [];
if (isset($installed['versions'])) {
$packages = $installed['versions'];
} elseif (is_array($installed)) {
foreach ($installed as $section) {
if (isset($section['versions'])) {
$packages = $section['versions'];
break;
}
}
}
if (isset($packages['shopware/core']['pretty_version'])) {
return $cachedVersion = ltrim($packages['shopware/core']['pretty_version'], 'v');
}
}
$lockFile = $basePath . '/composer.lock';
if (is_file($lockFile)) {
$data = json_decode((string) file_get_contents($lockFile), true);
if (!empty($data['packages'])) {
foreach ($data['packages'] as $package) {
if (($package['name'] ?? '') === 'shopware/core') {
return $cachedVersion = ltrim($package['version'], 'v');
}
}
}
}
return $cachedVersion = Kernel::SHOPWARE_FALLBACK_VERSION;
}
}
+27 -17
View File
@@ -12,6 +12,7 @@ use Shopware\Core\{Checkout\Cart\Tax\Struct\CalculatedTaxCollection,
Framework\DataAbstractionLayer\Search\Criteria, Framework\DataAbstractionLayer\Search\Criteria,
System\SalesChannel\SalesChannelContext System\SalesChannel\SalesChannelContext
}; };
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
use VRPayment\Sdk\{Model\AddressCreate, use VRPayment\Sdk\{Model\AddressCreate,
@@ -193,10 +194,16 @@ class TransactionPayload extends AbstractPayload
->setShippingAddress($shippingAddress) ->setShippingAddress($shippingAddress)
->setShippingMethod($transactionData['shipping_method']); ->setShippingMethod($transactionData['shipping_method']);
$paymentConfiguration = $this->getPaymentConfiguration($this->salesChannelContext->getPaymentMethod()->getId()); $paymentConfiguration = $this->getPaymentConfiguration(
$this->salesChannelContext->getPaymentMethod()->getId(),
$transactionPayload->setAllowedPaymentMethodConfigurations([$paymentConfiguration->getPaymentMethodConfigurationId()]); $this->settings->getSpaceId()
);
if ($paymentConfiguration) {
$transactionPayload->setAllowedPaymentMethodConfigurations([
$paymentConfiguration->getPaymentMethodConfigurationId()
]);
}
$successUrl = $this->transaction->getReturnUrl() . '&status=paid'; $successUrl = $this->transaction->getReturnUrl() . '&status=paid';
$failedUrl = $this->getFailUrl($this->transaction->getOrder()->getId()) . '&status=fail'; $failedUrl = $this->getFailUrl($this->transaction->getOrder()->getId()) . '&status=fail';
$transactionPayload->setSuccessUrl($successUrl) $transactionPayload->setSuccessUrl($successUrl)
@@ -210,6 +217,23 @@ class TransactionPayload extends AbstractPayload
return $transactionPayload; return $transactionPayload;
} }
/**
* @param string $paymentMethodId
* @param int $spaceId
* @return PaymentMethodConfigurationEntity|null
*/
protected function getPaymentConfiguration(string $paymentMethodId, int $spaceId): ?PaymentMethodConfigurationEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('paymentMethodId', $paymentMethodId));
$criteria->addFilter(new EqualsFilter('spaceId', $spaceId));
return $this->container->get('vrpayment_payment_method_configuration.repository')
->search($criteria, $this->salesChannelContext->getContext())
->first();
}
/** /**
* Get transaction line items * Get transaction line items
* *
@@ -792,20 +816,6 @@ class TransactionPayload extends AbstractPayload
return $addressPayload; return $addressPayload;
} }
/**
* @param string $id
*
* @return \VRPaymentPayment\Core\Api\PaymentMethodConfiguration\Entity\PaymentMethodConfigurationEntity
*/
protected function getPaymentConfiguration(string $id): PaymentMethodConfigurationEntity
{
$criteria = (new Criteria([$id]));
return $this->container->get('vrpayment_payment_method_configuration.repository')
->search($criteria, $this->salesChannelContext->getContext())
->getEntities()->first();
}
/** /**
* Get failure URL * Get failure URL
* *
@@ -14,7 +14,7 @@
{% block vrpayment_settings_content_card_channel_config_credentials_card_container_settings_space_id %} {% block vrpayment_settings_content_card_channel_config_credentials_card_container_settings_space_id %}
<sw-inherit-wrapper <sw-inherit-wrapper
v-model:value="actualConfigData[CONFIG_SPACE_ID]" v-model:value="actualConfigData[CONFIG_SPACE_ID]"
:inheritedValue="selectedSalesChannelId === null ? null : allConfigs['null'][CONFIG_SPACE_ID]" :inheritedValue="getInheritedValue(CONFIG_SPACE_ID)"
:customInheritationCheckFunction="checkNumberFieldInheritance"> :customInheritationCheckFunction="checkNumberFieldInheritance">
<template #content="props"> <template #content="props">
<sw-number-field <sw-number-field
@@ -23,7 +23,7 @@
:mapInheritance="props" :mapInheritance="props"
:label="$tc('vrpayment-settings.settingForm.credentials.spaceId.label')" :label="$tc('vrpayment-settings.settingForm.credentials.spaceId.label')"
:helpText="$tc('vrpayment-settings.settingForm.credentials.spaceId.tooltipText')" :helpText="$tc('vrpayment-settings.settingForm.credentials.spaceId.tooltipText')"
:disabled="props.isInherited || !acl.can('vrpayment.editor')" :disabled="!acl.can('vrpayment.editor')"
:value="props.currentValue" :value="props.currentValue"
:error="spaceIdErrorState" :error="spaceIdErrorState"
@update:value="props.updateCurrentValue"> @update:value="props.updateCurrentValue">
@@ -35,7 +35,7 @@
{% block vrpayment_settings_content_card_channel_config_credentials_card_container_settings_user_id %} {% block vrpayment_settings_content_card_channel_config_credentials_card_container_settings_user_id %}
<sw-inherit-wrapper <sw-inherit-wrapper
v-model:value="actualConfigData[CONFIG_USER_ID]" v-model:value="actualConfigData[CONFIG_USER_ID]"
:inheritedValue="selectedSalesChannelId === null ? null : allConfigs['null'][CONFIG_USER_ID]" :inheritedValue="getInheritedValue(CONFIG_USER_ID)"
:customInheritationCheckFunction="checkNumberFieldInheritance"> :customInheritationCheckFunction="checkNumberFieldInheritance">
<template #content="props"> <template #content="props">
<sw-number-field <sw-number-field
@@ -44,7 +44,7 @@
:mapInheritance="props" :mapInheritance="props"
:label="$tc('vrpayment-settings.settingForm.credentials.userId.label')" :label="$tc('vrpayment-settings.settingForm.credentials.userId.label')"
:helpText="$tc('vrpayment-settings.settingForm.credentials.userId.tooltipText')" :helpText="$tc('vrpayment-settings.settingForm.credentials.userId.tooltipText')"
:disabled="props.isInherited || !acl.can('vrpayment.editor')" :disabled="!acl.can('vrpayment.editor')"
:value="props.currentValue" :value="props.currentValue"
:error="userIdErrorState" :error="userIdErrorState"
@update:value="props.updateCurrentValue"> @update:value="props.updateCurrentValue">
@@ -56,7 +56,7 @@
{% block vrpayment_settings_content_card_channel_config_credentials_card_container_settings_application_key %} {% block vrpayment_settings_content_card_channel_config_credentials_card_container_settings_application_key %}
<sw-inherit-wrapper <sw-inherit-wrapper
v-model:value="actualConfigData[CONFIG_APPLICATION_KEY]" v-model:value="actualConfigData[CONFIG_APPLICATION_KEY]"
:inheritedValue="selectedSalesChannelId === null ? null : allConfigs['null'][CONFIG_APPLICATION_KEY]" :inheritedValue="getInheritedValue(CONFIG_APPLICATION_KEY)"
:customInheritationCheckFunction="checkTextFieldInheritance"> :customInheritationCheckFunction="checkTextFieldInheritance">
<template #content="props"> <template #content="props">
<sw-password-field <sw-password-field
@@ -66,7 +66,7 @@
:mapInheritance="props" :mapInheritance="props"
:label="$tc('vrpayment-settings.settingForm.credentials.applicationKey.label')" :label="$tc('vrpayment-settings.settingForm.credentials.applicationKey.label')"
:helpText="$tc('vrpayment-settings.settingForm.credentials.applicationKey.tooltipText')" :helpText="$tc('vrpayment-settings.settingForm.credentials.applicationKey.tooltipText')"
:disabled="props.isInherited || !acl.can('vrpayment.editor')" :disabled="!acl.can('vrpayment.editor')"
:value="props.currentValue" :value="props.currentValue"
:error="applicationKeyErrorState" :error="applicationKeyErrorState"
@update:value="props.updateCurrentValue"> @update:value="props.updateCurrentValue">
@@ -6,7 +6,7 @@ import constants from '../../page/vrpayment-settings/configuration-constants'
const {Component, Mixin} = Shopware; const {Component, Mixin} = Shopware;
Component.register('sw-vrpayment-credentials', { Component.register('sw-vrpayment-credentials', {
template: template, template,
name: 'VRPaymentCredentials', name: 'VRPaymentCredentials',
@@ -29,7 +29,9 @@ Component.register('sw-vrpayment-credentials', {
}, },
selectedSalesChannelId: { selectedSalesChannelId: {
required: true type: [String, null],
required: false,
default: null
}, },
spaceIdFilled: { spaceIdFilled: {
type: Boolean, type: Boolean,
@@ -68,22 +70,24 @@ Component.register('sw-vrpayment-credentials', {
}; };
}, },
computed: {
currentConfig() {
if (this.selectedSalesChannelId && this.allConfigs[this.selectedSalesChannelId]) {
return this.allConfigs[this.selectedSalesChannelId];
}
return this.allConfigs['null'] || {};
}
},
methods: { methods: {
checkTextFieldInheritance(value) { checkTextFieldInheritance(value) {
if (typeof value !== 'string') { return !value || value.length <= 0;
return true;
}
return value.length <= 0;
}, },
checkNumberFieldInheritance(value) { checkNumberFieldInheritance(value) {
if (typeof value !== 'number') { return value == null || value === '';
return true;
}
return value.length <= 0;
}, },
checkBoolFieldInheritance(value) { checkBoolFieldInheritance(value) {
@@ -94,12 +98,16 @@ Component.register('sw-vrpayment-credentials', {
// Used to trigger API connection testing from this component. // Used to trigger API connection testing from this component.
emitCheckApiConnectionEvent() { emitCheckApiConnectionEvent() {
const apiConnectionParams = { const apiConnectionParams = {
spaceId: this.actualConfigData[constants.CONFIG_SPACE_ID], spaceId: this.currentConfig[constants.CONFIG_SPACE_ID],
userId: this.actualConfigData[constants.CONFIG_USER_ID], userId: this.currentConfig[constants.CONFIG_USER_ID],
applicationKey: this.actualConfigData[constants.CONFIG_APPLICATION_KEY] applicationKey: this.currentConfig[constants.CONFIG_APPLICATION_KEY]
}; };
this.$emit('check-api-connection-event', apiConnectionParams); this.$emit('check-api-connection-event', apiConnectionParams);
},
getInheritedValue(key) {
return this.allConfigs['null']?.[key] ?? null;
} }
} }
}); });
@@ -1,11 +1,11 @@
{% block vrpayment_settings %} {% block vrpayment_settings %}
<sw-page class="vrpayment-settings">
<sw-page class="vrpayment-settings">
{% block vrpayment_settings_header %} {% block vrpayment_settings_header %}
<template #smart-bar-header> <template #smart-bar-header>
<h2> <h2>
{{ $tc('sw-settings.index.title') }} {{ $tc('sw-settings.index.title') }}
<sw-icon name="small-arrow-medium-right" small></sw-icon> <mt-icon name="small-arrow-medium-right" size="16px"></mt-icon>
{{ $tc('vrpayment-settings.header') }} {{ $tc('vrpayment-settings.header') }}
</h2> </h2>
</template> </template>
@@ -14,7 +14,7 @@
{% block vrpayment_settings_actions %} {% block vrpayment_settings_actions %}
<template #smart-bar-actions> <template #smart-bar-actions>
{% block vrpayment_settings_actions_save %} {% block vrpayment_settings_actions_save %}
<sw-button-process <mt-button
v-model:value="isSaveSuccessful" v-model:value="isSaveSuccessful"
class="sw-settings-login-registration__save-action" class="sw-settings-login-registration__save-action"
variant="primary" variant="primary"
@@ -22,7 +22,7 @@
:disabled="isLoading" :disabled="isLoading"
@click="onSave"> @click="onSave">
{{ $tc('vrpayment-settings.settingForm.save') }} {{ $tc('vrpayment-settings.settingForm.save') }}
</sw-button-process> </mt-button>
{% endblock %} {% endblock %}
</template> </template>
{% endblock %} {% endblock %}
@@ -31,7 +31,7 @@
<template #content> <template #content>
{% block vrpayment_settings_content_card %} {% block vrpayment_settings_content_card %}
<sw-card-view> <mt-card-view>
{% block vrpayment_settings_content_card_channel_config %} {% block vrpayment_settings_content_card_channel_config %}
<sw-sales-channel-config v-model:value="config" <sw-sales-channel-config v-model:value="config"
@@ -42,18 +42,17 @@
<template #select="{ onInput, selectedSalesChannelId, salesChannel }"> <template #select="{ onInput, selectedSalesChannelId, salesChannel }">
{% block vrpayment_settings_content_card_channel_config_sales_channel_card %} {% block vrpayment_settings_content_card_channel_config_sales_channel_card %}
<sw-card title="Sales Channel Switch"> <mt-card title="Sales Channel Switch">
{% block vrpayment_settings_content_card_channel_config_sales_channel_card_title %} {% block vrpayment_settings_content_card_channel_config_sales_channel_card_title %}
<sw-single-select <sw-single-select
v-model:value="selectedSalesChannelId" :value="selectedSalesChannelId"
labelProperty="translated.name" :options="salesChannel.map(sc => ({ id: sc.id, name: sc.translated.name }))"
labelProperty="name"
valueProperty="id" valueProperty="id"
:mapInheritance="props"
:isLoading="isLoading" :isLoading="isLoading"
:options="salesChannel" @update:value="onInput"
@update:value="onInput"> />
</sw-single-select>
{% endblock %} {% endblock %}
{% block vrpayment_settings_content_card_channel_config_sales_channel_card_footer %} {% block vrpayment_settings_content_card_channel_config_sales_channel_card_footer %}
<template #footer> <template #footer>
@@ -66,18 +65,19 @@
{% endblock %} {% endblock %}
{% block vrpayment_settings_content_card_channel_config_sales_channel_card_footer_container_button %} {% block vrpayment_settings_content_card_channel_config_sales_channel_card_footer_container_button %}
<sw-button-process <sw-button
variant="primary"
v-model:value="isSetDefaultPaymentSuccessful" v-model:value="isSetDefaultPaymentSuccessful"
:isLoading="isSettingDefaultPaymentMethods" :isLoading="isSettingDefaultPaymentMethods"
@click="onSetPaymentMethodDefault"> @click="onSetPaymentMethodDefault">
{{ $tc('vrpayment-settings.salesChannelCard.button.label') }} {{ $tc('vrpayment-settings.salesChannelCard.button.label') }}
</sw-button-process> </sw-button>
{% endblock %} {% endblock %}
</sw-container> </sw-container>
{% endblock %} {% endblock %}
</template> </template>
{% endblock %} {% endblock %}
</sw-card> </mt-card>
{% endblock %} {% endblock %}
</template> </template>
{% endblock %} {% endblock %}
@@ -134,9 +134,9 @@
{% endblock %} {% endblock %}
{% block vrpayment_settings_content_card_loading %} {% block vrpayment_settings_content_card_loading %}
<sw-loader v-if="isLoading"></sw-loader> <mt-loader v-if="isLoading"></mt-loader>
{% endblock %} {% endblock %}
</sw-card-view> </mt-card-view>
{% endblock %} {% endblock %}
</template> </template>
@@ -80,7 +80,7 @@ Component.register('vrpayment-settings', {
watch: { watch: {
config: { config: {
handler(configData) { handler(configData) {
const defaultConfig = this.$refs.configComponent.allConfigs.null; const defaultConfig = (this.$refs.configComponent.allConfigs || {}).null || {};
const salesChannelId = this.$refs.configComponent.selectedSalesChannelId; const salesChannelId = this.$refs.configComponent.selectedSalesChannelId;
if (salesChannelId === null) { if (salesChannelId === null) {
File diff suppressed because one or more lines are too long
@@ -15,6 +15,7 @@
<argument type="service" id="Shopware\Core\Checkout\Order\SalesChannel\OrderRoute"/> <argument type="service" id="Shopware\Core\Checkout\Order\SalesChannel\OrderRoute"/>
<argument type="service" id="Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStateHandler"/> <argument type="service" id="Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStateHandler"/>
<argument type="service" id="Shopware\Core\System\StateMachine\StateMachineRegistry"/> <argument type="service" id="Shopware\Core\System\StateMachine\StateMachineRegistry"/>
<argument type="service" id="Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface"/>
<call method="setLogger"> <call method="setLogger">
<argument type="service" id="monolog.logger.vrpayment_payment"/> <argument type="service" id="monolog.logger.vrpayment_payment"/>
</call> </call>
@@ -32,6 +33,7 @@
<argument id="VRPaymentPayment\Core\Api\Transaction\Service\TransactionService" type="service"/> <argument id="VRPaymentPayment\Core\Api\Transaction\Service\TransactionService" type="service"/>
<argument id="VRPaymentPayment\Core\Settings\Service\SettingsService" type="service"/> <argument id="VRPaymentPayment\Core\Settings\Service\SettingsService" type="service"/>
<argument id="VRPaymentPayment\Core\Util\PaymentMethodUtil" type="service"/> <argument id="VRPaymentPayment\Core\Util\PaymentMethodUtil" type="service"/>
<argument id="payment_method.repository" type="service"/>
<call method="setLogger"> <call method="setLogger">
<argument type="service" id="monolog.logger.vrpayment_payment"/> <argument type="service" id="monolog.logger.vrpayment_payment"/>
</call> </call>
@@ -0,0 +1,2 @@
.sw-order-detail .sw-tabs{margin-top:40px}.sw-order-detail .sw-order-detail-base .sw-card-view__content{overflow-x:visible;overflow-y:visible}
.vrpayment-order-detail__data{display:grid}.vrpayment-order-detail__heading{padding-top:15px}
File diff suppressed because one or more lines are too long