From f4704fbe648ebc28b86a43417933002fae22727b Mon Sep 17 00:00:00 2001 From: Patrick Weinstein Date: Tue, 17 Feb 2026 20:52:24 +0100 Subject: [PATCH] v6.5.2 --- CHANGELOG_de-DE.md | 8 + CHANGELOG_en-GB.md | 8 + composer.json | 2 +- .../CancelService/CancelService.php | 14 +- .../CancelService/CancelServiceInterface.php | 8 +- src/Components/ConfigReader/ConfigReader.php | 1 + .../PaymentActions/PaymentActionService.php | 309 ++++++++++++++++++ .../PaymentActions/Struct/RefundItem.php | 58 ++++ .../Struct/RefundItemCollection.php | 46 +++ .../UnzerWeroPaymentHandler.php | 3 +- .../PaymentResourceHydrator.php | 1 + .../UnzerUtil/UnzerTransactionUtil.php | 148 ++------- .../PaymentStatusWebhookHandler.php | 2 + .../UnzerPaymentConfigurationController.php | 5 +- .../UnzerPaymentTransactionController.php | 117 ++++++- .../ExpressButtonsEventListener.php | 31 +- .../StateMachine/TransitionEventListener.php | 24 +- .../page/unzer-payment-tab/index.js | 4 + .../unzer-payment-tab.html.twig | 9 +- .../js/unzer-payment6/unzer-payment6.js | 2 +- .../unzer-payment.express-buttons.plugin.js | 20 +- .../config/dependencies/controllers.xml | 1 + .../config/dependencies/event_listeners.xml | 3 +- .../config/dependencies/services.xml | 14 +- src/Resources/config/settings.xml | 11 + .../administration/js/unzer-payment6.js | 2 +- src/Resources/views/storefront/base.html.twig | 7 - .../page/checkout/confirm/index.html.twig | 1 - 28 files changed, 694 insertions(+), 165 deletions(-) create mode 100644 src/Components/PaymentActions/PaymentActionService.php create mode 100644 src/Components/PaymentActions/Struct/RefundItem.php create mode 100644 src/Components/PaymentActions/Struct/RefundItemCollection.php delete mode 100644 src/Resources/views/storefront/base.html.twig diff --git a/CHANGELOG_de-DE.md b/CHANGELOG_de-DE.md index b49499bd..807effa7 100644 --- a/CHANGELOG_de-DE.md +++ b/CHANGELOG_de-DE.md @@ -1,3 +1,11 @@ +# 6.5.2 +* Fehler behoben, bei dem die AGB nicht bis zum Akzeptieren-Häkchen gescrollt wurden +* Falsche UI-Komponente für B2B-Rechnung korrigiert +* Fehlerhafte Kundendaten für UPL behoben +* Fehlerbehebung für Apple Pay in Nicht-Safari-Browsern +* Apple-Pay-Button wird nun immer angezeigt, wenn Apple Pay aktiv ist +* Buchungsmodus-Fix für Wero + # 6.5.1 * Minor Fix am Customer-Objekt für besseren PayPal-B2B-Support diff --git a/CHANGELOG_en-GB.md b/CHANGELOG_en-GB.md index 776581c6..c3dce055 100644 --- a/CHANGELOG_en-GB.md +++ b/CHANGELOG_en-GB.md @@ -1,3 +1,11 @@ +# 6.5.2 +* Fix for Terms and Conditions no scroll to accept checkmark +* Fix incorrect UI Comp. for B2B invoice +* Fix for incorrect customer data for UPL +* Fix for Apple Pay in Non-Safari browsers +* Fix to always show Apple Pay button when Apple Pay is active +* Booking mode fix for Wero + # 6.5.1 * Minor fix to customer object for better Paypal B2B support diff --git a/composer.json b/composer.json index 124116b4..d37fa4bd 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "unzerdev/shopware6", "description": "Unzer payment integration for Shopware 6", - "version": "6.5.1", + "version": "6.5.2", "type": "shopware-platform-plugin", "license": "Apache-2.0", "minimum-stability": "dev", diff --git a/src/Components/CancelService/CancelService.php b/src/Components/CancelService/CancelService.php index f37e1723..df608534 100644 --- a/src/Components/CancelService/CancelService.php +++ b/src/Components/CancelService/CancelService.php @@ -23,7 +23,7 @@ class CancelService implements CancelServiceInterface { - private const PAYLATER_PAYMENT_METHODS = [ + public const PAYLATER_PAYMENT_METHODS = [ PaymentInstaller::PAYMENT_ID_PAYLATER_INVOICE, PaymentInstaller::PAYMENT_ID_PAYLATER_INSTALLMENT, PaymentInstaller::PAYMENT_ID_PAYLATER_DIRECT_DEBIT_SECURED, @@ -41,7 +41,7 @@ public function __construct( /** * {@inheritdoc} */ - public function cancelChargeById(string $orderTransactionId, string $chargeId, float $amountGross, ?string $reasonCode, Context $context): void + public function cancelChargeById(string $orderTransactionId, string $chargeId, float $amountGross, ?string $reasonCode, Context $context, string $referenceText = ''): Cancellation { $decimalPrecision = UnzerPayment6::MAX_DECIMAL_PRECISION; @@ -76,24 +76,26 @@ public function cancelChargeById(string $orderTransactionId, string $chargeId, f $payment = UnzerTransactionUtil::fetchPaymentFromOrderTransaction($transaction, $client); if ($this->isPaylaterPaymentMethod($transaction->getPaymentMethodId())) { $cancellation = new Cancellation($amountGross); + $cancellation->setPaymentReference($referenceText); - $client->cancelChargedPayment( + $responseCancellation = $client->cancelChargedPayment( $payment, $cancellation ); } else { - $client->cancelChargeById( + $responseCancellation = $client->cancelChargeById( $payment, $chargeId, $amountGross, $this->getCancelReasonCode($reasonCode), - '', + $referenceText, $amountNet, $amountVat ); } $this->updateOrderStatus($client, $transaction, $context); + return $responseCancellation; } /** @@ -139,7 +141,7 @@ protected function getCancelReasonCode(?string $reasonCode): string return $reasonCode ?? CancelReasonCodes::REASON_CODE_CANCEL; } - protected function isPaylaterPaymentMethod(string $paymentMethodId): bool + public function isPaylaterPaymentMethod(string $paymentMethodId): bool { return \in_array($paymentMethodId, self::PAYLATER_PAYMENT_METHODS, true); } diff --git a/src/Components/CancelService/CancelServiceInterface.php b/src/Components/CancelService/CancelServiceInterface.php index 98fe84af..ef20070c 100644 --- a/src/Components/CancelService/CancelServiceInterface.php +++ b/src/Components/CancelService/CancelServiceInterface.php @@ -6,6 +6,7 @@ use Shopware\Core\Framework\Context; use UnzerSDK\Exceptions\UnzerApiException; +use UnzerSDK\Resources\TransactionTypes\Cancellation; interface CancelServiceInterface { @@ -18,8 +19,9 @@ public function cancelChargeById( string $chargeId, float $amountGross, ?string $reasonCode, - Context $context - ): void; + Context $context, + string $referenceText = '' + ): Cancellation; /** * @throws UnzerApiException @@ -31,4 +33,6 @@ public function cancelAuthorizationById( float $amountGross, Context $context ): void; + + public function isPaylaterPaymentMethod(string $paymentMethodId): bool; } diff --git a/src/Components/ConfigReader/ConfigReader.php b/src/Components/ConfigReader/ConfigReader.php index 6a831557..31f60066 100644 --- a/src/Components/ConfigReader/ConfigReader.php +++ b/src/Components/ConfigReader/ConfigReader.php @@ -43,6 +43,7 @@ class ConfigReader implements ConfigReaderInterface public const CONFIG_KEY_PAYPAL_SHOW_SAVE_ACCOUNT = 'paypalShowSaveAccount'; public const CONFIG_KEY_DELIVERY_STATUS_FOR_CAPTURE = 'deliveryStatusForAutomaticCapture'; public const CONFIG_KEY_DELIVERY_STATUS_FOR_REFUND = 'deliveryStatusForAutomaticRefund'; + public const CONFIG_KEY_DELIVERY_STATUS_FOR_RETURNS_REFUND = 'deliveryStatusForAutomaticReturnsRefund'; public const CONFIG_KEY_USE_EXPRESS_PAYPAL = 'usePaypalExpress'; public const CONFIG_KEY_USE_EXPRESS_GOOGLE = 'useGooglePayExpress'; diff --git a/src/Components/PaymentActions/PaymentActionService.php b/src/Components/PaymentActions/PaymentActionService.php new file mode 100644 index 00000000..091ad4b8 --- /dev/null +++ b/src/Components/PaymentActions/PaymentActionService.php @@ -0,0 +1,309 @@ +logger->info('Capturing order', ['order' => $order->getId()]); + $orderTransaction = $this->unzerTransactionUtil->getOrderTransactionFromOrder($order, $context); + + if ($orderTransaction === null) { + return false; + } + + $client = $this->clientFactory->createClient(KeyPairContext::createFromOrderTransaction($orderTransaction)); + try { + $charge = $client->performChargeOnPayment($orderTransaction->getId(), new Charge($orderTransaction->getAmount()->getTotalPrice())); + $this->transactionStateHandler->transformTransactionState( + $orderTransaction->getId(), + $charge->getPayment(), + $context + ); + } catch (UnzerApiException $e) { + throw new \Exception($e->getMerchantMessage() ?: $e->getClientMessage()); + } + + return true; + } + + + + + /** + * @throws \Exception + */ + public function refundOrder(OrderEntity $order, Context $context): void + { + $this->logger->info('Refunding order', ['order' => $order->getId()]); + $orderTransaction = $this->unzerTransactionUtil->getOrderTransactionFromOrder($order, $context); + + if ($orderTransaction === null) { + return; + } + + $client = $this->clientFactory->createClient(KeyPairContext::createFromOrderTransaction($orderTransaction)); + try { + $payment = $client->fetchPayment($orderTransaction->getId()); + foreach ($payment->getCharges() as $charge) { + try { + if ($charge->isError()) { + continue; + } + $this->logger->info('Refunding charge', ['chargeId' => $charge->getId()]); + $this->cancelService->cancelChargeById( + $orderTransaction->getId(), + $charge->getId(), + $charge->getAmount() - $charge->getCancelledAmount(), + null, + $context + ); + } catch (Throwable $e) { + $this->logger->error('Error while refunding charge', ['charge' => $charge->getId(), 'error' => $e->getMessage()]); + } + } + $authorization = $payment->getAuthorization(); + if ($authorization !== null && !$authorization->isError()) { + try { + $this->logger->info('Refunding authorization', ['paymentId' => $payment->getId(), 'authorizationId' => $authorization->getId()]); + + $this->cancelService->cancelAuthorizationById( + $orderTransaction->getId(), + $payment->getId(), + $authorization->getAmount() - $authorization->getCancelledAmount(), + $context + ); + } catch (Throwable $e) { + $this->logger->error('Error while refunding authorization', ['authorization' => $authorization->getId(), 'error' => $e->getMessage()]); + } + } + $this->transactionStateHandler->transformTransactionState( + $orderTransaction->getId(), + $payment, + $context + ); + } catch (UnzerApiException $e) { + throw new \Exception($e->getMerchantMessage() ?: $e->getClientMessage()); + } + } + + + + public function executeReturnRefunds(OrderEntity $order, Context $context): void + { + $this->logger->info('Refunding order based on returns', ['order' => $order->getId()]); + + if($this->orderReturnRepository === null) { + $this->logger->warning('Returns repository does not exist'); + return; + } + + $orderTransaction = $this->unzerTransactionUtil->getOrderTransactionFromOrder($order, $context); + + if ($orderTransaction === null) { + return; + } + + $returnsToProcess = $this->getUnprocessedReturns($orderTransaction, $context); + + foreach($returnsToProcess as $returnEntity) { + $items = new RefundItemCollection(); + foreach ($returnEntity->getLineItems() as $lineItem) { + $refundItem = new RefundItem( + id: $lineItem->getOrderLineItemId(), + quantity: $lineItem->getQuantity(), + amount: $lineItem->getRefundAmount(), + resetStockQuantity: 0, + label: $lineItem->getLineItem()->getLabel(), + ); + $items->add($refundItem); + } + $cancellationId = $this->doUnifiedRefund( + orderTransaction: $orderTransaction, + amount: $returnEntity->getAmountTotal(), + context: $context, + items: $items, + comment: 'SW Auto Refund from order #'.$order->getOrderNumber().' return #'.$returnEntity->getReturnNumber(), + referenceText: $order->getOrderNumber().'/'.$returnEntity->getReturnNumber() + ); + + $transactionCustomFields = $orderTransaction->getCustomFields() ?? []; + if (!isset($transactionCustomFields['unzerRefundDetails']['processedReturns'])) { + $transactionCustomFields['unzerRefundDetails']['processedReturns'] = []; + } + $transactionCustomFields['unzerRefundDetails']['processedReturns'][$returnEntity->getId()] = $cancellationId; + + $this->unzerTransactionUtil->updateOrderTransaction([ + 'id' => $orderTransaction->getId(), + 'customFields' => $transactionCustomFields, + ], $context); + + $orderTransaction->setCustomFields($transactionCustomFields); + + $existingComment = $returnEntity->getInternalComment() ?? ''; + $refundNote = 'Unzer refund processed: ' . $cancellationId . ' (' . (new \DateTimeImmutable())->format('Y-m-d H:i:s') . ')'; + $newComment = $existingComment ? $existingComment . "\n\n" . $refundNote : $refundNote; + + $this->orderReturnRepository->update([ + [ + 'id' => $returnEntity->getId(), + 'internalComment' => $newComment, + ], + ], $context); + } + + } + + /** + * @return OrderReturnEntity[] + */ + protected function getUnprocessedReturns(OrderTransactionEntity $orderTransaction, Context $context): array + { + if ($this->orderReturnRepository === null) { + return []; + } + + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('orderId', $orderTransaction->getOrderId())); + $criteria->addAssociation('lineItems.lineItem.orderLineItem'); + + $returns = $this->orderReturnRepository->search($criteria, $context); + + $transactionCustomFields = $orderTransaction->getCustomFields() ?? []; + $processedReturns = $transactionCustomFields['unzerRefundDetails']['processedReturns'] ?? []; + + $unprocessedReturns = []; + + foreach ($returns as $return) { + if (isset($processedReturns[$return->getId()])) { + continue; + } + + $unprocessedReturns[] = $return; + } + + return $unprocessedReturns; + } + + public function doUnifiedRefund(OrderTransactionEntity $orderTransaction, float $amount, Context $context, ?RefundItemCollection $items = null, string $comment = '', string $referenceText = ''): string + { + $client = $this->clientFactory->createClient(KeyPairContext::createFromOrderTransaction($orderTransaction)); + $payment = UnzerTransactionUtil::fetchPaymentFromOrderTransaction($orderTransaction, $client); + $charges = $payment->getCharges(); + $charge = reset($charges);//TODO + + $cancellation = $this->cancelService->cancelChargeById($orderTransaction->getId(), $charge->getId(), $amount, null, $context, $referenceText); + + $transactionCustomFields = $orderTransaction->getCustomFields() ?? []; + if (!isset($transactionCustomFields['unzerRefundDetails'])) { + $transactionCustomFields['unzerRefundDetails'] = []; + } + + $transactionCustomFields['unzerRefundDetails'][$cancellation->getId()] = [ + 'items' => $items?$items->jsonSerialize():[], + 'comment' => $comment, + 'cancellation' => $cancellation->expose(), + ]; + + $this->unzerTransactionUtil->updateOrderTransaction([ + 'id' => $orderTransaction->getId(), + 'customFields' => $transactionCustomFields, + ], $context); + + $orderTransaction->setCustomFields($transactionCustomFields); + + if($items !== null && $items->count() > 0) { + $this->processRefundItems($items, $context); + } + + return $cancellation->getId(); + } + + + protected function processRefundItems(RefundItemCollection $items, Context $context) + { + foreach ($items->getElements() as $item) { + $lineItemId = $item->getId(); + $quantity = $item->getQuantity(); + $amount = $item->getAmount(); + $restockQuantity = $item->getResetStockQuantity(); + + if ($quantity <= 0 && $restockQuantity <= 0) { + continue; + } + + /** @var OrderLineItemEntity $lineItem */ + $lineItem = $this->orderLineItemRepository->search(new Criteria([$lineItemId]), $context)->first(); + + if ($lineItem === null) { + continue; + } + + if ($restockQuantity > 0 && $lineItem->getProductId()) { + /** @var ProductEntity $product */ + $product = $this->productRepository->search(new Criteria([$lineItem->getProductId()]), $context)->first(); + if ($product !== null) { + $updatePayload = [ + 'id' => $product->getId(), + 'quantity' => $product->getStock() + $restockQuantity, + ]; + $this->productRepository->update([$updatePayload], $context); + } + } + if ($quantity > 0) { + $customFields = $lineItem->getCustomFields(); + if (!is_array($customFields)) { + $customFields = []; + } + + $customFields['unzerRefundedQuantity'] = ($customFields['unzerRefundedQuantity'] ?? 0) + $quantity; + $customFields['unzerRefundedAmount'] = ($customFields['unzerRefundedAmount'] ?? 0) + $amount; + $updatePayload = [ + 'id' => $lineItem->getId(), + 'customFields' => $customFields, + ]; + $this->orderLineItemRepository->update([$updatePayload], $context); + } + } + } +} \ No newline at end of file diff --git a/src/Components/PaymentActions/Struct/RefundItem.php b/src/Components/PaymentActions/Struct/RefundItem.php new file mode 100644 index 00000000..5eabc68f --- /dev/null +++ b/src/Components/PaymentActions/Struct/RefundItem.php @@ -0,0 +1,58 @@ +id; + } + + public function getQuantity(): int + { + return $this->quantity; + } + + public function getAmount(): float + { + return $this->amount; + } + + public function getResetStockQuantity(): int + { + return $this->resetStockQuantity; + } + + public function getLabel(): ?string + { + return $this->label; + } +} \ No newline at end of file diff --git a/src/Components/PaymentActions/Struct/RefundItemCollection.php b/src/Components/PaymentActions/Struct/RefundItemCollection.php new file mode 100644 index 00000000..1d930213 --- /dev/null +++ b/src/Components/PaymentActions/Struct/RefundItemCollection.php @@ -0,0 +1,46 @@ + + * + * @method void add(RefundItem $entity) + * @method void set(string $key, RefundItem $entity) + * @method RefundItem[] getIterator() + * @method RefundItem[] getElements() + * @method RefundItem|null get(string $key) + * @method RefundItem|null first() + * @method RefundItem|null last() + */ +class RefundItemCollection extends Collection +{ + public static function fromArray(array $items): self + { + $collection = new self(); + + foreach ($items as $item) { + $collection->add(RefundItem::fromArray($item)); + } + + return $collection; + } + + public function jsonSerialize():array + { + $return = []; + foreach ($this->getElements() as $item) { + $return[] = $item->jsonSerialize(); + } + return $return; + } + + protected function getExpectedClass(): ?string + { + return RefundItem::class; + } +} \ No newline at end of file diff --git a/src/Components/PaymentHandler/UnzerWeroPaymentHandler.php b/src/Components/PaymentHandler/UnzerWeroPaymentHandler.php index cd6361f2..c80da54d 100644 --- a/src/Components/PaymentHandler/UnzerWeroPaymentHandler.php +++ b/src/Components/PaymentHandler/UnzerWeroPaymentHandler.php @@ -20,6 +20,7 @@ protected function getUnzerPaymentTypeObject(): Wero protected function setBookingMode(): void { - $this->bookingMode = $this->pluginConfig->get(ConfigReader::CONFIG_KEY_BOOKING_MODE_WERO, BookingMode::CHARGE); + $this->bookingMode = BookingMode::CHARGE; + #$this->bookingMode = $this->pluginConfig->get(ConfigReader::CONFIG_KEY_BOOKING_MODE_WERO, BookingMode::CHARGE); } } diff --git a/src/Components/ResourceHydrator/PaymentResourceHydrator/PaymentResourceHydrator.php b/src/Components/ResourceHydrator/PaymentResourceHydrator/PaymentResourceHydrator.php index ab40ab3e..36778c24 100644 --- a/src/Components/ResourceHydrator/PaymentResourceHydrator/PaymentResourceHydrator.php +++ b/src/Components/ResourceHydrator/PaymentResourceHydrator/PaymentResourceHydrator.php @@ -370,6 +370,7 @@ protected function hydrateTransactionItem(AbstractTransactionType $item, string return [ 'id' => $item->getId(), 'shortId' => $item->getShortId(), + 'reference'=>method_exists($item, 'getPaymentReference')?$item->getPaymentReference():'', 'state' => $state, 'date' => $item->getDate(), 'type' => $type, diff --git a/src/Components/UnzerUtil/UnzerTransactionUtil.php b/src/Components/UnzerUtil/UnzerTransactionUtil.php index 1a83bba1..9efdcf88 100644 --- a/src/Components/UnzerUtil/UnzerTransactionUtil.php +++ b/src/Components/UnzerUtil/UnzerTransactionUtil.php @@ -10,44 +10,42 @@ use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter; -use UnzerPayment6\Components\CancelService\CancelServiceInterface; -use UnzerPayment6\Components\ClientFactory\ClientFactoryInterface; -use UnzerPayment6\Components\Struct\KeyPairContext; +use Throwable; use UnzerPayment6\Components\TransactionStateHandler\TransactionStateHandlerInterface; use UnzerPayment6\Installer\CustomFieldInstaller; use UnzerPayment6\Installer\PaymentInstaller; use UnzerSDK\Exceptions\UnzerApiException; use UnzerSDK\Resources\Payment; -use UnzerSDK\Resources\TransactionTypes\Charge; use UnzerSDK\Unzer; readonly class UnzerTransactionUtil { + public const ORDER_TRANSACTION_ASSOCIATIONS = [ + 'order', + 'order.billingAddress.country', + 'order.currency', + 'order.documents.documentType', + 'paymentMethod', + 'order.orderCustomer.customer', + 'order.deliveries.shippingMethod.translated', + 'order.deliveries.shippingOrderAddress.country', + 'order.lineItems.product.manufacturer', + 'order.lineItems.cover.url', + 'order.lineItems.calculatedPrices.taxes', + ]; + public function __construct( - protected EntityRepository $orderTransactionRepository, - protected ClientFactoryInterface $clientFactory, + protected EntityRepository $orderTransactionRepository, protected TransactionStateHandlerInterface $transactionStateHandler, - protected CancelServiceInterface $cancelService, - protected LoggerInterface $logger - ) { + protected LoggerInterface $logger, + ) + { } public function getOrderTransaction(string $orderTransactionId, Context $context): ?OrderTransactionEntity { $criteria = new Criteria([$orderTransactionId]); - $criteria->addAssociations([ - 'order', - 'order.billingAddress.country', - 'order.currency', - 'order.documents.documentType', - 'paymentMethod', - 'order.orderCustomer.customer', - 'order.deliveries.shippingMethod.translated', - 'order.deliveries.shippingOrderAddress.country', - 'order.lineItems.product.manufacturer', - 'order.lineItems.cover.url', - 'order.lineItems.calculatedPrices.taxes', - ]); + $criteria->addAssociations(self::ORDER_TRANSACTION_ASSOCIATIONS); return $this->orderTransactionRepository->search($criteria, $context)->first(); } @@ -60,101 +58,21 @@ public function getOrderTransactionFromOrder(OrderEntity $orderEntity, Context $ $criteria = new Criteria(); $criteria->addFilter(new EqualsFilter('orderId', $orderEntity->getId())); $criteria->addFilter(new EqualsAnyFilter('paymentMethodId', PaymentInstaller::PAYMENT_METHOD_IDS)); - $criteria->addAssociations([ - 'order', - 'order.billingAddress', - 'order.currency', - 'order.documents', - 'order.documents.documentType', - 'paymentMethod', - ]); + $criteria->addAssociations(self::ORDER_TRANSACTION_ASSOCIATIONS); - return $this->orderTransactionRepository->search($criteria, $context)->first(); + return $this->orderTransactionRepository->search($criteria, $context)->last(); } - /** - * @throws \Exception - */ - public function captureOrder(OrderEntity $order, Context $context): bool + public function getOrderTransactionFromOrderNumber(string $orderNumber, Context $context): ?OrderTransactionEntity { - $this->logger->info('Capturing order', ['order' => $order->getId()]); - $orderTransaction = $this->getOrderTransactionFromOrder($order, $context); - - if ($orderTransaction === null) { - return false; - } - - $client = $this->clientFactory->createClient(KeyPairContext::createFromOrderTransaction($orderTransaction)); - try { - $charge = $client->performChargeOnPayment($orderTransaction->getId(), new Charge($orderTransaction->getAmount()->getTotalPrice())); - $this->transactionStateHandler->transformTransactionState( - $orderTransaction->getId(), - $charge->getPayment(), - $context - ); - } catch (UnzerApiException $e) { - throw new \Exception($e->getMerchantMessage() ?: $e->getClientMessage()); - } + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('order.orderNumber', $orderNumber)); + $criteria->addFilter(new EqualsAnyFilter('paymentMethodId', PaymentInstaller::PAYMENT_METHOD_IDS)); + $criteria->addAssociations(self::ORDER_TRANSACTION_ASSOCIATIONS); - return true; + return $this->orderTransactionRepository->search($criteria, $context)->last(); } - /** - * @throws \Exception - */ - public function refundOrder(OrderEntity $order, Context $context): void - { - $this->logger->info('Refunding order', ['order' => $order->getId()]); - $orderTransaction = $this->getOrderTransactionFromOrder($order, $context); - - if ($orderTransaction === null) { - return; - } - - $client = $this->clientFactory->createClient(KeyPairContext::createFromOrderTransaction($orderTransaction)); - try { - $payment = $client->fetchPayment($orderTransaction->getId()); - foreach ($payment->getCharges() as $charge) { - try { - if ($charge->isError()) { - continue; - } - $this->logger->info('Refunding charge', ['chargeId' => $charge->getId()]); - $this->cancelService->cancelChargeById( - $orderTransaction->getId(), - $charge->getId(), - $charge->getAmount() - $charge->getCancelledAmount(), - null, - $context - ); - } catch (\Throwable $e) { - $this->logger->error('Error while refunding charge', ['charge' => $charge->getId(), 'error' => $e->getMessage()]); - } - } - $authorization = $payment->getAuthorization(); - if ($authorization !== null && !$authorization->isError()) { - try { - $this->logger->info('Refunding authorization', ['paymentId' => $payment->getId(), 'authorizationId' => $authorization->getId()]); - - $this->cancelService->cancelAuthorizationById( - $orderTransaction->getId(), - $payment->getId(), - $authorization->getAmount() - $authorization->getCancelledAmount(), - $context - ); - } catch (\Throwable $e) { - $this->logger->error('Error while refunding authorization', ['authorization' => $authorization->getId(), 'error' => $e->getMessage()]); - } - } - $this->transactionStateHandler->transformTransactionState( - $orderTransaction->getId(), - $payment, - $context - ); - } catch (UnzerApiException $e) { - throw new \Exception($e->getMerchantMessage() ?: $e->getClientMessage()); - } - } public static function fetchPaymentFromOrderTransaction(OrderTransactionEntity $orderTransaction, Unzer $client): Payment { @@ -183,9 +101,15 @@ public function updateOrderTransactionStatus(Unzer $client, OrderTransactionEnti $payment, $context ); - } catch (\Throwable $e) { - $this->logger->error('error updating transaction state from util: ' . $e->getMessage(), ['trace'=>$e->getTraceAsString()]); + } catch (Throwable $e) { + $this->logger->error('error updating transaction state from util: ' . $e->getMessage(), ['trace' => $e->getTraceAsString()]); } } + public function updateOrderTransaction(array $data, Context $context): void + { + $this->orderTransactionRepository->update([$data], $context); + } + + } diff --git a/src/Components/WebhookHandler/PaymentStatusWebhookHandler.php b/src/Components/WebhookHandler/PaymentStatusWebhookHandler.php index e4b4c420..fc4a4698 100644 --- a/src/Components/WebhookHandler/PaymentStatusWebhookHandler.php +++ b/src/Components/WebhookHandler/PaymentStatusWebhookHandler.php @@ -54,6 +54,8 @@ public function execute(Webhook $webhook, SalesChannelContext $context): void $transaction = $this->getOrderTransaction($payment->getOrderId(), $context->getContext()); + $context->getContext()->assign(['languageIdChain' => [$transaction->getOrder()->getLanguageId()]]); + if ($transaction === null) { $this->logger->error( \sprintf( diff --git a/src/Controllers/Administration/UnzerPaymentConfigurationController.php b/src/Controllers/Administration/UnzerPaymentConfigurationController.php index cae8fda8..7388f8c8 100644 --- a/src/Controllers/Administration/UnzerPaymentConfigurationController.php +++ b/src/Controllers/Administration/UnzerPaymentConfigurationController.php @@ -9,6 +9,7 @@ use Shopware\Core\Framework\Validation\DataBag\RequestDataBag; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use UnzerPayment6\Components\ClientFactory\ClientFactoryInterface; @@ -59,10 +60,10 @@ public function validateCredentials(RequestDataBag $dataBag): JsonResponse } #[Route(path: '/api/_action/unzer-payment/get-google-pay-gateway-merchant-id', name: 'api.action.unzer.get.google.pay.gateway.merchant.id', methods: ['GET'])] - public function getGooglePayGatewayMerchantId(RequestDataBag $dataBag): JsonResponse + public function getGooglePayGatewayMerchantId(Request $request): JsonResponse { try { - $salesChannelId = $dataBag->get('salesChannelId', ''); + $salesChannelId = $request->get('salesChannelId', ''); /** @var ConfigReader $configReader */ $configReader = $this->container->get(ConfigReader::class); diff --git a/src/Controllers/Administration/UnzerPaymentTransactionController.php b/src/Controllers/Administration/UnzerPaymentTransactionController.php index 1e11235a..4fd12edd 100644 --- a/src/Controllers/Administration/UnzerPaymentTransactionController.php +++ b/src/Controllers/Administration/UnzerPaymentTransactionController.php @@ -11,11 +11,14 @@ use Shopware\Core\Framework\Context; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use UnzerPayment6\Components\BasketConverter\BasketConverterInterface; use UnzerPayment6\Components\CancelService\CancelServiceInterface; use UnzerPayment6\Components\ClientFactory\ClientFactoryInterface; +use UnzerPayment6\Components\PaymentActions\PaymentActionService; +use UnzerPayment6\Components\PaymentActions\Struct\RefundItemCollection; use UnzerPayment6\Components\ResourceHydrator\PaymentResourceHydrator\PaymentResourceHydratorInterface; use UnzerPayment6\Components\ShipService\ShipServiceInterface; use UnzerPayment6\Components\Struct\KeyPairContext; @@ -28,14 +31,16 @@ class UnzerPaymentTransactionController extends AbstractController { public function __construct( - private readonly ClientFactoryInterface $clientFactory, - private readonly UnzerTransactionUtil $unzerTransactionUtil, + private readonly ClientFactoryInterface $clientFactory, + private readonly UnzerTransactionUtil $unzerTransactionUtil, + private readonly PaymentActionService $paymentTransactionService, private readonly PaymentResourceHydratorInterface $hydrator, - private readonly CancelServiceInterface $cancelService, - private readonly ShipServiceInterface $shipService, - private readonly BasketConverterInterface $basketConverter, - private readonly LoggerInterface $logger - ) { + private readonly CancelServiceInterface $cancelService, + private readonly ShipServiceInterface $shipService, + private readonly BasketConverterInterface $basketConverter, + private readonly LoggerInterface $logger + ) + { } #[Route(path: '/api/_action/unzer-payment/transaction/{orderTransactionId}/details', name: 'api.action.unzer.transaction.details', methods: ['GET'])] @@ -65,6 +70,60 @@ public function fetchTransactionDetails(string $orderTransactionId, Context $con return new JsonResponse($data); } + #[Route(path: '/api/_action/unzer-payment/transaction/{orderTransactionId}/refund-information', name: 'api.action.unzer.transaction.refund-information', methods: ['GET'])] + public function fetchTransactionRefundInformation(string $orderTransactionId, Context $context): JsonResponse + { + $transaction = $this->getOrderTransaction($orderTransactionId, $context); + + if ($transaction === null || $transaction->getOrder() === null) { + throw PaymentException::invalidTransaction($orderTransactionId); + } + + $client = $this->clientFactory->createClient(KeyPairContext::createFromOrderTransaction($transaction)); + + try { + $payment = UnzerTransactionUtil::fetchPaymentFromOrderTransaction($transaction, $client); + + + //TODO: kill the overhead + $data = $this->hydrator->hydrateArray($payment, $transaction, $client); + $transactions = $data['transactions']; + $refunds = array_filter($transactions, function (array $transaction) { + return $transaction['type'] === 'cancellation'; + }); + + foreach ($refunds as &$refund) { + if (isset($transaction->getCustomFields()['unzerRefundDetails'][$refund['id']])) { + $refund['details'] = $transaction->getCustomFields()['unzerRefundDetails'][$refund['id']]; + } + } + + $amounts = []; + $charges = $payment->getCharges(); + // TODO: currently the unified refunds run on the first charge only + /** @var Charge $charge */ + $charge = reset($charges);//TODO + if ($charge) { + $amounts['charged'] = $charge->isSuccess() ? $charge->getAmount() : 0; + if ($this->cancelService->isPaylaterPaymentMethod($transaction->getPaymentMethodId())) { + $amounts['cancelled'] = $payment->getAmount()->getCanceled(); + } else { + $amounts['cancelled'] = $charge->getCancelledAmount(); + } + $amounts['remaining'] = max(0, $amounts['charged'] - $amounts['cancelled']); + } + } catch (UnzerApiException|\Throwable $exception) { + $exceptionReturnValues = $this->handleException($exception, \sprintf('Error while executing fetching transaction details for order transaction [%s]: %s', $orderTransactionId, $exception->getMessage())); + + return new JsonResponse($exceptionReturnValues[0], $exceptionReturnValues[1]); + } + + return new JsonResponse([ + 'refunds' => $refunds, + 'amounts' => $amounts, + ]); + } + // TODO: evaluate if GET is the correct method here #[Route(path: '/api/_action/unzer-payment/transaction/{orderTransactionId}/charge/{amount}', name: 'api.action.unzer.transaction.charge', methods: ['GET'])] public function chargeTransaction(string $orderTransactionId, float $amount, Context $context): JsonResponse @@ -115,6 +174,46 @@ public function refundTransaction(string $orderTransactionId, string $chargeId, return new JsonResponse(['status' => true]); } + #[Route(path: '/api/_action/unzer-payment/transaction/refund', name: 'api.action.unzer.transaction.unified-refund', methods: ['POST'])] + public function unifiedRefund(Request $request, Context $context): JsonResponse + { + try { + if ($request->get('orderTransactionId')) { + $orderTransaction = $this->unzerTransactionUtil->getOrderTransaction($request->get('orderTransactionId'), $context); + } elseif ($request->get('orderNumber')) { + $orderTransaction = $this->unzerTransactionUtil->getOrderTransactionFromOrderNumber($request->get('orderNumber'), $context); + } + + if (empty($orderTransaction)) { + throw new \Exception('no order transaction found for request'); + } + } catch (\Throwable $exception) { + $exceptionReturnValues = $this->handleException($exception, 'no order transaction found for unifiedRefund', $exception->getMessage()); + return new JsonResponse($exceptionReturnValues[0], $exceptionReturnValues[1]); + } + + $amount = (float)$request->get('amount', 0); + $referenceText = (string)$request->get('referenceText', ''); + $items = RefundItemCollection::fromArray((array)$request->get('items', [])); + $comment = (string)$request->get('comment', ''); + + try { + $this->paymentTransactionService->doUnifiedRefund( + orderTransaction: $orderTransaction, + amount: $amount, + context: $context, + items: $items, + comment: $comment, + referenceText: $referenceText + ); + } catch (UnzerApiException|\Throwable $exception) { + $exceptionReturnValues = $this->handleException($exception, \sprintf('Error while executing refund transaction for order transaction [%s]: %s', $orderTransaction->getId(), $exception->getMessage())); + return new JsonResponse($exceptionReturnValues[0], $exceptionReturnValues[1]); + } + + return new JsonResponse(['success' => true]); + } + // TODO: evaluate if GET is the correct method here #[Route(path: '/api/_action/unzer-payment/transaction/{orderTransactionId}/cancel/{authorizationId}/{amount}', name: 'api.action.unzer.transaction.cancel', methods: ['GET'])] public function cancelTransaction(string $orderTransactionId, string $authorizationId, float $amount, Context $context): JsonResponse @@ -154,7 +253,8 @@ protected function handleException(\Throwable|UnzerApiException $exception, stri return [ [ 'status' => false, - 'errors' => [$exception instanceof UnzerApiException ? $exception->getMerchantMessage() : 'generic-error'], + 'success' => false, + 'errors' => [$exception instanceof UnzerApiException ? $exception->getMerchantMessage() : $exception->getMessage()], ], Response::HTTP_BAD_REQUEST, ]; @@ -189,4 +289,5 @@ private function getInvoiceNumber(OrderTransactionEntity $transaction): ?string return $invoiceNumber; } + } diff --git a/src/EventListeners/ExpressButtons/ExpressButtonsEventListener.php b/src/EventListeners/ExpressButtons/ExpressButtonsEventListener.php index 280c61c6..479f45f8 100644 --- a/src/EventListeners/ExpressButtons/ExpressButtonsEventListener.php +++ b/src/EventListeners/ExpressButtons/ExpressButtonsEventListener.php @@ -4,7 +4,12 @@ namespace UnzerPayment6\EventListeners\ExpressButtons; +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\Framework\Struct\ArrayStruct; +use Shopware\Core\System\SalesChannel\SalesChannelContext; use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent; use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent; use Shopware\Storefront\Page\PageLoadedEvent; @@ -14,12 +19,14 @@ use UnzerPayment6\Components\Storefront\ExtensionFactory; use UnzerPayment6\Components\Struct\PageExtension\Checkout\Confirm\ApplePayV2PageExtension; use UnzerPayment6\Components\Struct\PageExtension\Checkout\Confirm\GooglePayPageExtension; +use UnzerPayment6\Installer\PaymentInstaller; class ExpressButtonsEventListener implements EventSubscriberInterface { public function __construct( private ConfigReaderInterface $configReader, private ExtensionFactory $extensionFactory, + private EntityRepository $salesChannelRepository ) { } @@ -43,9 +50,9 @@ public function addExpressButtons(PageLoadedEvent $event): void $event->getPage()->addExtension('UnzerExpressButtons', new ArrayStruct([ 'publicKey' => $config->get(ConfigReader::CONFIG_KEY_PUBLIC_KEY), - 'usePaypal' => $config->get(ConfigReader::CONFIG_KEY_USE_EXPRESS_PAYPAL), - 'useGooglePay' => $config->get(ConfigReader::CONFIG_KEY_USE_EXPRESS_GOOGLE), - 'useApplePay' => $config->get(ConfigReader::CONFIG_KEY_USE_EXPRESS_APPLEPAY), + 'usePaypal' => $config->get(ConfigReader::CONFIG_KEY_USE_EXPRESS_PAYPAL) && $this->isPaymentMethodActive(PaymentInstaller::PAYMENT_ID_PAYPAL, $event->getSalesChannelContext()), + 'useGooglePay' => $config->get(ConfigReader::CONFIG_KEY_USE_EXPRESS_GOOGLE) && $this->isPaymentMethodActive(PaymentInstaller::PAYMENT_ID_GOOGLE_PAY, $event->getSalesChannelContext()), + 'useApplePay' => $config->get(ConfigReader::CONFIG_KEY_USE_EXPRESS_APPLEPAY) && $this->isPaymentMethodActive(PaymentInstaller::PAYMENT_ID_APPLE_PAY_V2, $event->getSalesChannelContext()), ])); $googlePayExtension = $this->extensionFactory->getGooglePayExtension($event->getSalesChannelContext()->getSalesChannelId()); $event->getPage()->addExtension(GooglePayPageExtension::EXTENSION_NAME, $googlePayExtension); @@ -53,4 +60,22 @@ public function addExpressButtons(PageLoadedEvent $event): void $applePayExtension = $this->extensionFactory->getApplePayExtension($event->getSalesChannelContext()->getSalesChannelId()); $event->getPage()->addExtension(ApplePayV2PageExtension::EXTENSION_NAME, $applePayExtension); } + + public function isPaymentMethodActive(string $paymentMethodId, SalesChannelContext $context): bool + { + $criteria = new Criteria(); + $criteria->setLimit(1); + $criteria->addFilter( + new MultiFilter( + MultiFilter::CONNECTION_AND, + [ + new EqualsFilter('id', $context->getSalesChannel()->getId()), + new EqualsFilter('paymentMethods.id', $paymentMethodId), + new EqualsFilter('paymentMethods.active', true), + ] + ) + ); + + return $this->salesChannelRepository->searchIds($criteria, $context->getContext())->firstId() !== null; + } } diff --git a/src/EventListeners/StateMachine/TransitionEventListener.php b/src/EventListeners/StateMachine/TransitionEventListener.php index ddc2277f..8659dd87 100644 --- a/src/EventListeners/StateMachine/TransitionEventListener.php +++ b/src/EventListeners/StateMachine/TransitionEventListener.php @@ -20,6 +20,7 @@ use UnzerPayment6\Components\ConfigReader\ConfigReader; use UnzerPayment6\Components\ConfigReader\ConfigReaderInterface; use UnzerPayment6\Components\Event\AutomaticShippingNotificationEvent; +use UnzerPayment6\Components\PaymentActions\PaymentActionService; use UnzerPayment6\Components\ShipService\ShipServiceInterface; use UnzerPayment6\Components\UnzerUtil\UnzerTransactionUtil; use UnzerPayment6\Components\Validator\AutomaticShippingValidatorInterface; @@ -36,7 +37,7 @@ public function __construct( private EventDispatcherInterface $eventDispatcher, private ShipServiceInterface $shipService, private ConfigReaderInterface $configReader, - private UnzerTransactionUtil $unzerTransactionUtil + private PaymentActionService $paymentActionService ) { } @@ -119,7 +120,7 @@ protected function doAutomaticTransactions(StateMachineTransitionEvent $event, ? if (\is_array($autoCaptureStatus) && \in_array($event->getToPlace()->getId(), $autoCaptureStatus, true)) { $this->logger->info(\sprintf('Automatic capture for order [%s] was triggered', $order->getOrderNumber())); try { - $this->unzerTransactionUtil->captureOrder($order, $event->getContext()); + $this->paymentActionService->captureOrder($order, $event->getContext()); } catch (\Throwable $exception) { $this->logger->error(\sprintf('Error while executing automatic capture for order [%s]: %s', $order->getOrderNumber(), $exception->getMessage()), [ 'trace' => $exception->getTraceAsString(), @@ -134,13 +135,30 @@ protected function doAutomaticTransactions(StateMachineTransitionEvent $event, ? if (\is_array($autoRefundStatus) && \in_array($event->getToPlace()->getId(), $autoRefundStatus, true)) { $this->logger->info(\sprintf('Automatic refund for order [%s] was triggered', $order->getOrderNumber())); try { - $this->unzerTransactionUtil->refundOrder($order, $event->getContext()); + $this->paymentActionService->refundOrder($order, $event->getContext()); } catch (\Throwable $exception) { $this->logger->error(\sprintf('Error while executing automatic refund for order [%s]: %s', $order->getOrderNumber(), $exception->getMessage()), [ 'trace' => $exception->getTraceAsString(), ]); } } + + $autoReturnRefundStatus = $config->get(ConfigReader::CONFIG_KEY_DELIVERY_STATUS_FOR_RETURNS_REFUND); + if (\is_scalar($autoReturnRefundStatus)) { + $autoReturnRefundStatus = [$autoReturnRefundStatus]; + } + if (\is_array($autoReturnRefundStatus) && \in_array($event->getToPlace()->getId(), $autoReturnRefundStatus, true)) { + $this->logger->info(\sprintf('Automatic return refund for order [%s] was triggered', $order->getOrderNumber())); + try { + $this->paymentActionService->executeReturnRefunds($order, $event->getContext()); + } catch (\Throwable $exception) { + $this->logger->error(\sprintf('Error while executing automatic return refund for order [%s]: %s', $order->getOrderNumber(), $exception->getMessage()), [ + 'trace' => $exception->getTraceAsString(), + ]); + } + } + + } protected function setCustomFields( diff --git a/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/index.js b/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/index.js index 592721f7..05a7f753 100644 --- a/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/index.js +++ b/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/index.js @@ -15,6 +15,7 @@ Component.register('unzer-payment-tab', { paymentResources: [], loadedResources: 0, isLoading: true, + order:null }; }, @@ -55,7 +56,10 @@ Component.register('unzer-payment-tab', { const orderId = this.$route.params.id; const criteria = new Criteria(); criteria + .addAssociation('currency') + .addAssociation('lineItems.promotion') .getAssociation('transactions') + .addSorting(Criteria.sort('createdAt', 'DESC')); this.orderRepository diff --git a/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/unzer-payment-tab.html.twig b/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/unzer-payment-tab.html.twig index 805d3b3a..9cbffbc3 100644 --- a/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/unzer-payment-tab.html.twig +++ b/src/Resources/app/administration/src/module/unzer-payment/page/unzer-payment-tab/unzer-payment-tab.html.twig @@ -11,9 +11,16 @@ @reloadOrderDetails="reloadOrderDetails" > + {% endblock %} - {% block unzer_payment_payment_details_content_payment_history %} + {% block unzer_payment_payment_details_content_payment_history %} {"use strict";let e=window.PluginBaseClass;class t extends e{init(){this._registerElements(),this._registerEvents()}_registerElements(){this.submitButton=this.getSubmitButton()}getSubmitButton(){let e=document.getElementById(this.options.submitButtonId);return e||(e=document.getElementById(this.options.confirmFormId).getElementsByTagName("button")[0]),e||null}_registerEvents(){this.submitButton.addEventListener("click",this._onSubmitButtonClick.bind(this)),this.options.unzerCustomer&&Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&(console.log("set customer data",this.options.unzerCustomer),e.setCustomerData(this.options.unzerCustomer))})}setSubmitButtonActive(e){e?(this.submitButton.classList.remove(this.options.disabledClass),this.submitButton.disabled=!1):(this.submitButton.classList.add(this.options.disabledClass),this.submitButton.disabled=!0)}submitTypeId(e,t){if(document.getElementById(this.options.resourceIdElementId).value=e,t){let e=document.getElementById(this.options.threatMetrixIdElementId);e&&(e.value=t)}this.setSubmitButtonActive(!0),this.submitButton.click(),this.setSubmitButtonActive(!1)}showError(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=document.getElementsByClassName(this.options.errorWrapperClass).item(0),s=document.querySelectorAll(this.options.errorContentSelector)[0];t&&""!==s.innerText?s.innerText="".concat(s.innerText,"\n").concat(e.message):s.innerText=e.message,n.hidden=!1,n.scrollIntoView({block:"end",behavior:"smooth"}),this.setSubmitButtonActive(!0),this.submitting=!1}renderErrorToElement(e,t){let n=document.getElementsByClassName(this.options.errorWrapperClass).item(0),s=document.querySelectorAll(this.options.errorContentSelector)[0];n.hidden=!1,s.innerText=e.message,t.appendChild(n)}async _onSubmitButtonClick(e){if(!0===this.submitting)return;if(this.submitting=!0,e.preventDefault(),!this._validateForm()){this.submitting=!1,this.setSubmitButtonActive(!0);return}this.setSubmitButtonActive(!1);let t=document.querySelector(this.options.savedDeviceSelectedRadioButtonSelector);if(t&&t.id!==this.options.savedDeviceRadioButtonNewAccountId)this.submitTypeId(t.value,null);else{let e=document.getElementById("unzer-payment-component");if(e)try{let t=await e.submit();t.submitResponse?!0===t.submitResponse.success?(console.log("submit response: ",t.submitResponse),this.submitTypeId(t.submitResponse.data.id,t.threatMetrixId||null)):this.showError({message:"GENERAL ERROR"}):this.showError({message:"EXCEPTIONAL ERROR"})}catch(t){e.scrollIntoView({block:"end",behavior:"smooth"}),this.submitting=!1,this.setSubmitButtonActive(!0)}else this.setSubmitButtonActive(!0),this.submitButton.click(),this.setSubmitButtonActive(!1)}}_validateForm(){let e=!0,t=document.forms[this.options.confirmFormId].elements;this._clearErrorMessage();for(let n=0;n0&&this.showError({message:this.options.errorShouldNotBeEmpty.replace(/%field%/,s.labels[0].innerText)},!0),e=!1):s.classList.remove("is-invalid")}return e}_clearErrorMessage(){let e=document.getElementsByClassName(this.options.errorWrapperClass).item(0),t=document.querySelectorAll(this.options.errorContentSelector)[0];e.hidden=!0,t.innerText=""}getB2bCustomerObject(e){let t="".concat(e.firstName," ").concat(e.lastName),n=e.birthday?new Date(e.birthday):null,s={firstname:e.firstName,lastname:e.lastName,email:e.email,company:e.activeBillingAddress.company,salutation:e.salutation.salutationKey,billingAddress:{name:t,street:e.activeBillingAddress.street,zip:e.activeBillingAddress.zipcode,city:e.activeBillingAddress.city,country:e.activeBillingAddress.country.iso},shippingAddress:{name:t,street:e.activeShippingAddress.street,zip:e.activeShippingAddress.zipcode,city:e.activeShippingAddress.city,country:e.activeShippingAddress.country.iso}};return n&&(s.birthDate=n.getFullYear()+"-"+(n.getMonth()+1).toString().padStart(2,"0")+"-"+n.getDay().toString().padStart(2,"0")),s}}t.options={publicKey:null,shopLocale:null,unzerCustomer:null,submitButtonId:"confirmFormSubmit",disabledClass:"disabled",resourceIdElementId:"unzerResourceId",threatMetrixIdElementId:"unzerThreatMetrixId",confirmFormId:"confirmOrderForm",errorWrapperClass:"unzer-payment--error-wrapper",errorContentSelector:".unzer-payment--error-wrapper .alert-content",errorShouldNotBeEmpty:"%field% should not be empty",isOrderEdit:!1,savedDeviceRadioButtonSelector:'*[name="savedPaymentDevice"]',savedDeviceRadioButtonNewAccountId:"device-new",savedDeviceSelectedRadioButtonSelector:'*[name="savedPaymentDevice"]:checked'},t.submitting=!1;let n=window.PluginBaseClass;class s extends n{init(){this._unzerPaymentPlugin=window.PluginManager.getPluginInstances("UnzerPaymentBase")[0]}_handleError(e){this._unzerPaymentPlugin.showError(e)}_setSubmitButtonActive(e){this._unzerPaymentPlugin.setSubmitButtonActive(e)}_getSubmitButton(){return this._unzerPaymentPlugin.getSubmitButton()}}s._unzerPaymentPlugin=null,window.PluginBaseClass;class o extends s{init(){super.init(),this._registerEvents()}_registerEvents(){if(this.options.hasSavedDevices){let e=this.el.querySelectorAll(this.options.radioButtonSelector);for(let t=0;tthis._onRadioButtonChange(e));document.querySelector(this.options.selectedRadioButtonSelector).dispatchEvent(new Event("change"))}}_onRadioButtonChange(e){let t=e.target;this.el.querySelector(this.options.elementWrapperSelector).hidden=t.id!==this.options.radioButtonNewAccountId}}o.options={elementWrapperSelector:".unzer-payment-create-component-container",radioButtonSelector:'*[name="savedPaymentDevice"]',radioButtonNewAccountId:"device-new",selectedRadioButtonSelector:'*[name="savedPaymentDevice"]:checked',hasSavedDevices:!1},window.PluginBaseClass;class i extends s{init(){super.init(),this._hasCapability()?(this._createForm(),this._hideBuyButton()):this._disableApplePay()}_hasCapability(){return window.ApplePaySession&&window.ApplePaySession.canMakePayments()&&window.ApplePaySession.supportsVersion(6)}_disableApplePay(){document.querySelector(this.options.applePayMethodSelector).remove(),document.querySelectorAll("[data-unzer-payment-apple-pay-v2]").forEach(e=>e.remove()),this._handleError({message:this.options.noApplePayMessage}),this._unzerPaymentPlugin.setSubmitButtonActive(!1)}_createForm(){Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&(e.setApplePayData(this._getApplePayPaymentRequest()),document.getElementById("unzer-checkout-component").onPaymentSubmit=t=>{t.submitResponse&&t.submitResponse.success&&this._unzerPaymentPlugin._validateForm()&&(e.style.display="none",this._unzerPaymentPlugin.submitting=!0,this._unzerPaymentPlugin.submitTypeId(t.submitResponse.data.id))})})}_getApplePayPaymentRequest(){return{countryCode:this.options.countryCode,currencyCode:this.options.currency,supportedNetworks:this.options.supportedNetworks,merchantCapabilities:this.options.merchantCapabilities,total:{label:this.options.shopName,amount:this.options.amount}}}_hideBuyButton(){document.querySelector(this.options.checkoutConfirmButtonSelector).style.display="none"}}i.options={countryCode:"DE",currency:"EUR",shopName:"Unzer GmbH",amount:"0.0",applePayButtonSelector:".apple-pay-button",checkoutConfirmButtonSelector:"#confirmFormSubmit",applePayMethodSelector:".unzer-payment-apple-pay-v2-method-wrapper",authorizePaymentUrl:"",merchantValidationUrl:"",noApplePayMessage:"",supportedNetworks:["masterCard","visa"]};class a extends s{init(){super.init(),Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&e.setBasketData({amount:this.options.paylaterInstallmentAmount,currencyType:this.options.paylaterInstallmentCurrency,country:this.options.countryIso})})}}a.options={countryIso:"",paylaterInstallmentAmount:"",paylaterInstallmentCurrency:""};class r extends s{init(){super.init(),this._registerGooglePayButton(),this._hideBuyButton()}_registerGooglePayButton(){Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&(e.setGooglePayData({gatewayMerchantId:this.options.gatewayMerchantId,merchantInfo:{merchantName:this.options.merchantName,merchantId:this.options.merchantId},transactionInfo:{currencyCode:this.options.currency,countryCode:this.options.countryCode,totalPriceStatus:"ESTIMATED",totalPrice:String(this.options.amount)},buttonOptions:{buttonColor:this.options.buttonColor,buttonSizeMode:this.options.buttonSizeMode},allowedCardNetworks:this.options.allowedCardNetworks,allowCreditCards:this.options.allowCreditCards,allowPrepaidCards:this.options.allowPrepaidCards}),document.getElementById("unzer-checkout-component").onPaymentSubmit=t=>{t.submitResponse&&t.submitResponse.success?!this._unzerPaymentPlugin._validateForm()||(e.style.display="none",this._unzerPaymentPlugin.submitting=!0,this._unzerPaymentPlugin.submitTypeId(t.submitResponse.data.id)):console.log("ERROR",t)})})}_hideBuyButton(){this._getSubmitButton().style.display="none"}}r.options={googlePayButtonId:"unzer-google-pay-button",merchantName:"",merchantId:"",gatewayMerchantId:"",currency:"EUR",amount:"0.0",countryCode:"DE",allowedCardNetworks:[],allowCreditCards:!0,allowPrepaidCards:!0,buttonColor:"default",buttonSizeMode:"fill"},r.submitting=!1;let l=window.PluginBaseClass;class u extends l{init(){this.includeJs(),this.registerActions()}includeJs(){if(!document.querySelector('script[src*="static-v2.unzer.com/v2/ui-components/index.js"]')){let e=document.createElement("script");e.type="module",e.src="https://static-v2.unzer.com/v2/ui-components/index.js",document.head.appendChild(e)}}registerActions(){Promise.all([customElements.whenDefined("unzer-payment"),customElements.whenDefined("unzer-google-pay"),customElements.whenDefined("unzer-paypal-express"),customElements.whenDefined("unzer-apple-pay")]).then(()=>{let e=this.el.querySelector(".unzer-express-payment"),t=this.el.querySelector(".unzer-paypal-express"),n=this.el.querySelector(".unzer-google-pay"),s=this.el.querySelector(".unzer-apple-pay");e&&(t&&this.registerPaypalExpress(t,e),n&&this.registerGooglePay(n,e),s&&(window.ApplePaySession&&window.ApplePaySession.canMakePayments()&&window.ApplePaySession.supportsVersion(6)?this.registerApplePay(s,e):document.querySelector(".unzer-applepay-express-container").style.display="none"))})}registerPaypalExpress(e,t){e.id="unzer-paypal-button-"+Math.floor(1e4*Math.random()),e.addEventListener("click",async e=>{e.stopPropagation();let n=await t.submit();if(n.submitResponse&&n.submitResponse.success){let e=n.submitResponse.data.id;fetch("/unzer/paypal-express",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paymentTypeId:e})}).then(e=>e.json()).then(e=>{location.href=e.redirectUrl})}})}registerGooglePay(e,t){t.setGooglePayData({gatewayMerchantId:this.options.googlePay.gatewayMerchantId,merchantInfo:{merchantName:this.options.googlePay.merchantName,merchantId:this.options.googlePay.merchantId},transactionInfo:{currencyCode:this.options.googlePay.currency,countryCode:this.options.googlePay.countryCode,totalPriceStatus:"ESTIMATED",checkoutOption:"DEFAULT",totalPrice:String(this.options.googlePay.amount)},buttonOptions:{buttonColor:this.options.googlePay.buttonColor,buttonSizeMode:this.options.googlePay.buttonSizeMode},allowedCardNetworks:this.options.googlePay.allowedCardNetworks,allowCreditCards:this.options.googlePay.allowCreditCards,allowPrepaidCards:this.options.googlePay.allowPrepaidCards,billingAddressParameters:{format:"MIN"},billingAddressRequired:!0,emailRequired:!0,onPaymentDataChangedCallback:()=>({}),shippingOptionParameters:{},onPaymentAuthorizedCallback:async(e,n,s)=>{console.log("paymentData:",e);let o=await t.submit(),i=o.submitResponse.data.id;console.log(o,"--- success paymentTypeId",i),console.log("submit response: ",o),fetch("/unzer/google-pay-express",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paymentTypeId:i,paymentData:e})}).then(e=>e.json()).then(e=>{console.log(JSON.stringify(e)),location.href=e.redirectUrl})},shippingAddressRequired:!0,shippingOptionRequired:!1})}registerApplePay(e,t){let n={countryCode:this.options.applePay.countryCode,currencyCode:this.options.applePay.currency,supportedNetworks:this.options.applePay.supportedNetworks,merchantCapabilities:this.options.applePay.merchantCapabilities,total:{label:this.options.applePay.shopName,amount:String(this.options.applePay.amount)},requiredShippingContactFields:["postalAddress","name","email","phone"],requiredBillingContactFields:["postalAddress","name","email","phone"],onPaymentAuthorizedCallback:async(e,n,s)=>{console.log("paymentData:",e);let o=event.payment.shippingContact,i=event.payment.billingContact;console.log(o),console.log(i);let a=await t.submit(),r=a.submitResponse.data.id;console.log(a,"--- success paymentTypeId",r),console.log("submit response: ",a),fetch("/unzer/applepay-express",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paymentTypeId:r,paymentData:e,shippingContact:o,billingContact:i})}).then(e=>e.json()).then(e=>{console.log(JSON.stringify(e)),location.href=e.redirectUrl})}};n.initApplePaySession=e=>{},null==t||t.setApplePayData(n)}}u.options={googlePay:{},applePay:{}},window.PluginManager.register("UnzerPaymentBase",t,"[data-unzer-payment-base]"),window.PluginManager.register("UnzerPaymentCreditCard",class extends o{},"[data-unzer-payment-credit-card]"),window.PluginManager.register("UnzerPaymentPayPal",class extends o{},"[data-unzer-payment-paypal]"),window.PluginManager.register("UnzerPaymentSepaDirectDebit",class extends o{},"[data-unzer-payment-sepa-direct-debit]"),window.PluginManager.register("UnzerPaymentApplePayV2",i,"[data-unzer-payment-apple-pay-v2]"),window.PluginManager.register("UnzerPaymentPaylaterInvoice",class extends s{},"[data-unzer-payment-paylater-invoice]"),window.PluginManager.register("UnzerPaymentPaylaterInstallment",a,"[data-unzer-payment-paylater-installment]"),window.PluginManager.register("UnzerPaymentPaylaterDirectDebitSecured",class extends s{},"[data-unzer-payment-paylater-direct-debit-secured]"),window.PluginManager.register("UnzerPaymentGooglePay",r,"[data-unzer-payment-google-pay]"),window.PluginManager.register("UnzerPaymentExpressButtons",u,"[data-unzer-payment-express-buttons]")})(); \ No newline at end of file +(()=>{"use strict";let e=window.PluginBaseClass;class t extends e{init(){this._registerElements(),this._registerEvents()}_registerElements(){this.submitButton=this.getSubmitButton()}getSubmitButton(){let e=document.getElementById(this.options.submitButtonId);return e||(e=document.getElementById(this.options.confirmFormId).getElementsByTagName("button")[0]),e||null}_registerEvents(){this.submitButton.addEventListener("click",this._onSubmitButtonClick.bind(this)),this.options.unzerCustomer&&Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&(console.log("set customer data",this.options.unzerCustomer),e.setCustomerData(this.options.unzerCustomer))})}setSubmitButtonActive(e){e?(this.submitButton.classList.remove(this.options.disabledClass),this.submitButton.disabled=!1):(this.submitButton.classList.add(this.options.disabledClass),this.submitButton.disabled=!0)}submitTypeId(e,t){if(document.getElementById(this.options.resourceIdElementId).value=e,t){let e=document.getElementById(this.options.threatMetrixIdElementId);e&&(e.value=t)}this.setSubmitButtonActive(!0),this.submitButton.click(),this.setSubmitButtonActive(!1)}showError(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=document.getElementsByClassName(this.options.errorWrapperClass).item(0),s=document.querySelectorAll(this.options.errorContentSelector)[0];t&&""!==s.innerText?s.innerText="".concat(s.innerText,"\n").concat(e.message):s.innerText=e.message,n.hidden=!1,n.scrollIntoView({block:"end",behavior:"smooth"}),this.setSubmitButtonActive(!0),this.submitting=!1}renderErrorToElement(e,t){let n=document.getElementsByClassName(this.options.errorWrapperClass).item(0),s=document.querySelectorAll(this.options.errorContentSelector)[0];n.hidden=!1,s.innerText=e.message,t.appendChild(n)}async _onSubmitButtonClick(e){if(!0===this.submitting)return;if(this.submitting=!0,e.preventDefault(),!this._validateForm()){this.submitting=!1,this.setSubmitButtonActive(!0);return}this.setSubmitButtonActive(!1);let t=document.querySelector(this.options.savedDeviceSelectedRadioButtonSelector);if(t&&t.id!==this.options.savedDeviceRadioButtonNewAccountId)this.submitTypeId(t.value,null);else{let e=document.getElementById("unzer-payment-component");if(e)try{let t=await e.submit();t.submitResponse?!0===t.submitResponse.success?(console.log("submit response: ",t.submitResponse),this.submitTypeId(t.submitResponse.data.id,t.threatMetrixId||null)):this.showError({message:"GENERAL ERROR"}):this.showError({message:"EXCEPTIONAL ERROR"})}catch(t){e.scrollIntoView({block:"end",behavior:"smooth"}),this.submitting=!1,this.setSubmitButtonActive(!0)}else this.setSubmitButtonActive(!0),this.submitButton.click(),this.setSubmitButtonActive(!1)}}_validateForm(){let e=!0,t=document.forms[this.options.confirmFormId].elements;this._clearErrorMessage();for(let n=0;n0&&this.showError({message:this.options.errorShouldNotBeEmpty.replace(/%field%/,s.labels[0].innerText)},!0),e=!1):s.classList.remove("is-invalid")}return e}_clearErrorMessage(){let e=document.getElementsByClassName(this.options.errorWrapperClass).item(0),t=document.querySelectorAll(this.options.errorContentSelector)[0];e.hidden=!0,t.innerText=""}getB2bCustomerObject(e){let t="".concat(e.firstName," ").concat(e.lastName),n=e.birthday?new Date(e.birthday):null,s={firstname:e.firstName,lastname:e.lastName,email:e.email,company:e.activeBillingAddress.company,salutation:e.salutation.salutationKey,billingAddress:{name:t,street:e.activeBillingAddress.street,zip:e.activeBillingAddress.zipcode,city:e.activeBillingAddress.city,country:e.activeBillingAddress.country.iso},shippingAddress:{name:t,street:e.activeShippingAddress.street,zip:e.activeShippingAddress.zipcode,city:e.activeShippingAddress.city,country:e.activeShippingAddress.country.iso}};return n&&(s.birthDate=n.getFullYear()+"-"+(n.getMonth()+1).toString().padStart(2,"0")+"-"+n.getDay().toString().padStart(2,"0")),s}}t.options={publicKey:null,shopLocale:null,unzerCustomer:null,submitButtonId:"confirmFormSubmit",disabledClass:"disabled",resourceIdElementId:"unzerResourceId",threatMetrixIdElementId:"unzerThreatMetrixId",confirmFormId:"confirmOrderForm",errorWrapperClass:"unzer-payment--error-wrapper",errorContentSelector:".unzer-payment--error-wrapper .alert-content",errorShouldNotBeEmpty:"%field% should not be empty",isOrderEdit:!1,savedDeviceRadioButtonSelector:'*[name="savedPaymentDevice"]',savedDeviceRadioButtonNewAccountId:"device-new",savedDeviceSelectedRadioButtonSelector:'*[name="savedPaymentDevice"]:checked'},t.submitting=!1;let n=window.PluginBaseClass;class s extends n{init(){this._unzerPaymentPlugin=window.PluginManager.getPluginInstances("UnzerPaymentBase")[0]}_handleError(e){this._unzerPaymentPlugin.showError(e)}_setSubmitButtonActive(e){this._unzerPaymentPlugin.setSubmitButtonActive(e)}_getSubmitButton(){return this._unzerPaymentPlugin.getSubmitButton()}}s._unzerPaymentPlugin=null,window.PluginBaseClass;class o extends s{init(){super.init(),this._registerEvents()}_registerEvents(){if(this.options.hasSavedDevices){let e=this.el.querySelectorAll(this.options.radioButtonSelector);for(let t=0;tthis._onRadioButtonChange(e));document.querySelector(this.options.selectedRadioButtonSelector).dispatchEvent(new Event("change"))}}_onRadioButtonChange(e){let t=e.target;this.el.querySelector(this.options.elementWrapperSelector).hidden=t.id!==this.options.radioButtonNewAccountId}}o.options={elementWrapperSelector:".unzer-payment-create-component-container",radioButtonSelector:'*[name="savedPaymentDevice"]',radioButtonNewAccountId:"device-new",selectedRadioButtonSelector:'*[name="savedPaymentDevice"]:checked',hasSavedDevices:!1},window.PluginBaseClass;class i extends s{init(){super.init(),this._hasCapability()?(this._createForm(),this._hideBuyButton()):this._disableApplePay()}_hasCapability(){return window.ApplePaySession&&window.ApplePaySession.canMakePayments()&&window.ApplePaySession.supportsVersion(6)}_disableApplePay(){document.querySelector(this.options.applePayMethodSelector).remove(),document.querySelectorAll("[data-unzer-payment-apple-pay-v2]").forEach(e=>e.remove()),this._handleError({message:this.options.noApplePayMessage}),this._unzerPaymentPlugin.setSubmitButtonActive(!1)}_createForm(){Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&(e.setApplePayData(this._getApplePayPaymentRequest()),document.getElementById("unzer-checkout-component").onPaymentSubmit=t=>{t.submitResponse&&t.submitResponse.success&&this._unzerPaymentPlugin._validateForm()&&(e.style.display="none",this._unzerPaymentPlugin.submitting=!0,this._unzerPaymentPlugin.submitTypeId(t.submitResponse.data.id))})})}_getApplePayPaymentRequest(){return{countryCode:this.options.countryCode,currencyCode:this.options.currency,supportedNetworks:this.options.supportedNetworks,merchantCapabilities:this.options.merchantCapabilities,total:{label:this.options.shopName,amount:this.options.amount}}}_hideBuyButton(){document.querySelector(this.options.checkoutConfirmButtonSelector).style.display="none"}}i.options={countryCode:"DE",currency:"EUR",shopName:"Unzer GmbH",amount:"0.0",applePayButtonSelector:".apple-pay-button",checkoutConfirmButtonSelector:"#confirmFormSubmit",applePayMethodSelector:".unzer-payment-apple-pay-v2-method-wrapper",authorizePaymentUrl:"",merchantValidationUrl:"",noApplePayMessage:"",supportedNetworks:["masterCard","visa"]};class a extends s{init(){super.init(),Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&e.setBasketData({amount:this.options.paylaterInstallmentAmount,currencyType:this.options.paylaterInstallmentCurrency,country:this.options.countryIso})})}}a.options={countryIso:"",paylaterInstallmentAmount:"",paylaterInstallmentCurrency:""};class r extends s{init(){super.init(),this._registerGooglePayButton(),this._hideBuyButton()}_registerGooglePayButton(){Promise.all([customElements.whenDefined("unzer-payment")]).then(()=>{let e=document.getElementById("unzer-payment-component");e&&(e.setGooglePayData({gatewayMerchantId:this.options.gatewayMerchantId,merchantInfo:{merchantName:this.options.merchantName,merchantId:this.options.merchantId},transactionInfo:{currencyCode:this.options.currency,countryCode:this.options.countryCode,totalPriceStatus:"ESTIMATED",totalPrice:String(this.options.amount)},buttonOptions:{buttonColor:this.options.buttonColor,buttonSizeMode:this.options.buttonSizeMode},allowedCardNetworks:this.options.allowedCardNetworks,allowCreditCards:this.options.allowCreditCards,allowPrepaidCards:this.options.allowPrepaidCards}),document.getElementById("unzer-checkout-component").onPaymentSubmit=t=>{t.submitResponse&&t.submitResponse.success?!this._unzerPaymentPlugin._validateForm()||(e.style.display="none",this._unzerPaymentPlugin.submitting=!0,this._unzerPaymentPlugin.submitTypeId(t.submitResponse.data.id)):console.log("ERROR",t)})})}_hideBuyButton(){this._getSubmitButton().style.display="none"}}r.options={googlePayButtonId:"unzer-google-pay-button",merchantName:"",merchantId:"",gatewayMerchantId:"",currency:"EUR",amount:"0.0",countryCode:"DE",allowedCardNetworks:[],allowCreditCards:!0,allowPrepaidCards:!0,buttonColor:"default",buttonSizeMode:"fill"},r.submitting=!1;let l=window.PluginBaseClass;class u extends l{init(){this.includeJs(),this.registerActions()}includeJs(){if(!document.querySelector('script[src*="static-v2.unzer.com/v2/ui-components/index.js"]')){let e=document.createElement("script");e.type="module",e.src="https://static-v2.unzer.com/v2/ui-components/index.js",document.head.appendChild(e)}}registerActions(){Promise.all([customElements.whenDefined("unzer-payment"),customElements.whenDefined("unzer-google-pay"),customElements.whenDefined("unzer-paypal-express"),customElements.whenDefined("unzer-apple-pay")]).then(()=>{let e=this.el.querySelector(".unzer-express-payment"),t=this.el.querySelector(".unzer-paypal-express"),n=this.el.querySelector(".unzer-google-pay"),s=this.el.querySelector(".unzer-apple-pay");e&&(t&&this.registerPaypalExpress(t,e),n&&this.registerGooglePay(n,e),s&&this.registerApplePay(s,e))})}registerPaypalExpress(e,t){e.id="unzer-paypal-button-"+Math.floor(1e4*Math.random()),e.addEventListener("click",async e=>{e.stopPropagation();let n=await t.submit();if(n.submitResponse&&n.submitResponse.success){let e=n.submitResponse.data.id;fetch("/unzer/paypal-express",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paymentTypeId:e})}).then(e=>e.json()).then(e=>{location.href=e.redirectUrl})}})}registerGooglePay(e,t){t.setGooglePayData({gatewayMerchantId:this.options.googlePay.gatewayMerchantId,merchantInfo:{merchantName:this.options.googlePay.merchantName,merchantId:this.options.googlePay.merchantId},transactionInfo:{currencyCode:this.options.googlePay.currency,countryCode:this.options.googlePay.countryCode,totalPriceStatus:"ESTIMATED",checkoutOption:"DEFAULT",totalPrice:String(this.options.googlePay.amount)},buttonOptions:{buttonColor:this.options.googlePay.buttonColor,buttonSizeMode:this.options.googlePay.buttonSizeMode},allowedCardNetworks:this.options.googlePay.allowedCardNetworks,allowCreditCards:this.options.googlePay.allowCreditCards,allowPrepaidCards:this.options.googlePay.allowPrepaidCards,billingAddressParameters:{format:"MIN"},billingAddressRequired:!0,emailRequired:!0,onPaymentDataChangedCallback:()=>({}),shippingOptionParameters:{},onPaymentAuthorizedCallback:async(e,n,s)=>{console.log("paymentData:",e);let o=await t.submit(),i=o.submitResponse.data.id;console.log(o,"--- success paymentTypeId",i),console.log("submit response: ",o),fetch("/unzer/google-pay-express",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paymentTypeId:i,paymentData:e})}).then(e=>e.json()).then(e=>{console.log(JSON.stringify(e)),location.href=e.redirectUrl})},shippingAddressRequired:!0,shippingOptionRequired:!1})}registerApplePay(e,t){let n={countryCode:this.options.applePay.countryCode,currencyCode:this.options.applePay.currency,supportedNetworks:this.options.applePay.supportedNetworks,merchantCapabilities:this.options.applePay.merchantCapabilities,total:{label:this.options.applePay.shopName,amount:String(this.options.applePay.amount)},requiredShippingContactFields:["postalAddress","name","email","phone"],requiredBillingContactFields:["postalAddress","name","email","phone"],onPaymentAuthorizedCallback:async(e,n,s,o)=>{console.log("paymentData:",e);let i=o.payment.shippingContact,a=o.payment.billingContact;console.log(i),console.log(a);let r=await t.submit();r.submitResponse.success?n():s();let l=r.submitResponse.data.id;console.log(r,"--- success paymentTypeId",l),console.log("submit response: ",r),fetch("/unzer/applepay-express",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paymentTypeId:l,paymentData:e,shippingContact:i,billingContact:a})}).then(e=>e.json()).then(e=>{console.log(JSON.stringify(e)),location.href=e.redirectUrl})}};n.initApplePaySession=e=>{},null==t||t.setApplePayData(n)}}u.options={googlePay:{},applePay:{}},window.PluginManager.register("UnzerPaymentBase",t,"[data-unzer-payment-base]"),window.PluginManager.register("UnzerPaymentCreditCard",class extends o{},"[data-unzer-payment-credit-card]"),window.PluginManager.register("UnzerPaymentPayPal",class extends o{},"[data-unzer-payment-paypal]"),window.PluginManager.register("UnzerPaymentSepaDirectDebit",class extends o{},"[data-unzer-payment-sepa-direct-debit]"),window.PluginManager.register("UnzerPaymentApplePayV2",i,"[data-unzer-payment-apple-pay-v2]"),window.PluginManager.register("UnzerPaymentPaylaterInvoice",class extends s{},"[data-unzer-payment-paylater-invoice]"),window.PluginManager.register("UnzerPaymentPaylaterInstallment",a,"[data-unzer-payment-paylater-installment]"),window.PluginManager.register("UnzerPaymentPaylaterDirectDebitSecured",class extends s{},"[data-unzer-payment-paylater-direct-debit-secured]"),window.PluginManager.register("UnzerPaymentGooglePay",r,"[data-unzer-payment-google-pay]"),window.PluginManager.register("UnzerPaymentExpressButtons",u,"[data-unzer-payment-express-buttons]")})(); \ No newline at end of file diff --git a/src/Resources/app/storefront/src/unzer/express/unzer-payment.express-buttons.plugin.js b/src/Resources/app/storefront/src/unzer/express/unzer-payment.express-buttons.plugin.js index e6b2b821..411ced75 100644 --- a/src/Resources/app/storefront/src/unzer/express/unzer-payment.express-buttons.plugin.js +++ b/src/Resources/app/storefront/src/unzer/express/unzer-payment.express-buttons.plugin.js @@ -61,17 +61,7 @@ export default class UnzerPaymentExpressButtonsPlugin extends Plugin { } if (unzerApplePay) { - if ( - window.ApplePaySession && - window.ApplePaySession.canMakePayments() && - window.ApplePaySession.supportsVersion(6) - ) { - this.registerApplePay(unzerApplePay, unzerExpressPayment); - } else { - document.querySelector( - '.unzer-applepay-express-container' - ).style.display = 'none'; - } + this.registerApplePay(unzerApplePay, unzerExpressPayment); } }); } @@ -194,7 +184,8 @@ export default class UnzerPaymentExpressButtonsPlugin extends Plugin { onPaymentAuthorizedCallback: async ( paymentData, approve, - reject + reject, + event ) => { console.log('paymentData:', paymentData); let shippingContact = event.payment.shippingContact; // Store the shipping contact data for express checkout @@ -205,6 +196,11 @@ export default class UnzerPaymentExpressButtonsPlugin extends Plugin { // You can create customer here based on paymentData const response = await unzerExpressPayment.submit(); + if (response.submitResponse.success) { + approve(); + } else { + reject(); + } const paymentTypeId = response.submitResponse.data.id; console.log( response, diff --git a/src/Resources/config/dependencies/controllers.xml b/src/Resources/config/dependencies/controllers.xml index 85e3d640..c3963082 100755 --- a/src/Resources/config/dependencies/controllers.xml +++ b/src/Resources/config/dependencies/controllers.xml @@ -28,6 +28,7 @@ + diff --git a/src/Resources/config/dependencies/event_listeners.xml b/src/Resources/config/dependencies/event_listeners.xml index 5e9cf7cc..be996d2e 100644 --- a/src/Resources/config/dependencies/event_listeners.xml +++ b/src/Resources/config/dependencies/event_listeners.xml @@ -52,7 +52,7 @@ - + @@ -67,6 +67,7 @@ + diff --git a/src/Resources/config/dependencies/services.xml b/src/Resources/config/dependencies/services.xml index 1e205930..e307205c 100644 --- a/src/Resources/config/dependencies/services.xml +++ b/src/Resources/config/dependencies/services.xml @@ -82,9 +82,7 @@ - - @@ -106,7 +104,17 @@ - + + + + + + + + + + + diff --git a/src/Resources/config/settings.xml b/src/Resources/config/settings.xml index 320578fa..2af494fd 100755 --- a/src/Resources/config/settings.xml +++ b/src/Resources/config/settings.xml @@ -117,6 +117,7 @@ + paymentSettingsSaveDevices @@ -338,6 +340,15 @@ Leave blank, if you don't want to use automatic refund Leer lassen, um keine automatische Rückzahlung auszulösen + + + deliveryStatusForAutomaticReturnsRefund + state_machine_state + + + only with Shopware Commercial Plugin; Leave blank, if you don't want to use automatic refund + nur mit Shopware Commercial Plugin; Leer lassen, um keine automatische Rückzahlung auszulösen + diff --git a/src/Resources/public/administration/js/unzer-payment6.js b/src/Resources/public/administration/js/unzer-payment6.js index f8afc656..120d88f0 100644 --- a/src/Resources/public/administration/js/unzer-payment6.js +++ b/src/Resources/public/administration/js/unzer-payment6.js @@ -1 +1 @@ -!function(){var e={296:function(){},906:function(){},836:function(){},325:function(){},299:function(){},963:function(){let{Application:e}=Shopware,t=Shopware.Classes.ApiService;class n extends t{constructor(e,t,n="unzer-payment"){super(e,t,n)}validateCredentials(e){return this.httpClient.post(`_action/${this.getApiBasePath()}/validate-credentials`,e,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}registerWebhooks(e){return this.httpClient.post(`_action/${this.getApiBasePath()}/register-webhooks`,e,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}clearWebhooks(e){return this.httpClient.post(`_action/${this.getApiBasePath()}/clear-webhooks`,e,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}getWebhooks(e){return this.httpClient.post(`_action/${this.getApiBasePath()}/get-webhooks`,{privateKey:e},{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}getGooglePayGatewayMerchantId(e){return this.httpClient.get(`_action/${this.getApiBasePath()}/get-google-pay-gateway-merchant-id?salesChannelId=${e||""}`,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}}e.addServiceProvider("UnzerPaymentConfigurationService",t=>new n(e.getContainer("init").httpClient,t.loginService))},748:function(){let{Application:e}=Shopware,t=Shopware.Classes.ApiService;class n extends t{constructor(e,t,n="unzer-payment"){super(e,t,n)}fetchPaymentDetails(e){let n=`_action/${this.getApiBasePath()}/transaction/${e}/details`;return this.httpClient.get(n,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}chargeTransaction(e,n,a){let s=`_action/${this.getApiBasePath()}/transaction/${e}/charge/${a}`;return this.httpClient.get(s,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}refundTransaction(e,n,a,s=null){let i=`_action/${this.getApiBasePath()}/transaction/${e}/refund/${n}/${a}`;return null!==s&&(i=`${i}/${s}`),this.httpClient.get(i,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}cancelTransaction(e,n,a){let s=`_action/${this.getApiBasePath()}/transaction/${e}/cancel/${n}/${a}`;return this.httpClient.get(s,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}ship(e){let n=`_action/${this.getApiBasePath()}/transaction/${e}/ship`;return this.httpClient.get(n,{headers:this.getBasicHeaders()}).then(e=>t.handleResponse(e))}}e.addServiceProvider("UnzerPaymentService",t=>new n(e.getContainer("init").httpClient,t.loginService))},337:function(){let{Component:e}=Shopware,{Criteria:t,EntityCollection:n}=Shopware.Data;e.extend("unzer-entity-multi-select-delivery-status","sw-entity-multi-id-select",{inject:["repositoryFactory"],props:{repository:{type:Object,required:!0,default(){return this.repositoryFactory.create("state_machine_state")}},criteria:{type:Object,required:!1,default(){let e=new t(1,100);return e.addFilter(t.equals("stateMachine.technicalName","order_delivery.state")),e}},entityCollection(){}}})},708:function(){let{Component:e}=Shopware,{Criteria:t}=Shopware.Data;e.extend("unzer-entity-single-select-delivery-status","sw-entity-single-select",{props:{criteria:{type:Object,required:!1,default(){let e=new t(1,100);return e.addFilter(t.equals("stateMachine.technicalName","order_delivery.state")),e}}}})},129:function(e,t,n){var a=n(296);a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[e.id,a,""]]),a.locals&&(e.exports=a.locals),(0,n(534).A)("0620ec53",a,!0,{})},425:function(e,t,n){var a=n(906);a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[e.id,a,""]]),a.locals&&(e.exports=a.locals),(0,n(534).A)("f0afdb6a",a,!0,{})},345:function(e,t,n){var a=n(836);a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[e.id,a,""]]),a.locals&&(e.exports=a.locals),(0,n(534).A)("61f99e4d",a,!0,{})},90:function(e,t,n){var a=n(325);a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[e.id,a,""]]),a.locals&&(e.exports=a.locals),(0,n(534).A)("05921a3e",a,!0,{})},34:function(e,t,n){var a=n(299);a.__esModule&&(a=a.default),"string"==typeof a&&(a=[[e.id,a,""]]),a.locals&&(e.exports=a.locals),(0,n(534).A)("3bbcbade",a,!0,{})},534:function(e,t,n){"use strict";function a(e,t){for(var n=[],a={},s=0;sn.parts.length&&(a.parts.length=n.parts.length)}else{for(var i=[],s=0;s\n {% block unzer_payment_actions_amount_field %}\n
\n \n \n
\n {% endblock %}\n
\n \n {% block unzer_payment_actions_charge_button %}\n \n {{ $tc(\'unzer-payment.paymentDetails.actions.chargeButton\') }}\n \n {% endblock %}\n\n {% block unzer_payment_actions_cancel_button %}\n \n {{ $tc(\'unzer-payment.paymentDetails.actions.cancelButton\') }}\n \n {% endblock %}\n \n \n {% block unzer_payment_actions_reason_field %}\n \n \n {% endblock %}\n\n {% block unzer_payment_actions_refund_button %}\n \n {{ $tc(\'unzer-payment.paymentDetails.actions.refundButton\') }}\n \n {% endblock %}\n \n {% block unzer_payment_actions_button_container_inner %}{% endblock %}\n
\n \n\n
\n {{ $tc(\'unzer-payment.paymentDetails.actions.noActions\') }}\n
\n{% endblock %}',inject:["UnzerPaymentService"],mixins:[t.getByName("notification")],data(){return{isLoading:!1,isSuccessful:!1,transactionAmount:0,reasonCode:null}},props:{transactionResource:{type:Object,required:!0},paymentResource:{type:Object,required:!0},decimalPrecision:{type:Number,required:!0,default:4}},computed:{isChargePossible:function(){return"authorization"===this.transactionResource.type&&"error"!==this.transactionResource.state},isRefundPossible:function(){return"charge"===this.transactionResource.type&&"error"!==this.transactionResource.state&&!(this.transactionResource.isFirst&&"085b64d0028a8bd447294e03c4eb411a"===this.paymentResource.paymentMethodId&&"pending"!==this.paymentResource.state.name&&"partly"!==this.paymentResource.state.name)},maxTransactionAmount(){let e=0,t=this.isRefundPossible&&"085b64d0028a8bd447294e03c4eb411a"===this.paymentResource.paymentMethodId;return this.isRefundPossible&&(e=this.transactionResource.amount),this.isChargePossible&&(e=this.paymentResource.amount.remaining),"remainingAmount"in this.transactionResource&&(e=this.transactionResource.remainingAmount),this.transactionResource.isFirst&&t&&(e=this.paymentResource.amount.remaining),e/10**this.paymentResource.amount.decimalPrecision},reasonCodeSelection(){return[{label:this.$tc("unzer-payment.paymentDetails.actions.reason.cancel"),value:"CANCEL"},{label:this.$tc("unzer-payment.paymentDetails.actions.reason.credit"),value:"CREDIT"},{label:this.$tc("unzer-payment.paymentDetails.actions.reason.return"),value:"RETURN"}]}},created(){this.transactionAmount=this.maxTransactionAmount},methods:{charge(){this.isLoading=!0,this.UnzerPaymentService.chargeTransaction(this.paymentResource.orderTransactionId,this.transactionResource.id,this.transactionAmount).then(()=>{this.createNotificationSuccess({title:this.$tc("unzer-payment.paymentDetails.notifications.chargeSuccessTitle"),message:this.$tc("unzer-payment.paymentDetails.notifications.chargeSuccessMessage")}),this.isSuccessful=!0,this.$emit("reload")}).catch(e=>{let t=e.response.data.errors[0];"generic-error"===t&&(t=this.$tc("unzer-payment.paymentDetails.notifications.genericErrorMessage")),"paylater-invoice-document-required"===t&&(t=this.$tc("unzer-payment.paymentDetails.notifications.paylaterInvoiceDocumentRequiredErrorMessage")),this.createNotificationError({title:this.$tc("unzer-payment.paymentDetails.notifications.chargeErrorTitle"),message:t}),this.isLoading=!1})},refund(){this.isLoading=!0,this.UnzerPaymentService.refundTransaction(this.paymentResource.orderTransactionId,this.transactionResource.id,this.transactionAmount,this.reasonCode).then(()=>{this.createNotificationSuccess({title:this.$tc("unzer-payment.paymentDetails.notifications.refundSuccessTitle"),message:this.$tc("unzer-payment.paymentDetails.notifications.refundSuccessMessage")}),this.isSuccessful=!0,this.$emit("reload")}).catch(e=>{let t=e.response.data.errors[0];"generic-error"===t&&(t=this.$tc("unzer-payment.paymentDetails.notifications.genericErrorMessage")),this.createNotificationError({title:this.$tc("unzer-payment.paymentDetails.notifications.refundErrorTitle"),message:t}),this.isLoading=!1})},startCancel(){this.$emit("cancel",this.transactionAmount)}}});let{Component:a,Mixin:s,Module:i}=Shopware;a.register("unzer-payment-detail",{template:'{% block unzer_payment_detail %}\n \n \n {% block unzer_payment_detail_footer %}\n \n {% block unzer_payment_detail_ship_button %}\n \n {{ $tc(\'unzer-payment.paymentDetails.actions.shipButton\') }}\n \n {% endblock %}\n \n {% endblock %}\n \n{% endblock %}',inject:["UnzerPaymentService"],mixins:[s.getByName("notification")],data(){return{isLoading:!1,isSuccessful:!1,paylaterPaymentMethods:["09588ffee8064f168e909ff31889dd7f","12fbfbce271a43a89b3783453b88e9a6","6d6adcd4b7bf40499873c294a85f32ed"]}},props:{paymentResource:{type:Object,required:!0}},computed:{unzerMaxDigits(){let e=i.getModuleRegistry().get("unzer-payment");return e&&e.manifest?e.manifest.maxDigits:4},remainingAmount(){return this.paymentResource&&this.paymentResource.amount?this.formatAmount(this.paymentResource.amount.remaining,this.paymentResource.amount.decimalPrecision):0},cancelledAmount(){return this.paymentResource&&this.paymentResource.amount?this.formatAmount(this.paymentResource.amount.cancelled,this.paymentResource.amount.decimalPrecision):0},chargedAmount(){return this.paymentResource&&this.paymentResource.amount?this.formatAmount(this.paymentResource.amount.charged,this.paymentResource.amount.decimalPrecision):0}},methods:{reloadOrderDetail(){this.$emit("reloadOrderDetails")},ship(){this.isLoading=!0,this.UnzerPaymentService.ship(this.paymentResource.orderTransactionId).then(()=>{this.createNotificationSuccess({title:this.$tc("unzer-payment.paymentDetails.notifications.shipSuccessTitle"),message:this.$tc("unzer-payment.paymentDetails.notifications.shipSuccessMessage")}),this.isSuccessful=!0,this.$emit("reload")}).catch(e=>{let t=e.response.data.errors[0];"generic-error"===t?t=this.$tc("unzer-payment.paymentDetails.notifications.genericErrorMessage"):"invoice-missing-error"===t?t=this.$tc("unzer-payment.paymentDetails.notifications.invoiceNotFoundMessage"):"documentdate-missing-error"===t?t=this.$tc("unzer-payment.paymentDetails.notifications.documentDateMissingError"):"payment-missing-error"===t&&(t=this.$tc("unzer-payment.paymentDetails.notifications.paymentMissingError")),this.createNotificationError({title:this.$tc("unzer-payment.paymentDetails.notifications.shipErrorTitle"),message:t}),this.isLoading=!1})},formatAmount(e,t){return e/10**Math.min(this.unzerMaxDigits,t)},formatCurrency(e){return Shopware.Utils.format.currency(e||0,this.paymentResource.currency)},isPaylaterPaymentMethod(e){return this.paylaterPaymentMethods.indexOf(e)>=0}}});let{Component:r,Module:o,Mixin:c}=Shopware;r.register("unzer-payment-history",{template:'{% block unzer_payment_history %}\n \n {% block unzer_payment_history_container %}\n \n {% endblock %}\n \n{% endblock %}',inject:["repositoryFactory","UnzerPaymentService"],mixins:[c.getByName("notification")],data(){return{showCancelModal:!1,isCancelLoading:!1,cancelAmount:0}},props:{paymentResource:{type:Object,required:!0}},computed:{unzerMaxDigits(){let e=o.getModuleRegistry().get("unzer-payment");return e&&e.manifest?e.manifest.maxDigits:4},orderTransactionRepository:function(){return this.repositoryFactory.create("order_transaction")},decimalPrecision(){return this.paymentResource&&this.paymentResource.amount&&this.paymentResource.amount.decimalPrecision?Math.min(this.unzerMaxDigits,this.paymentResource.amount.decimalPrecision):this.unzerMaxDigits},data:function(){let e=[];return Object.values(this.paymentResource.transactions).forEach(t=>{let n=this.formatCurrency(this.formatAmount(parseFloat(t.amount),this.decimalPrecision)),a=Shopware.Filter.getByName("date")(t.date,{hour:"numeric",minute:"numeric",second:"numeric"});e.push({type:this.transactionTypeRenderer(t.type),amount:n,date:a,resource:t})}),e},columns:function(){return[{property:"type",label:this.$tc("unzer-payment.paymentDetails.history.column.type"),rawData:!0},{property:"amount",label:this.$tc("unzer-payment.paymentDetails.history.column.amount"),rawData:!0},{property:"date",label:this.$tc("unzer-payment.paymentDetails.history.column.date"),rawData:!0}]}},methods:{transactionTypeRenderer:function(e){switch(e){case"authorization":return this.$tc("unzer-payment.paymentDetails.history.type.authorization");case"charge":return this.$tc("unzer-payment.paymentDetails.history.type.charge");case"shipment":return this.$tc("unzer-payment.paymentDetails.history.type.shipment");case"refund":return this.$tc("unzer-payment.paymentDetails.history.type.refund");case"cancellation":return this.$tc("unzer-payment.paymentDetails.history.type.cancellation");default:return this.$tc("unzer-payment.paymentDetails.history.type.default")}},reload:function(){this.$emit("reload"),this.$emit("reloadOrderDetails")},formatAmount(e,t){return e/10**t},openCancelModal(e,t){this.showCancelModal=e.resource.id,this.cancelAmount=t},closeCancelModal(){this.showCancelModal=!1,this.cancelAmount=0},cancel(){this.isCancelLoading=!0,this.UnzerPaymentService.cancelTransaction(this.paymentResource.orderTransactionId,this.paymentResource.id,this.cancelAmount).then(()=>{this.createNotificationSuccess({title:this.$tc("unzer-payment.paymentDetails.notifications.cancelSuccessTitle"),message:this.$tc("unzer-payment.paymentDetails.notifications.cancelSuccessMessage")}),this.reload()}).catch(e=>{let t=e.response.data.errors[0];"generic-error"===t&&(t=this.$tc("unzer-payment.paymentDetails.notifications.cancelErrorMessage")),this.createNotificationError({title:this.$tc("unzer-payment.paymentDetails.notifications.cancelErrorTitle"),message:t}),this.isCancelLoading=!1,this.reload()})},formatCurrency(e){return Shopware.Utils.format.currency(e||0,this.paymentResource.currency)}}});let{Component:l}=Shopware;l.register("unzer-payment-metadata",{template:'{% block unzer_payment_metadata %}\n