mirror of
https://github.com/vr-payment/shopware-6.git
synced 2026-06-04 19:03:01 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93f24a2cac | |||
| dbd0b6808c | |||
| 3f3bf866dd |
@@ -1,3 +1,21 @@
|
||||
# 7.3.3
|
||||
- Shopware 6.7.9.0 compatible
|
||||
- Fix for only showing 25 sales channels in selector
|
||||
- Fixed bug with discount occasionally blocking payment methods
|
||||
|
||||
# 7.3.2
|
||||
- Fix for partial refunds using standard refund option
|
||||
- Fixed issue with undefined array key
|
||||
- Fixed issue with recurring payments
|
||||
- Fixed concrete class reference; used interface instead
|
||||
|
||||
# 7.3.1
|
||||
- Shopware 6.7.7.0 compatibility
|
||||
- Fix for missing payment icons
|
||||
- Fixed issue with 'Entire Set' coupons returning error due to totals mismatch
|
||||
- Fixed issue with orphaned order_transactions causing an admin UI failure
|
||||
- Fixed error thrown when customers who aren't logged in attempt to download an invoice
|
||||
|
||||
# 7.3.0
|
||||
- Headless storefront support
|
||||
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
# 7.3.3
|
||||
- Kompatibel mit Shopware 6.7.9.0
|
||||
- Problem behoben, dass im Selektor nur 25 Vertriebskanäle angezeigt wurden
|
||||
- Fehler behoben, der gelegentlich dazu führte, dass Rabatte Zahlungsmethoden blockierten
|
||||
|
||||
# 7.3.2
|
||||
- Problem mit Teilrückerstattungen über die Standardrückerstattungsoption behoben
|
||||
- Problem mit undefiniertem Array-Schlüssel behoben
|
||||
- Problem mit einziehenden Zahlungen behoben
|
||||
- Konkrete Klasse durch Verwendung einer Schnittstelle korrigiert
|
||||
# 7.3.1
|
||||
- Kompatibilität mit Shopware 6.7.7.0
|
||||
- Fehlende Zahlungssymbole behoben
|
||||
- Problem mit „Gesamtes Set“-Gutscheinen aufgrund von Summenabweichungen behoben
|
||||
- Problem mit verwaisten Bestelltransaktionen behoben, die zu einem Fehler in der Admin-Oberfläche führten
|
||||
- Ein Fehler wurde behoben, der auftrat, wenn nicht angemeldete Kunden versuchten, eine Rechnung herunterzuladen.
|
||||
|
||||
# 7.3.0
|
||||
- Headless Storefront unterstützung
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ Please note that this plugin is for versions 6.5, 6.6 or 6.7. For the 6.4 plugin
|
||||
|
||||
## Documentation
|
||||
|
||||
- For English documentation click [here](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.0/docs/en/documentation.html)
|
||||
- Für die deutsche Dokumentation klicken Sie [hier](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.0/docs/de/documentation.html)
|
||||
- Pour la documentation Française, cliquez [ici](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.0/docs/fr/documentation.html)
|
||||
- Per la documentazione in tedesco, clicca [qui](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.0/docs/it/documentation.html)
|
||||
- For English documentation click [here](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.3/docs/en/documentation.html)
|
||||
- Für die deutsche Dokumentation klicken Sie [hier](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.3/docs/de/documentation.html)
|
||||
- Pour la documentation Française, cliquez [ici](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.3/docs/fr/documentation.html)
|
||||
- Per la documentazione in tedesco, clicca [qui](https://docs.plugin-documentation.vr-payment.de/vr-payment/shopware-6/7.3.3/docs/it/documentation.html)
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
+1
-1
@@ -59,5 +59,5 @@
|
||||
"vrpayment/sdk": "^4.0.0"
|
||||
},
|
||||
"type": "shopware-platform-plugin",
|
||||
"version": "7.3.0"
|
||||
"version": "7.3.3"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.0/">
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.3/">
|
||||
Source
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.0/">
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.3/">
|
||||
Source
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.0/">
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.3/">
|
||||
Source
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.0/">
|
||||
<a href="https://github.com/vr-payment/shopware-6/releases/tag/7.3.3/">
|
||||
Source
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -14,7 +14,8 @@ use Symfony\Component\{
|
||||
use VRPaymentPayment\Core\{
|
||||
Api\Refund\Service\RefundService,
|
||||
Api\Transaction\Service\TransactionService,
|
||||
Settings\Service\SettingsService
|
||||
Settings\Service\SettingsService,
|
||||
Util\Exception\RefundNotSupportedException
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -105,7 +106,12 @@ class RefundController extends AbstractController
|
||||
return new Response('refundExceedsQuantity', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$refund = $this->refundService->create($transaction, $context, $lineItemId, $quantity);
|
||||
try {
|
||||
$refund = $this->refundService->create($transaction, $context, $lineItemId, $quantity);
|
||||
} catch (RefundNotSupportedException $exception) {
|
||||
$this->logger->info('Payment method does not support online refunds for transaction: ' . $transactionId);
|
||||
return new Response('methodDoesNotSupportRefund', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($refund === null) {
|
||||
return new Response('Refund was not created. Please check the refund amound or if the item was not refunded before', Response::HTTP_BAD_REQUEST);
|
||||
@@ -148,7 +154,12 @@ class RefundController extends AbstractController
|
||||
return new Response('refundExceedsAmount', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$refund = $this->refundService->createRefundByAmount($transaction, $refundableAmount, $context);
|
||||
try {
|
||||
$refund = $this->refundService->createRefundByAmount($transaction, $refundableAmount, $context);
|
||||
} catch (RefundNotSupportedException $exception) {
|
||||
$this->logger->info('Payment method does not support online refunds for transaction: ' . $transactionId);
|
||||
return new Response('methodDoesNotSupportRefund', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($refund === null) {
|
||||
return new Response('refundExceedsAmount', Response::HTTP_BAD_REQUEST);
|
||||
@@ -179,7 +190,13 @@ class RefundController extends AbstractController
|
||||
$apiClient = $settings->getApiClient();
|
||||
|
||||
$transaction = $apiClient->getTransactionService()->read($settings->getSpaceId(), $transactionId);
|
||||
$this->refundService->createPartialRefund($transaction, $context, $lineItemId, $refundableAmount);
|
||||
|
||||
try {
|
||||
$refund = $this->refundService->createPartialRefund($transaction, $context, $lineItemId, $refundableAmount);
|
||||
} catch (RefundNotSupportedException $exception) {
|
||||
$this->logger->info('Payment method does not support online refunds for transaction: ' . $transactionId);
|
||||
return new Response('methodDoesNotSupportRefund', Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
return new Response(null, Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
@@ -17,13 +17,15 @@ use VRPayment\Sdk\{
|
||||
Model\EntityQueryFilter,
|
||||
Model\EntityQueryFilterType,
|
||||
Model\EntityQuery,
|
||||
ApiException
|
||||
};
|
||||
use VRPaymentPayment\Core\{
|
||||
Api\Refund\Entity\RefundEntity,
|
||||
Api\Transaction\Entity\TransactionEntity,
|
||||
Api\Transaction\Entity\TransactionEntityDefinition,
|
||||
Settings\Service\SettingsService,
|
||||
Util\Payload\RefundPayload
|
||||
Util\Payload\RefundPayload,
|
||||
Util\Exception\RefundNotSupportedException
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -103,6 +105,12 @@ class RefundService
|
||||
$this->upsert($refund, $context);
|
||||
return $refund;
|
||||
}
|
||||
} catch (ApiException $exception) {
|
||||
$message = $exception->getMessage();
|
||||
$this->logger->critical($message);
|
||||
if ($exception->getCode() === 442 && str_contains($message, 'does not support online refunds')) {
|
||||
throw new RefundNotSupportedException($message, 0, $exception);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->critical($exception->getMessage());
|
||||
}
|
||||
@@ -138,6 +146,12 @@ class RefundService
|
||||
$this->upsert($refund, $context);
|
||||
return $refund;
|
||||
}
|
||||
} catch (ApiException $exception) {
|
||||
$message = $exception->getMessage();
|
||||
$this->logger->critical($message);
|
||||
if ($exception->getCode() === 442 && str_contains($message, 'does not support online refunds')) {
|
||||
throw new RefundNotSupportedException($message, 0, $exception);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->critical($exception->getMessage());
|
||||
}
|
||||
@@ -174,6 +188,12 @@ class RefundService
|
||||
$this->upsert($refund, $context);
|
||||
return $refund;
|
||||
}
|
||||
} catch (ApiException $exception) {
|
||||
$message = $exception->getMessage();
|
||||
$this->logger->critical($message);
|
||||
if ($exception->getCode() === 442 && str_contains($message, 'does not support online refunds')) {
|
||||
throw new RefundNotSupportedException($message, 0, $exception);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$this->logger->critical($exception->getMessage());
|
||||
}
|
||||
|
||||
@@ -313,8 +313,8 @@ class TransactionService
|
||||
public function upsert(
|
||||
Transaction $transaction,
|
||||
Context $context,
|
||||
string $paymentMethodId = null,
|
||||
string $salesChannelId = null
|
||||
?string $paymentMethodId = null,
|
||||
?string $salesChannelId = null
|
||||
): void {
|
||||
try {
|
||||
|
||||
@@ -328,6 +328,13 @@ class TransactionService
|
||||
$orderId = $transactionMetaData[TransactionPayload::VRPAYMENT_METADATA_ORDER_ID];
|
||||
$orderTransactionId = $transactionMetaData[TransactionPayload::VRPAYMENT_METADATA_ORDER_TRANSACTION_ID];
|
||||
|
||||
if (!$paymentMethodId) {
|
||||
$criteria = new Criteria([$orderTransactionId]);
|
||||
$criteria->addAssociation('order');
|
||||
$orderTransaction = $this->container->get('order_transaction.repository')->search($criteria, $context)->first();
|
||||
$paymentMethodId = $orderTransaction->getPaymentMethodId();
|
||||
}
|
||||
|
||||
$dataParamValue = json_decode(strval($transaction), true);
|
||||
$brandName = '';
|
||||
if (isset($dataParamValue['paymentConnectorConfiguration'])) {
|
||||
@@ -617,11 +624,14 @@ class TransactionService
|
||||
throw new \Exception('Space settings not configured');
|
||||
}
|
||||
|
||||
$language = $this->localeCodeProvider->getLocaleCodeFromContext($salesChannelContext->getContext());
|
||||
|
||||
$transactionPayload = (new TransactionCreate())
|
||||
->setBillingAddress($billingAddress)
|
||||
->setShippingAddress($shippingAddress)
|
||||
->setLineItems($lineItems)
|
||||
->setCurrency($currency)
|
||||
->setLanguage($language)
|
||||
->setSpaceViewId($settings->getSpaceViewId())
|
||||
->setAutoConfirmationEnabled(false)
|
||||
->setChargeRetryEnabled(false)
|
||||
@@ -661,7 +671,10 @@ class TransactionService
|
||||
|
||||
$currency = $salesChannelContext->getCurrency()->getIsoCode();
|
||||
|
||||
$language = $this->localeCodeProvider->getLocaleCodeFromContext($salesChannelContext->getContext());
|
||||
|
||||
$pendingTransaction->setCurrency($currency);
|
||||
$pendingTransaction->setLanguage($language);
|
||||
$billingAddress = $this->buildAddress($salesChannelContext, $salesChannelContext->getCustomer()->getActiveBillingAddress());
|
||||
$shippingAddress = $this->buildAddress($salesChannelContext, $salesChannelContext->getCustomer()->getActiveShippingAddress());
|
||||
|
||||
@@ -800,20 +813,26 @@ class TransactionService
|
||||
{
|
||||
$lineItem = new LineItemCreate();
|
||||
|
||||
$roundedPrice = $this->round($productData->getPrice()->getUnitPrice());
|
||||
$price = $productData->getPrice();
|
||||
$unit = $price->getUnitPrice();
|
||||
|
||||
// Expects discounts as separate items, avoid negative prices
|
||||
if ($unit < 0) {
|
||||
return $this->mapDiscountLineItem($productData);
|
||||
}
|
||||
|
||||
if ($productData instanceof LineItem) {
|
||||
$lineItem->setName($productData->getLabel());
|
||||
$lineItem->setUniqueId($productData->getId());
|
||||
$lineItem->setSku($productData->getReferencedId() ?? $productData->getId());
|
||||
$lineItem->setQuantity($productData->getQuantity());
|
||||
$lineItem->setAmountIncludingTax($roundedPrice);
|
||||
$lineItem->setAmountIncludingTax($this->round($unit));
|
||||
} 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($roundedPrice);
|
||||
$lineItem->setAmountIncludingTax($this->round($unit));
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Unsupported line item type: ' . get_class($productData));
|
||||
}
|
||||
@@ -984,4 +1003,29 @@ class TransactionService
|
||||
// Store in session for Storefront.
|
||||
$_SESSION['transactionId'] = $transactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a discount line item for negative-priced cart entries.
|
||||
*
|
||||
* @param $productData
|
||||
* @return LineItemCreate
|
||||
*
|
||||
*/
|
||||
private function mapDiscountLineItem($productData): LineItemCreate
|
||||
{
|
||||
$price = $productData->getPrice();
|
||||
|
||||
$lineItem = new LineItemCreate();
|
||||
|
||||
$amount = abs($price->getTotalPrice());
|
||||
|
||||
$lineItem->setName($productData->getLabel() ?: 'Discount');
|
||||
$lineItem->setUniqueId('discount-' . $productData->getId());
|
||||
$lineItem->setSku('discount');
|
||||
$lineItem->setQuantity(1);
|
||||
$lineItem->setAmountIncludingTax($this->round($amount));
|
||||
$lineItem->setType(LineItemType::DISCOUNT);
|
||||
|
||||
return $lineItem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +486,7 @@ class WebHookController extends AbstractController {
|
||||
$transaction = $this->settings->getApiClient()
|
||||
->getTransactionService()
|
||||
->read($callBackData->getSpaceId(), $callBackData->getEntityId());
|
||||
$orderId = $transaction->getMetaData()[TransactionPayload::VRPAYMENT_METADATA_ORDER_ID];
|
||||
$orderId = $transaction->getMetaData()[TransactionPayload::VRPAYMENT_METADATA_ORDER_ID] ?? null;
|
||||
if(!empty($orderId) && !$transaction->getParent()) {
|
||||
$this->executeLocked($orderId, $context, function () use ($orderId, $transaction, $context, $callBackData) {
|
||||
$this->transactionService->upsert($transaction, $context);
|
||||
|
||||
@@ -64,7 +64,7 @@ class WebHookRefundStrategy extends WebHookStrategyBase implements WebhookStrate
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrderIdByTransaction($transaction): string
|
||||
public function getOrderIdByTransaction($transaction): string|null
|
||||
{
|
||||
/** @var \VRPayment\Sdk\Model\Refund $transaction */
|
||||
return $transaction->getTransaction()
|
||||
|
||||
@@ -63,10 +63,10 @@ class WebHookTransactionInvoiceStrategy extends WebHookStrategyBase implements W
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrderIdByTransaction($transaction): string
|
||||
public function getOrderIdByTransaction($transactionInvoice): string|null
|
||||
{
|
||||
/** @var \VRPayment\Sdk\Model\TransactionInvoice $transaction */
|
||||
return $transaction->getCompletion()
|
||||
return $transactionInvoice->getCompletion()
|
||||
->getLineItemVersion()
|
||||
->getTransaction()
|
||||
->getMetaData()[TransactionPayload::VRPAYMENT_METADATA_ORDER_ID];
|
||||
|
||||
@@ -61,7 +61,7 @@ class WebHookTransactionStrategy extends WebHookStrategyBase implements WebhookS
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrderIdByTransaction(Transaction $transaction): string
|
||||
public function getOrderIdByTransaction(Transaction $transaction): string|null
|
||||
{
|
||||
/** @var \VRPayment\Sdk\Model\Transaction $transaction */
|
||||
return $transaction->getMetaData()[TransactionPayload::VRPAYMENT_METADATA_ORDER_ID];
|
||||
@@ -116,10 +116,12 @@ class WebHookTransactionStrategy extends WebHookStrategyBase implements WebhookS
|
||||
/** @var \Shopware\Core\Checkout\Order\OrderEntity $order */
|
||||
$transaction = $this->getTransaction($request);
|
||||
$token = $transaction->getToken();
|
||||
$orderId = $transaction->getMetaData()[TransactionPayload::VRPAYMENT_METADATA_ORDER_ID];
|
||||
$orderId = $transaction->getMetaData()[TransactionPayload::VRPAYMENT_METADATA_ORDER_ID] ?? null;
|
||||
if (!empty($orderId) && !$transaction->getParent()) {
|
||||
$this->executeLocked($orderId, $context, function () use ($orderId, $transaction, $context, $request, $token) {
|
||||
$this->transactionService->upsert($transaction, $context);
|
||||
if ($this->allowUpsert($transaction, $orderId, $context)) {
|
||||
$this->transactionService->upsert($transaction, $context);
|
||||
}
|
||||
$orderTransactionId = $transaction->getMetaData()[TransactionPayload::VRPAYMENT_METADATA_ORDER_TRANSACTION_ID];
|
||||
$orderTransaction = $this->getOrderTransaction($orderId, $context);
|
||||
$this->logger->info("OrderId: {orderId} Current state: {state}", [
|
||||
@@ -178,4 +180,26 @@ class WebHookTransactionStrategy extends WebHookStrategyBase implements WebhookS
|
||||
|
||||
return new JsonResponse(['data' => $request->jsonSerialize()], $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the incoming transaction ID against the current transaction ID of the order.
|
||||
* If they don’t match, the saved transaction in the database remains unchanged.
|
||||
*
|
||||
* @param Transaction $transaction The transaction data retrieved from the portal.
|
||||
* @param string $orderId The order ID of the current transaction.
|
||||
* @param Context $context The operational context providing settings and environment for transaction processing.
|
||||
* @return bool Returns a value that determines whether to upsert the transaction into the database.
|
||||
*/
|
||||
private function allowUpsert(Transaction $transaction, string $orderId, Context $context): bool
|
||||
{
|
||||
try {
|
||||
$transactionEntity = $this->transactionService->getByOrderId($orderId, $context);
|
||||
if ($transactionEntity->getTransactionId() !== $transaction->getId()) {
|
||||
return false;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,5 +57,5 @@ interface WebhookStrategyActionsInterface {
|
||||
* @param Transaction|TransactionInvoiceState|Refund|mixed $transaction The transaction object from which the order ID should be extracted.
|
||||
* @return string The order ID as a string.
|
||||
*/
|
||||
public function getOrderIdByTransaction(Transaction $transaction): string;
|
||||
public function getOrderIdByTransaction(Transaction $transaction): string|null;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use Shopware\Core\{
|
||||
Framework\Struct\Struct,
|
||||
Framework\Validation\DataBag\RequestDataBag,
|
||||
System\StateMachine\Aggregation\StateMachineState\StateMachineStateEntity,
|
||||
System\SalesChannel\Context\SalesChannelContextService,
|
||||
System\SalesChannel\Context\SalesChannelContextServiceInterface,
|
||||
System\SalesChannel\Context\SalesChannelContextServiceParameters
|
||||
};
|
||||
use Shopware\Core\Framework\Util\Random;
|
||||
@@ -71,7 +71,7 @@ class VRPaymentPaymentHandler extends AbstractPaymentHandler
|
||||
*/
|
||||
private $orderTransactionStateHandler;
|
||||
|
||||
protected SalesChannelContextService $salesChannelContextService;
|
||||
protected SalesChannelContextServiceInterface $salesChannelContextService;
|
||||
|
||||
protected EntityRepository $orderTransactionRepository;
|
||||
|
||||
@@ -84,7 +84,7 @@ class VRPaymentPaymentHandler extends AbstractPaymentHandler
|
||||
CustomCartPersister $cartPersister,
|
||||
PluginTransactionService $pluginTransactionService,
|
||||
OrderTransactionStateHandler $orderTransactionStateHandler,
|
||||
SalesChannelContextService $salesChannelContextService,
|
||||
SalesChannelContextServiceInterface $salesChannelContextService,
|
||||
EntityRepository $orderTransactionRepository,
|
||||
?EntityRepository $subscriptionRepository,
|
||||
) {
|
||||
@@ -137,7 +137,7 @@ class VRPaymentPaymentHandler extends AbstractPaymentHandler
|
||||
}
|
||||
|
||||
$contextToken = $this->getContextToken($request);
|
||||
$parameters = new SalesChannelContextServiceParameters($salesChannelContextId, $contextToken, originalContext: $context);
|
||||
$parameters = new SalesChannelContextServiceParameters($salesChannelContextId, $contextToken, languageId: $context->getLanguageId(), originalContext: $context);
|
||||
|
||||
$salesChannelContext = $this->salesChannelContextService->get($parameters);
|
||||
$redirectUrl = $transaction->getReturnUrl();
|
||||
|
||||
@@ -76,7 +76,7 @@ class PaymentMethodRouteDecorator extends AbstractPaymentMethodRoute
|
||||
$response = $this->decorated->load($request, $context, $criteria);
|
||||
|
||||
$currentRoute = $request->attributes->get('_route');
|
||||
if ($currentRoute === 'frontend.checkout.finish.page') {
|
||||
if ($currentRoute === 'frontend.checkout.finish.page' || !$this->allowFilterPaymentMethods($request)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -100,4 +100,22 @@ class PaymentMethodRouteDecorator extends AbstractPaymentMethodRoute
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* We prevent filtering methods unless onlyAvailable is true.
|
||||
* This is because the filterPaymentMethods() function creates unnecessary pending transactions in the
|
||||
* portal when logged-in users navigate between pages.
|
||||
* The onlyAvailable flag applies rule-based filtering of payment methods and is usually true on checkout pages,
|
||||
* so we apply filterPaymentMethods() only when relevant.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
private function allowFilterPaymentMethods(Request $request): bool
|
||||
{
|
||||
if ($request->query->getBoolean('onlyAvailable') || $request->request->getBoolean('onlyAvailable')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use VRPaymentPayment\Core\Api\Transaction\Service\TransactionService;
|
||||
use VRPaymentPayment\Core\Settings\Options\Integration;
|
||||
use VRPaymentPayment\Core\Settings\Service\SettingsService;
|
||||
use VRPaymentPayment\Core\Checkout\Struct\PaymentConfigStruct;
|
||||
use VRPaymentPayment\Core\Util\LocaleCodeProvider;
|
||||
use VRPayment\Sdk\Model\TransactionState;
|
||||
|
||||
/**
|
||||
@@ -44,22 +45,30 @@ class PaymentIntegrationService
|
||||
*/
|
||||
private RouterInterface $router;
|
||||
|
||||
/**
|
||||
* @var LocaleCodeProvider
|
||||
*/
|
||||
private LocaleCodeProvider $localeCodeProvider;
|
||||
|
||||
/**
|
||||
* @param TransactionService $transactionService
|
||||
* @param SettingsService $settingsService
|
||||
* @param TransactionManagementService $transactionManagementService
|
||||
* @param RouterInterface $router
|
||||
* @param LocaleCodeProvider $localeCodeProvider
|
||||
*/
|
||||
public function __construct(
|
||||
TransactionService $transactionService,
|
||||
SettingsService $settingsService,
|
||||
TransactionManagementService $transactionManagementService,
|
||||
RouterInterface $router
|
||||
RouterInterface $router,
|
||||
LocaleCodeProvider $localeCodeProvider
|
||||
) {
|
||||
$this->transactionService = $transactionService;
|
||||
$this->settingsService = $settingsService;
|
||||
$this->transactionManagementService = $transactionManagementService;
|
||||
$this->router = $router;
|
||||
$this->localeCodeProvider = $localeCodeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +91,9 @@ class PaymentIntegrationService
|
||||
$transactionId
|
||||
);
|
||||
|
||||
$javascriptUrl = $this->getTransactionJavaScriptUrl($settings, $transactionId);
|
||||
$localeCode = $this->localeCodeProvider->getLocaleCodeFromContext($salesChannelContext->getContext());
|
||||
$paymentPageLocale = $this->localeCodeProvider->mapToPaymentPageLocale($localeCode);
|
||||
$javascriptUrl = $this->getTransactionJavaScriptUrl($settings, $transactionId, $paymentPageLocale);
|
||||
|
||||
$possiblePaymentMethods = $settings->getApiClient()
|
||||
->getTransactionService()
|
||||
@@ -161,9 +172,10 @@ class PaymentIntegrationService
|
||||
*
|
||||
* @param mixed $settings The plugin settings.
|
||||
* @param int $transactionId The transaction ID.
|
||||
* @param string $paymentPageLocale The payment page locale.
|
||||
* @return string The absolute URL to the JavaScript component.
|
||||
*/
|
||||
private function getTransactionJavaScriptUrl($settings, int $transactionId): string
|
||||
private function getTransactionJavaScriptUrl($settings, int $transactionId, string $paymentPageLocale = ''): string
|
||||
{
|
||||
$javascriptUrl = '';
|
||||
switch ($settings->getIntegration()) {
|
||||
@@ -176,6 +188,12 @@ class PaymentIntegrationService
|
||||
->javascriptUrl($settings->getSpaceId(), $transactionId);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($javascriptUrl && $paymentPageLocale) {
|
||||
$separator = str_contains($javascriptUrl, '?') ? '&' : '?';
|
||||
$javascriptUrl .= $separator . 'language=' . $paymentPageLocale;
|
||||
}
|
||||
|
||||
return $javascriptUrl;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,8 @@ declare(strict_types=1);
|
||||
namespace VRPaymentPayment\Core\Checkout\Service;
|
||||
|
||||
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\System\SalesChannel\SalesChannelContext;
|
||||
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
|
||||
use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;
|
||||
use VRPaymentPayment\Core\Api\PaymentMethodConfiguration\Service\PaymentMethodConfigurationService;
|
||||
use VRPaymentPayment\Core\Api\Transaction\Service\TransactionService;
|
||||
use VRPaymentPayment\Core\Checkout\PaymentHandler\VRPaymentPaymentHandler;
|
||||
@@ -50,12 +46,6 @@ class PaymentMethodFilterService
|
||||
*/
|
||||
private PaymentMethodUtil $paymentMethodUtil;
|
||||
|
||||
/**
|
||||
* @var EntityRepository
|
||||
* Repository for Shopware payment methods.
|
||||
*/
|
||||
private EntityRepository $paymentMethodRepository;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
@@ -77,15 +67,14 @@ class PaymentMethodFilterService
|
||||
* @param TransactionService $transactionService
|
||||
* @param PaymentMethodConfigurationService $paymentMethodConfigurationService
|
||||
* @param PaymentMethodUtil $paymentMethodUtil
|
||||
* @param EntityRepository $paymentMethodRepository
|
||||
* @param TransactionManagementService $transactionManagementService
|
||||
* @param CartService $cartService
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsService $settingsService,
|
||||
TransactionService $transactionService,
|
||||
PaymentMethodConfigurationService $paymentMethodConfigurationService,
|
||||
PaymentMethodUtil $paymentMethodUtil,
|
||||
EntityRepository $paymentMethodRepository,
|
||||
TransactionManagementService $transactionManagementService,
|
||||
CartService $cartService
|
||||
) {
|
||||
@@ -93,7 +82,6 @@ class PaymentMethodFilterService
|
||||
$this->transactionService = $transactionService;
|
||||
$this->paymentMethodConfigurationService = $paymentMethodConfigurationService;
|
||||
$this->paymentMethodUtil = $paymentMethodUtil;
|
||||
$this->paymentMethodRepository = $paymentMethodRepository;
|
||||
$this->transactionManagementService = $transactionManagementService;
|
||||
$this->cartService = $cartService;
|
||||
}
|
||||
@@ -208,8 +196,12 @@ class PaymentMethodFilterService
|
||||
/**
|
||||
* Builds a filtered PaymentMethodCollection based on allowed IDs.
|
||||
*
|
||||
* @param PaymentMethodCollection $paymentMethodCollection Original collection.
|
||||
* @param string[] $allowedIds List of allowed configuration IDs.
|
||||
* Filters the original collection (which already has Shopware's availability rules applied)
|
||||
* to only include WhitelabelMachineName methods that are also allowed by the API.
|
||||
* Non-WhitelabelMachineName methods are kept as-is.
|
||||
*
|
||||
* @param PaymentMethodCollection $paymentMethodCollection Original collection (already rule-filtered by Shopware).
|
||||
* @param string[] $allowedIds List of allowed configuration IDs from the WhitelabelMachineName API.
|
||||
* @param int $spaceId WhitelabelMachineName space ID.
|
||||
* @param SalesChannelContext $salesChannelContext The context.
|
||||
* @return PaymentMethodCollection The final collection.
|
||||
@@ -220,21 +212,12 @@ class PaymentMethodFilterService
|
||||
int $spaceId,
|
||||
SalesChannelContext $salesChannelContext
|
||||
): PaymentMethodCollection {
|
||||
$paymentIds = [];
|
||||
// Extract non-WhitelabelMachineName payment methods first.
|
||||
foreach ($paymentMethodCollection as $paymentMethodCollectionItem) {
|
||||
$isVRPaymentPM = VRPaymentPaymentHandler::class === $paymentMethodCollectionItem->getHandlerIdentifier();
|
||||
if (!$isVRPaymentPM) {
|
||||
$paymentIds[] = $paymentMethodCollectionItem->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$allowedWLMethods = [];
|
||||
// Fetch all WhitelabelMachineName payment method configurations for the space.
|
||||
$paymentMethodConfigurations = $this->paymentMethodConfigurationService
|
||||
->getAllPaymentMethodConfigurations($spaceId, $salesChannelContext->getContext());
|
||||
|
||||
// Check each configuration against the list of allowed IDs from WhitelabelMachineName API.
|
||||
// Build a map of Shopware payment method ID => configuration for methods allowed by the API.
|
||||
$allowedWLConfigByPmId = [];
|
||||
foreach ($paymentMethodConfigurations as $paymentMethodConfiguration) {
|
||||
if ($paymentMethodConfiguration->getPaymentMethod() === null) {
|
||||
continue;
|
||||
@@ -247,39 +230,31 @@ class PaymentMethodFilterService
|
||||
$paymentMethodConfiguration->getSpaceId() === $spaceId
|
||||
&& \in_array($pmConfigId, $allowedIds, true)
|
||||
) {
|
||||
$allowedWLMethods[] = $pmId;
|
||||
$allowedWLConfigByPmId[$pmId] = $paymentMethodConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
// Combine non-WhitelabelMachineName and allowed WhitelabelMachineName payment methods.
|
||||
$allPaymentIds = array_unique(array_merge($paymentIds, $allowedWLMethods));
|
||||
// Filter the original collection to preserve Shopware's availability rule filtering.
|
||||
// Non-WLM methods pass through unchanged; WLM methods are kept only if allowed by the API.
|
||||
$collection = new PaymentMethodCollection();
|
||||
foreach ($paymentMethodCollection as $method) {
|
||||
$isVRPaymentPM = VRPaymentPaymentHandler::class === $method->getHandlerIdentifier();
|
||||
|
||||
if (!empty($allPaymentIds)) {
|
||||
$criteria = new Criteria($allPaymentIds);
|
||||
$criteria->addFilter(new EqualsFilter('active', true));
|
||||
$criteria->addFilter(
|
||||
new EqualsFilter('salesChannels.id', $salesChannelContext->getSalesChannelId())
|
||||
);
|
||||
$criteria->addSorting(new FieldSorting('position', FieldSorting::ASCENDING));
|
||||
if (!$isVRPaymentPM) {
|
||||
$collection->add($method);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Re-fetch the entities to ensure we have valid objects with all associations.
|
||||
$result = $this->paymentMethodRepository->search($criteria, $salesChannelContext->getContext());
|
||||
/** @var \Shopware\Core\Checkout\Payment\PaymentMethodEntity $method */
|
||||
foreach ($result->getEntities() as $method) {
|
||||
if (!$collection->has((string)$method->getId())) {
|
||||
// Attach the configuration to the payment method as an extension for Twig access.
|
||||
foreach ($paymentMethodConfigurations as $paymentMethodConfiguration) {
|
||||
if ($paymentMethodConfiguration->getPaymentMethodId() === $method->getId()) {
|
||||
$method->addExtension('vrpayment_config', $paymentMethodConfiguration);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$collection->add($method);
|
||||
}
|
||||
if (isset($allowedWLConfigByPmId[$method->getId()])) {
|
||||
$method->addExtension('vrpayment_config', $allowedWLConfigByPmId[$method->getId()]);
|
||||
$collection->add($method);
|
||||
}
|
||||
}
|
||||
|
||||
$collection->sort(function ($a, $b) {
|
||||
return ($a->getPosition() ?? 0) <=> ($b->getPosition() ?? 0);
|
||||
});
|
||||
|
||||
return $collection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace VRPaymentPayment\Core\Storefront\Account\Controller;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Shopware\Core\{
|
||||
Checkout\Cart\Exception\CustomerNotLoggedInException,
|
||||
Checkout\Cart\CartException,
|
||||
Checkout\Customer\CustomerEntity,
|
||||
PlatformRequest,
|
||||
System\SalesChannel\SalesChannelContext
|
||||
@@ -133,14 +133,14 @@ class AccountOrderController extends StorefrontController
|
||||
* Helper to retrieve the currently logged-in customer.
|
||||
*
|
||||
* @return CustomerEntity
|
||||
* @throws CustomerNotLoggedInException
|
||||
* @throws CartException
|
||||
*/
|
||||
protected function getLoggedInCustomer(): CustomerEntity
|
||||
{
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
|
||||
if (!$request) {
|
||||
throw new CustomerNotLoggedInException();
|
||||
throw CartException::customerNotLoggedIn();
|
||||
}
|
||||
|
||||
/** @var SalesChannelContext|null $context */
|
||||
@@ -150,6 +150,6 @@ class AccountOrderController extends StorefrontController
|
||||
return $context->getCustomer();
|
||||
}
|
||||
|
||||
throw new CustomerNotLoggedInException();
|
||||
throw CartException::customerNotLoggedIn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Analytics {
|
||||
self::SHOP_SYSTEM => 'shopware',
|
||||
self::SHOP_SYSTEM_VERSION => '6',
|
||||
self::SHOP_SYSTEM_AND_VERSION => 'shopware-6',
|
||||
self::PLUGIN_SYSTEM_VERSION => '7.3.0',
|
||||
self::PLUGIN_SYSTEM_VERSION => '7.3.3',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
|
||||
namespace VRPaymentPayment\Core\Util\Exception;
|
||||
|
||||
class RefundNotSupportedException extends \LogicException{
|
||||
|
||||
}
|
||||
@@ -91,6 +91,26 @@ class LocaleCodeProvider {
|
||||
return $language->getLocale() ? $language->getLocale()->getCode() : $defaultLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a locale code to a VRPayment-supported payment page locale by matching the language prefix.
|
||||
* E.g. de-CH -> de-DE, fr-CH -> fr-FR, en-US -> en-GB, it-CH -> it-IT.
|
||||
*
|
||||
* @param string $localeCode
|
||||
* @return string
|
||||
*/
|
||||
public function mapToPaymentPageLocale(string $localeCode): string
|
||||
{
|
||||
$supportedLocales = [
|
||||
'de' => self::LOCALE_GERMANY_GERMAN,
|
||||
'fr' => self::LOCALE_FRANCE_FRENCH,
|
||||
'it' => self::LOCALE_ITALY_ITALIAN,
|
||||
'en' => self::LOCALE_GREAT_BRITAIN_ENGLISH,
|
||||
];
|
||||
|
||||
$languagePrefix = substr($localeCode, 0, 2);
|
||||
|
||||
return $supportedLocales[$languagePrefix] ?? self::LOCALE_GREAT_BRITAIN_ENGLISH;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Shopware\Core\Framework\Context $context
|
||||
|
||||
@@ -197,7 +197,7 @@ class TransactionPayload extends AbstractPayload
|
||||
'merchant_reference' => $this->fixLength($this->order->getOrderNumber(), 100),
|
||||
'meta_data' => [
|
||||
self::VRPAYMENT_METADATA_ORDER_ID => $this->order->getId(),
|
||||
self::VRPAYMENT_METADATA_ORDER_TRANSACTION_ID => $this->order->getTransactions()->first()->getId(),
|
||||
self::VRPAYMENT_METADATA_ORDER_TRANSACTION_ID => $this->transaction->getOrderTransactionId(),
|
||||
self::VRPAYMENT_METADATA_SALES_CHANNEL_ID => $this->salesChannelContext->getSalesChannel()->getId(),
|
||||
self::VRPAYMENT_METADATA_CUSTOMER_NAME => $customerName,
|
||||
],
|
||||
@@ -378,7 +378,7 @@ class TransactionPayload extends AbstractPayload
|
||||
$rate = $calculatedTax->getTaxRate();
|
||||
$amount = $this->calculateDiscountAmount($calculatedTax);
|
||||
|
||||
$lineItems[] = $this->createDiscountLineItem($discountName, $amount, $rate);
|
||||
$lineItems[] = $this->createDiscountLineItem($discountName, $amount, $rate, $discount->getId());
|
||||
}
|
||||
} else {
|
||||
$taxRules = $calculatedPrice->getTaxRules();
|
||||
@@ -387,12 +387,12 @@ class TransactionPayload extends AbstractPayload
|
||||
foreach ($taxRules as $taxRule) {
|
||||
$rate = $taxRule->getTaxRate();
|
||||
$amount = $calculatedPrice->getTotalPrice();
|
||||
$lineItems[] = $this->createDiscountLineItem($discountName, $amount, $rate);
|
||||
$lineItems[] = $this->createDiscountLineItem($discountName, $amount, $rate, $discount->getId());
|
||||
}
|
||||
} else {
|
||||
$rate = $this->getDefaultTaxRate();
|
||||
$amount = $calculatedPrice->getTotalPrice();
|
||||
$lineItems[] = $this->createDiscountLineItem($discountName, $amount, $rate);
|
||||
$lineItems[] = $this->createDiscountLineItem($discountName, $amount, $rate, $discount->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,7 +403,7 @@ class TransactionPayload extends AbstractPayload
|
||||
* @param float $rate
|
||||
* @return LineItemCreate
|
||||
*/
|
||||
private function createDiscountLineItem(string $discountName, float $amount, float $rate): LineItemCreate
|
||||
private function createDiscountLineItem(string $discountName, float $amount, float $rate, string $discountId): LineItemCreate
|
||||
{
|
||||
$lineItem = new LineItemCreate();
|
||||
|
||||
@@ -422,7 +422,7 @@ class TransactionPayload extends AbstractPayload
|
||||
->setShippingRequired(false)
|
||||
->setSku($discountSkuName, 200)
|
||||
->setType(LineItemType::DISCOUNT)
|
||||
->setUniqueId('coupon-' . $discountSkuName);
|
||||
->setUniqueId('coupon-' . $discountSkuName . '-' . $discountId);
|
||||
|
||||
$taxRate = new TaxCreate([
|
||||
'title' => 'Discount Tax: ' . $rate,
|
||||
|
||||
+3
@@ -79,6 +79,9 @@ Component.register('vrpayment-order-action-refund-by-amount', {
|
||||
case 'refundExceedsAmount':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messageRefundAmountExceedsAvailableBalance');
|
||||
break;
|
||||
case 'methodDoesNotSupportRefund':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messagePaymentMethodDoesNotSupportRefund');
|
||||
break;
|
||||
default:
|
||||
errorMessage = errorResponse.response.data.errors[0].detail;
|
||||
}
|
||||
|
||||
+11
-2
@@ -71,9 +71,18 @@ Component.register('vrpayment-order-action-refund-partial', {
|
||||
});
|
||||
}).catch((errorResponse) => {
|
||||
try {
|
||||
var errorTitle = errorResponse?.response?.data?.errors?.[0]?.title ?? this.$tc('vrpayment-order.refundAction.refundCreateError.errorTitle')
|
||||
var errorMessage;
|
||||
switch(errorResponse.response.data) {
|
||||
case 'methodDoesNotSupportRefund':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messagePaymentMethodDoesNotSupportRefund');
|
||||
break;
|
||||
default:
|
||||
errorMessage = errorResponse.response.data.errors[0].detail;
|
||||
}
|
||||
this.createNotificationError({
|
||||
title: errorResponse.response.data.errors[0].title,
|
||||
message: errorResponse.response.data.errors[0].detail,
|
||||
title: errorTitle,
|
||||
message: errorMessage,
|
||||
autoClose: false
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
+11
-2
@@ -70,9 +70,18 @@ Component.register('vrpayment-order-action-refund-selected', {
|
||||
});
|
||||
}).catch((errorResponse) => {
|
||||
try {
|
||||
var errorTitle = errorResponse?.response?.data?.errors?.[0]?.title ?? this.$tc('vrpayment-order.refundAction.refundCreateError.errorTitle')
|
||||
var errorMessage;
|
||||
switch(errorResponse.response.data) {
|
||||
case 'methodDoesNotSupportRefund':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messagePaymentMethodDoesNotSupportRefund');
|
||||
break;
|
||||
default:
|
||||
errorMessage = errorResponse.response.data.errors[0].detail;
|
||||
}
|
||||
this.createNotificationError({
|
||||
title: errorResponse.response.data.errors[0].title,
|
||||
message: errorResponse.response.data.errors[0].detail,
|
||||
title: errorTitle,
|
||||
message: errorMessage,
|
||||
autoClose: false
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
+3
@@ -77,6 +77,9 @@ Component.register('vrpayment-order-action-refund', {
|
||||
case 'refundExceedsQuantity':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messageRefundQuantityExceedsAvailableBalance');
|
||||
break;
|
||||
case 'methodDoesNotSupportRefund':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messagePaymentMethodDoesNotSupportRefund');
|
||||
break;
|
||||
default:
|
||||
errorMessage = errorResponse.response.data.errors[0].detail;
|
||||
}
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@
|
||||
<template #actions="{ item }">
|
||||
<sw-context-menu-item
|
||||
:disabled="transaction.state != 'FULFILL' || item.refundableQuantity != item.quantity || item.refundableAmount == 0 || item.itemRefundedAmount > 0 || item.itemRefundedQuantity > 0"
|
||||
@click="lineItemRefund(item.uniqueId)">
|
||||
@click="lineItemRefund(item.uniqueId, item.quantity)">
|
||||
{{ $tc('vrpayment-order.buttons.label.refund-whole-line-item') }}
|
||||
</sw-context-menu-item>
|
||||
|
||||
|
||||
+35
-13
@@ -332,12 +332,12 @@ Component.register('vrpayment-order-detail', {
|
||||
this.modalType = '';
|
||||
},
|
||||
|
||||
lineItemRefund(lineItemId) {
|
||||
lineItemRefund(lineItemId, itemQuantity) {
|
||||
this.isLoading = true;
|
||||
this.VRPaymentRefundService.createRefund(
|
||||
this.transactionData.transactions[0].metaData.salesChannelId,
|
||||
this.transactionData.transactions[0].id,
|
||||
0,
|
||||
itemQuantity,
|
||||
lineItemId
|
||||
).then(() => {
|
||||
this.createNotificationSuccess({
|
||||
@@ -351,9 +351,18 @@ Component.register('vrpayment-order-detail', {
|
||||
});
|
||||
}).catch((errorResponse) => {
|
||||
try {
|
||||
var errorTitle = errorResponse?.response?.data?.errors?.[0]?.title ?? this.$tc('vrpayment-order.refundAction.refundCreateError.errorTitle')
|
||||
var errorMessage;
|
||||
switch(errorResponse.response.data) {
|
||||
case 'methodDoesNotSupportRefund':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messagePaymentMethodDoesNotSupportRefund');
|
||||
break;
|
||||
default:
|
||||
errorMessage = errorResponse.response.data.errors[0].detail;
|
||||
}
|
||||
this.createNotificationError({
|
||||
title: errorResponse.response.data.errors[0].title,
|
||||
message: errorResponse.response.data.errors[0].detail,
|
||||
title: errorTitle,
|
||||
message: errorMessage,
|
||||
autoClose: false
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -385,7 +394,7 @@ Component.register('vrpayment-order-detail', {
|
||||
// Force the DOM to update before proceeding with the asynchronous operations
|
||||
this.$nextTick(() => {
|
||||
const refundPromises = this.selectedItems.map((item) => {
|
||||
return this.lineItemRefundBulk(item.uniqueId); // Simulated refund action with delay
|
||||
return this.lineItemRefundBulk(item.uniqueId, item.quantity); // Simulated refund action with delay
|
||||
});
|
||||
|
||||
// Wait for all refund promises to complete
|
||||
@@ -399,6 +408,10 @@ Component.register('vrpayment-order-detail', {
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error?.response?.data === 'methodDoesNotSupportRefund') {
|
||||
this.isLoading = false;
|
||||
return;
|
||||
}
|
||||
// Handle any errors during the refund process
|
||||
this.createNotificationError({
|
||||
title: 'Error',
|
||||
@@ -410,12 +423,12 @@ Component.register('vrpayment-order-detail', {
|
||||
});
|
||||
}
|
||||
},
|
||||
lineItemRefundBulk(lineItemId) {
|
||||
lineItemRefundBulk(lineItemId, itemQuantity) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.VRPaymentRefundService.createRefund(
|
||||
this.transactionData.transactions[0].metaData.salesChannelId,
|
||||
this.transactionData.transactions[0].id,
|
||||
0,
|
||||
itemQuantity,
|
||||
lineItemId
|
||||
)
|
||||
.then(() => {
|
||||
@@ -427,11 +440,20 @@ Component.register('vrpayment-order-detail', {
|
||||
})
|
||||
.catch((errorResponse) => {
|
||||
try {
|
||||
this.createNotificationError({
|
||||
title: errorResponse.response.data.errors[0].title,
|
||||
message: errorResponse.response.data.errors[0].detail,
|
||||
autoClose: false
|
||||
});
|
||||
var errorTitle = errorResponse?.response?.data?.errors?.[0]?.title ?? this.$tc('vrpayment-order.refundAction.refundCreateError.errorTitle')
|
||||
var errorMessage;
|
||||
switch(errorResponse.response.data) {
|
||||
case 'methodDoesNotSupportRefund':
|
||||
errorMessage = this.$tc('vrpayment-order.refundAction.refundCreateError.messagePaymentMethodDoesNotSupportRefund');
|
||||
break;
|
||||
default:
|
||||
errorMessage = errorResponse.response.data.errors[0].detail;
|
||||
}
|
||||
this.createNotificationError({
|
||||
title: errorTitle,
|
||||
message: errorMessage,
|
||||
autoClose: false
|
||||
});
|
||||
} catch (e) {
|
||||
this.createNotificationError({
|
||||
title: errorResponse.title,
|
||||
@@ -439,7 +461,7 @@ Component.register('vrpayment-order-detail', {
|
||||
autoClose: false
|
||||
});
|
||||
} finally {
|
||||
reject();
|
||||
reject(errorResponse);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
"messageRefundAmountExceedsAvailableBalance": "Der Rückerstattungsbetrag übersteigt das verfügbare Guthaben.",
|
||||
"messageRefundAmountIsZero": "Der Rückerstattungsbetrag muss größer als 0 sein.",
|
||||
"messageRefundQuantityExceedsAvailableBalance": "Rückerstattung nach Menge überschreitet die maximal verfügbare Anzahl an Artikeln zur Rückerstattung.",
|
||||
"messageRefundQuantityIsZero": "Rückerstattung nach Menge muss größer als 0 sein."
|
||||
"messageRefundQuantityIsZero": "Rückerstattung nach Menge muss größer als 0 sein.",
|
||||
"messagePaymentMethodDoesNotSupportRefund": "Die Zahlungsmethode unterstützt keine Online-Rückerstattungen."
|
||||
}
|
||||
},
|
||||
"transactionHistory": {
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
"messageRefundAmountExceedsAvailableBalance": "Refund amount exceeds available balance.",
|
||||
"messageRefundAmountIsZero": "Refund amount must be greater than 0.",
|
||||
"messageRefundQuantityExceedsAvailableBalance": "Refund by quantity exceeds maximum available items to refund.",
|
||||
"messageRefundQuantityIsZero": "Refund by quantity must be greater than 0."
|
||||
"messageRefundQuantityIsZero": "Refund by quantity must be greater than 0.",
|
||||
"messagePaymentMethodDoesNotSupportRefund": "Payment method does not support online refunds."
|
||||
}
|
||||
},
|
||||
"transactionHistory": {
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
"messageRefundAmountExceedsAvailableBalance": "Le montant du remboursement dépasse le solde disponible.",
|
||||
"messageRefundAmountIsZero": "Le montant du remboursement doit être supérieur à 0.",
|
||||
"messageRefundQuantityExceedsAvailableBalance": "Le remboursement par quantité dépasse le nombre maximal d’articles remboursables.",
|
||||
"messageRefundQuantityIsZero": "Le remboursement par quantité doit être supérieur à 0."
|
||||
"messageRefundQuantityIsZero": "Le remboursement par quantité doit être supérieur à 0.",
|
||||
"messagePaymentMethodDoesNotSupportRefund": "Le mode de paiement ne prend pas en charge les remboursements en ligne."
|
||||
}
|
||||
},
|
||||
"transactionHistory": {
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
"messageRefundAmountExceedsAvailableBalance": "LL'importo del rimborso supera il saldo disponibile.",
|
||||
"messageRefundAmountIsZero": "L'importo del rimborso deve essere superiore a 0.",
|
||||
"messageRefundQuantityExceedsAvailableBalance": "Il rimborso per quantità supera il numero massimo di articoli rimborsabili.",
|
||||
"messageRefundQuantityIsZero": "Il rimborso per quantità deve essere maggiore di 0."
|
||||
"messageRefundQuantityIsZero": "Il rimborso per quantità deve essere maggiore di 0.",
|
||||
"messagePaymentMethodDoesNotSupportRefund": "Il metodo di pagamento non supporta i rimborsi online."
|
||||
}
|
||||
},
|
||||
"transactionHistory": {
|
||||
|
||||
+5
-8
@@ -35,6 +35,7 @@
|
||||
|
||||
{% block vrpayment_settings_content_card_channel_config %}
|
||||
<sw-sales-channel-config v-model:value="config"
|
||||
v-model:selectedSalesChannelId="selectedSalesChannelId"
|
||||
ref="configComponent"
|
||||
:domain="CONFIG_DOMAIN">
|
||||
|
||||
@@ -45,14 +46,10 @@
|
||||
<mt-card title="Sales Channel Switch">
|
||||
|
||||
{% block vrpayment_settings_content_card_channel_config_sales_channel_card_title %}
|
||||
<sw-single-select
|
||||
:value="selectedSalesChannelId"
|
||||
:options="salesChannel.map(sc => ({ id: sc.id, name: sc.translated.name }))"
|
||||
labelProperty="name"
|
||||
valueProperty="id"
|
||||
:isLoading="isLoading"
|
||||
@update:value="onInput"
|
||||
/>
|
||||
<sw-sales-channel-switch
|
||||
ref="channelSwitch"
|
||||
@change-sales-channel-id="onSalesChannelSwitchChange($event, onInput)">
|
||||
</sw-sales-channel-switch>
|
||||
{% endblock %}
|
||||
{% block vrpayment_settings_content_card_channel_config_sales_channel_card_footer %}
|
||||
<template #footer>
|
||||
|
||||
+23
-5
@@ -41,6 +41,7 @@ Component.register('vrpayment-settings', {
|
||||
|
||||
isSetDefaultPaymentSuccessful: false,
|
||||
isSettingDefaultPaymentMethods: false,
|
||||
selectedSalesChannelId: null,
|
||||
|
||||
configIntegrationDefaultValue: 'payment_page',
|
||||
configEmailEnabledDefaultValue: true,
|
||||
@@ -70,7 +71,7 @@ Component.register('vrpayment-settings', {
|
||||
config: {
|
||||
handler(configData) {
|
||||
const defaultConfig = (this.$refs.configComponent.allConfigs || {}).null || {};
|
||||
const salesChannelId = this.$refs.configComponent.selectedSalesChannelId;
|
||||
const salesChannelId = this.selectedSalesChannelId;
|
||||
if (salesChannelId === null) {
|
||||
|
||||
this.applicationKeyFilled = !!this.config[this.CONFIG_APPLICATION_KEY];
|
||||
@@ -137,6 +138,16 @@ Component.register('vrpayment-settings', {
|
||||
this.$emit('update:value', configData);
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
selectedSalesChannelId: {
|
||||
handler(newValue) {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.channelSwitch) {
|
||||
this.$refs.channelSwitch.salesChannelId = newValue || '';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -198,7 +209,7 @@ Component.register('vrpayment-settings', {
|
||||
},
|
||||
|
||||
async validateHeadlessIntegration() {
|
||||
const salesChannelId = this.$refs.configComponent.selectedSalesChannelId;
|
||||
const salesChannelId = this.selectedSalesChannelId;
|
||||
const currentIntegration = this.config[this.CONFIG_INTEGRATION];
|
||||
|
||||
// If integration is 'payment_page', it is always valid.
|
||||
@@ -270,7 +281,7 @@ Component.register('vrpayment-settings', {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.VRPaymentConfigurationService.registerWebHooks(this.$refs.configComponent.selectedSalesChannelId)
|
||||
this.VRPaymentConfigurationService.registerWebHooks(this.selectedSalesChannelId)
|
||||
.then(() => {
|
||||
this.createNotificationSuccess({
|
||||
title: this.$tc('vrpayment-settings.settingForm.titleSuccess'),
|
||||
@@ -291,7 +302,7 @@ Component.register('vrpayment-settings', {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.VRPaymentConfigurationService.synchronizePaymentMethodConfiguration(this.$refs.configComponent.selectedSalesChannelId)
|
||||
this.VRPaymentConfigurationService.synchronizePaymentMethodConfiguration(this.selectedSalesChannelId)
|
||||
.then(() => {
|
||||
this.createNotificationSuccess({
|
||||
title: this.$tc('vrpayment-settings.settingForm.titleSuccess'),
|
||||
@@ -328,7 +339,7 @@ Component.register('vrpayment-settings', {
|
||||
onSetPaymentMethodDefault() {
|
||||
this.isSettingDefaultPaymentMethods = true;
|
||||
this.VRPaymentConfigurationService.setVRPaymentAsSalesChannelPaymentDefault(
|
||||
this.$refs.configComponent.selectedSalesChannelId
|
||||
this.selectedSalesChannelId
|
||||
).then(() => {
|
||||
this.isSettingDefaultPaymentMethods = false;
|
||||
this.isSetDefaultPaymentSuccessful = true;
|
||||
@@ -385,6 +396,13 @@ Component.register('vrpayment-settings', {
|
||||
});
|
||||
this.isTesting = false;
|
||||
});
|
||||
},
|
||||
|
||||
onSalesChannelSwitchChange(id, onInput) {
|
||||
this.selectedSalesChannelId = id;
|
||||
if (typeof onInput === 'function') {
|
||||
onInput(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -17,7 +17,6 @@
|
||||
<argument type="service" id="VRPaymentPayment\Core\Api\Transaction\Service\TransactionService"/>
|
||||
<argument type="service" id="VRPaymentPayment\Core\Api\PaymentMethodConfiguration\Service\PaymentMethodConfigurationService"/>
|
||||
<argument type="service" id="VRPaymentPayment\Core\Util\PaymentMethodUtil"/>
|
||||
<argument type="service" id="payment_method.repository"/>
|
||||
<argument type="service" id="VRPaymentPayment\Core\Checkout\Service\TransactionManagementService"/>
|
||||
<argument type="service" id="Shopware\Core\Checkout\Cart\SalesChannel\CartService"/>
|
||||
<call method="setLogger">
|
||||
@@ -30,6 +29,7 @@
|
||||
<argument type="service" id="VRPaymentPayment\Core\Settings\Service\SettingsService"/>
|
||||
<argument type="service" id="VRPaymentPayment\Core\Checkout\Service\TransactionManagementService"/>
|
||||
<argument type="service" id="router"/>
|
||||
<argument type="service" id="VRPaymentPayment\Core\Util\LocaleCodeProvider"/>
|
||||
</service>
|
||||
|
||||
<service id="VRPaymentPayment\Core\Checkout\Service\CartRecoveryService">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
],
|
||||
"dynamic": [],
|
||||
"js": [
|
||||
"/bundles/vrpaymentpayment/administration/assets/v-r-payment-payment-BV391wJu.js"
|
||||
"/bundles/vrpaymentpayment/administration/assets/v-r-payment-payment-CPfpiGQp.js"
|
||||
],
|
||||
"legacy": false,
|
||||
"preload": []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"main.js": {
|
||||
"file": "assets/v-r-payment-payment-BV391wJu.js",
|
||||
"file": "assets/v-r-payment-payment-CPfpiGQp.js",
|
||||
"name": "v-r-payment-payment",
|
||||
"src": "main.js",
|
||||
"isEntry": true,
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user