diff --git a/CHANGELOG.md b/CHANGELOG.md
index 117d2e7..e2f7281 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.
+## [2.0.9]
+### Added
+- Support for sales channel–specific terminals for payment methods.
+
## [2.0.8]
### Fixed
- Payment status was shown as Failed even though the order was placed successfully.
diff --git a/Docs/Configuration/shopware_configure_altapay_terminal_detail.png b/Docs/Configuration/shopware_configure_altapay_terminal_detail.png
index e967688..f49261a 100644
Binary files a/Docs/Configuration/shopware_configure_altapay_terminal_detail.png and b/Docs/Configuration/shopware_configure_altapay_terminal_detail.png differ
diff --git a/Docs/Configuration/shopware_setup_altapay_credentials.png b/Docs/Configuration/shopware_setup_altapay_credentials.png
index d6211ee..a098e53 100644
Binary files a/Docs/Configuration/shopware_setup_altapay_credentials.png and b/Docs/Configuration/shopware_setup_altapay_credentials.png differ
diff --git a/composer.json b/composer.json
index 1adda35..8ba8815 100644
--- a/composer.json
+++ b/composer.json
@@ -3,7 +3,7 @@
"description": "AltaPay plugin for Shopware 6",
"type": "shopware-platform-plugin",
"license": "MIT",
- "version": "2.0.8",
+ "version": "2.0.9",
"authors": [
{
"name": "AltaPay A/S",
diff --git a/src/Controller/ApiController.php b/src/Controller/ApiController.php
index 9e23c1f..c4ccf4b 100644
--- a/src/Controller/ApiController.php
+++ b/src/Controller/ApiController.php
@@ -29,11 +29,11 @@ public function __construct(
public function getPayments(Request $request): JsonApiResponse|Response
{
$orderId = $request->get('orderId');
+ /** @var ?OrderEntity $order */
$order = $this->orderRepository->search(new Criteria([$orderId]), Context::createDefaultContext())->first();
if (!$order) {
return new Response(status: 400);
}
- /** @var $order OrderEntity */
$response = $this->paymentService->getTransaction($order, $order->getSalesChannelId());
$responseAsXml = new \SimpleXMLElement($response->getBody()->getContents());
return new JsonApiResponse(json_encode($responseAsXml));
@@ -45,10 +45,7 @@ public function capture(Request $request): JsonApiResponse|Response
$orderId = $request->get('orderId');
$captureAmount = $request->get('captureAmount');
$context = Context::createDefaultContext();
- $criteria = new Criteria([$orderId]);
- $criteria->addAssociation('transactions')
- ->addSorting(new FieldSorting('transactions.createdAt', FieldSorting::DESCENDING));
- $order = $this->orderRepository->search($criteria, $context)->first();
+ $order = $this->getOrder($orderId, $context);
if (!$order) {
return new JsonApiResponse(['success' => false, 'message' => 'Order not found.'], 400);
}
@@ -69,7 +66,6 @@ public function capture(Request $request): JsonApiResponse|Response
return new JsonApiResponse(['success' => false, 'message' => 'The capture amount exceeds the remaining amount.'], 400);
}
- /** @var $order OrderEntity */
$response = $this->paymentService->captureReservation($order, $order->getSalesChannelId(), null, $captureAmount);
$responseAsXml = new \SimpleXMLElement($response->getBody()->getContents());
if ((string)$responseAsXml->Body?->Result === "Success") {
@@ -96,10 +92,7 @@ public function refund(Request $request): JsonApiResponse|Response
$orderId = $request->get('orderId');
$refundAmount = $request->get('refundAmount');
$context = Context::createDefaultContext();
- $criteria = new Criteria([$orderId]);
- $criteria->addAssociation('transactions')
- ->addSorting(new FieldSorting('transactions.createdAt', FieldSorting::DESCENDING));
- $order = $this->orderRepository->search($criteria, $context)->first();
+ $order = $this->getOrder($orderId, $context);
if (!$order) {
return new JsonApiResponse(['success' => false, 'message' => 'Order not found.'], 400);
}
@@ -120,7 +113,6 @@ public function refund(Request $request): JsonApiResponse|Response
return new JsonApiResponse(['success' => false, 'message' => 'The order has already been fully refunded.'], 400);
}
- /** @var $order OrderEntity */
$response = $this->paymentService->refundCapturedReservation(
$order->getCustomFields()[PaymentService::ALTAPAY_TRANSACTION_ID_CUSTOM_FIELD],
$order->getSalesChannelId(),
@@ -149,14 +141,11 @@ public function cancel(Request $request): JsonApiResponse|Response
{
$orderId = $request->get('orderId');
$context = Context::createDefaultContext();
- $criteria = new Criteria([$orderId]);
- $criteria->addAssociation('transactions')
- ->addSorting(new FieldSorting('transactions.createdAt', FieldSorting::DESCENDING));
- $order = $this->orderRepository->search($criteria, $context)->first();
+ $order = $this->getOrder($orderId, $context);
if (!$order) {
return new Response(status: 400);
}
- /** @var $order OrderEntity */
+
$response = $this->paymentService->releaseReservation(
$order->getCustomFields()[PaymentService::ALTAPAY_TRANSACTION_ID_CUSTOM_FIELD],
$order->getSalesChannelId()
@@ -164,10 +153,22 @@ public function cancel(Request $request): JsonApiResponse|Response
$responseAsXml = new \SimpleXMLElement($response->getBody()->getContents());
if ((string)$responseAsXml->Body?->Result === "Success") {
$this->orderTransactionStateHandler->cancel(
- $order->getTransactions()->first()->getId(), // todo get right transaction
+ $order->getTransactions()?->first()->getId(),
$context
);
}
return new JsonApiResponse(json_encode($responseAsXml));
}
+ private function getOrder(string $orderId, ?Context $context = null): ?OrderEntity
+ {
+ if ($context === null) {
+ $context = Context::createDefaultContext();
+ }
+ $criteria = new Criteria([$orderId]);
+ $criteria->addAssociation('transactions')
+ ->addSorting(new FieldSorting('transactions.createdAt', FieldSorting::DESCENDING));
+
+ /** @var ?OrderEntity */
+ return $this->orderRepository->search($criteria, $context)->first();
+ }
}
diff --git a/src/Core/Checkout/Cart/SalesChannel/CartOrderRouteDecorator.php b/src/Core/Checkout/Cart/SalesChannel/CartOrderRouteDecorator.php
index 279e714..8811a07 100644
--- a/src/Core/Checkout/Cart/SalesChannel/CartOrderRouteDecorator.php
+++ b/src/Core/Checkout/Cart/SalesChannel/CartOrderRouteDecorator.php
@@ -52,7 +52,7 @@ protected function restoreCart(Cart $cart, OrderEntity $orderEntity, SalesChanne
->addAssociation('paymentMethod');
- /** @var OrderTransactionEntity $orderTransaction */
+ /** @var OrderTransactionEntity|null $orderTransaction */
$orderTransaction = $this->orderTransactionRepository->search($criteria, $context->getContext())->first();
if ($orderTransaction) {
diff --git a/src/Resources/config/config.xml b/src/Resources/config/config.xml
index 01064a6..70710da 100644
--- a/src/Resources/config/config.xml
+++ b/src/Resources/config/config.xml
@@ -92,4 +92,47 @@
form_checkout_div
+
+ Terminal setup
+
+ terminal1
+
+
+
+ terminal2
+
+
+
+ terminal3
+
+
+
+ terminal4
+
+
+
+ terminal5
+
+
+
+ terminal6
+
+
+
+ terminal7
+
+
+
+ terminal8
+
+
+
+ terminal9
+
+
+
+ terminal10
+
+
+
diff --git a/src/Service/PaymentService.php b/src/Service/PaymentService.php
index c465129..936228c 100644
--- a/src/Service/PaymentService.php
+++ b/src/Service/PaymentService.php
@@ -58,6 +58,7 @@ class PaymentService extends AbstractPaymentHandler
public const ALTAPAY_TRANSACTION_PAYMENT_NATURE_CUSTOM_FIELD = "wexoAltapayTransactionPaymentNature";
public const ALTAPAY_IP_ADDRESS_SET = ["185.206.120.0/24", "2a10:a200::/29", '185.203.232.129', '185.203.233.129']; //NOSONAR
public const ALTAPAY_ORDER_STATUS = "altaPayOrderStatus";
+ public const ALTAPAY_SALES_CHANNEL_TERMINAL_ID = "altapaySalesChannelTerminalId";
public function __construct(
protected readonly SystemConfigService $systemConfigService,
@@ -179,6 +180,18 @@ public function pay(
$paymentMethod = $salesChannelContext->getPaymentMethod();
$terminal = $paymentMethod->getTranslated()['customFields'][self::ALTAPAY_TERMINAL_ID_CUSTOM_FIELD];
+ $salesChannelTerminal = $paymentMethod->getTranslated()['customFields'][self::ALTAPAY_SALES_CHANNEL_TERMINAL_ID];
+
+ if (!empty($salesChannelTerminal)) {
+ $field = 'WexoAltaPay.config.' . $salesChannelTerminal;
+ $salesChannelTerminalValue = $this->systemConfigService->get($field, $order->getSalesChannelId());
+
+ if (!empty($salesChannelTerminalValue)) {
+ $terminal = $salesChannelTerminalValue;
+ }
+
+ }
+
$paymentRequestType = ($paymentMethod->getTranslated()['customFields'][self::ALTAPAY_AUTO_CAPTURE_CUSTOM_FIELD] ?? null) ? 'paymentAndCapture' : 'payment';
try {
$altaPayResponse = $this->createPaymentRequest(
diff --git a/src/Service/Setup/CustomFieldSetupService.php b/src/Service/Setup/CustomFieldSetupService.php
index 6f471be..e9762e6 100644
--- a/src/Service/Setup/CustomFieldSetupService.php
+++ b/src/Service/Setup/CustomFieldSetupService.php
@@ -186,6 +186,60 @@ private function createPaymentMethodCustomField(Context $context): void
context: $context
);
+ $terminals = [];
+ $languages = ['de-DE', 'en-GB', 'da-DK'];
+
+ // Add default empty option
+ $terminals[] = [
+ 'label' => [
+ 'de-DE' => 'Wählen Sie ein Terminal aus',
+ 'en-GB' => 'Select a terminal',
+ 'da-DK' => 'Vælg en terminal',
+ ],
+ 'value' => '',
+ ];
+
+ for ($i = 1; $i <= 10; $i++) {
+ $label = [];
+
+ foreach ($languages as $lang) {
+ $label[$lang] = 'terminal ' . $i;
+ }
+
+ $terminals[] = [
+ 'label' => $label,
+ 'value' => 'terminal' . $i,
+ ];
+ }
+
+ $this->addCustomField(
+ name: PaymentService::ALTAPAY_SALES_CHANNEL_TERMINAL_ID,
+ type: CustomFieldTypes::SELECT,
+ config: [
+ 'customFieldPosition' => 4,
+ 'componentName' => 'sw-single-select',
+ 'customFieldType' => 'select',
+ 'label' => [
+ 'de-DE' => 'Sales Channel - AltaPay Terminal-ID',
+ 'en-GB' => 'Sales Channel - AltaPay Terminal ID',
+ 'da-DK' => 'Sales Channel - AltaPay Terminal-ID',
+ ],
+ 'placeholder' => [
+ 'de-DE' => 'Wählen Sie ein Terminal aus...',
+ 'en-GB' => 'Select a terminal...',
+ 'da-DK' => 'Vælg en terminal...',
+ ],
+ 'helpText' => [
+ 'de-DE' => 'Wählen Sie die Terminal-Konfiguration für den Vertriebskanal aus. Falls leer gelassen, wird die Standard-Terminal-ID aus der Zahlungsmethode verwendet.',
+ 'en-GB' => 'Select the terminal configuration for the sales channel. If left empty, the default terminal ID from the payment method will be used.',
+ 'da-DK' => 'Vælg terminal-konfigurationen for salgskanalen. Hvis den efterlades tom, vil standard terminal-ID fra betalingsmetoden blive brugt.',
+ ],
+ 'options' => $terminals,
+ ],
+ customFieldSetId: $fieldSetId,
+ context: $context
+ );
+
}
private function addCustomField(
diff --git a/src/Subscriber/PaymentMethodSubscriber.php b/src/Subscriber/PaymentMethodSubscriber.php
index 6747df9..7414055 100644
--- a/src/Subscriber/PaymentMethodSubscriber.php
+++ b/src/Subscriber/PaymentMethodSubscriber.php
@@ -4,6 +4,7 @@
use Shopware\Core\Checkout\Payment\Cart\PaymentHandler\DefaultPayment;
use Shopware\Core\Checkout\Payment\PaymentEvents;
+use Shopware\Core\Checkout\Payment\PaymentMethodCollection;
use Shopware\Core\Checkout\Payment\PaymentMethodEntity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
@@ -16,6 +17,9 @@
class PaymentMethodSubscriber implements EventSubscriberInterface
{
+ /**
+ * @param EntityRepository $paymentMethodRepository
+ */
public function __construct(
protected EntityRepository $paymentMethodRepository,
protected PluginIdProvider $pluginIdProvider
diff --git a/src/WexoAltaPay.php b/src/WexoAltaPay.php
index 51615b6..e7cf9d5 100644
--- a/src/WexoAltaPay.php
+++ b/src/WexoAltaPay.php
@@ -21,7 +21,7 @@ class WexoAltaPay extends Plugin
public const ALTAPAY_FIELD_SET_NAME = "wexoAltaPay";
public const ALTAPAY_PAYMENT_METHOD_FIELD_SET_NAME = "wexoAltaPayPaymentMethod";
public const ALTAPAY_CART_TOKEN = "wexoAltaPayCartToken";
- public const ALTAPAY_PLUGIN_VERSION = '2.0.8';
+ public const ALTAPAY_PLUGIN_VERSION = '2.0.9';
public const ALTAPAY_PLUGIN_NAME = 'WexoAltaPay';
public function update(UpdateContext $updateContext): void
diff --git a/wiki.md b/wiki.md
index e5f11e9..85d2f29 100644
--- a/wiki.md
+++ b/wiki.md
@@ -81,6 +81,7 @@ be provided by AltaPay.

+7. Enter the terminal names from your AltaPay account that you want to use for specific sales channels in the **Terminal Setup** section. Link these terminals from the Payment Method page.
## Add Payment Methods
@@ -107,19 +108,21 @@ be provided by AltaPay.
8. Once saved, a new section, **Custom fields**, will appear with the options **AltaPay Terminal ID**(where you must enter the terminal name from AltaPay), **Auto Capture**, and **Surcharge**.

-9. Click the **Save** button again.
+9. Select a sales channel-specific terminal configuration. If left empty, the default terminal ID (from the field above) will be used.
-10. Now click on your desired shop from the **Sales Channels** menu on the left.
+10. Click the **Save** button again.
+
+11. Now click on your desired shop from the **Sales Channels** menu on the left.
-11. In the **General** tab, scroll down to the **Payment and shipping** section & search by name for the payment method you just created.
+12. In the **General** tab, scroll down to the **Payment and shipping** section & search by name for the payment method you just created.

-12. Choose the payment method and click Save button in the top-right corner.
+13. Choose the payment method and click Save button in the top-right corner.

-13. Once the payment methods are configured, you will be ready to process transactions through AltaPay.
+14. Once the payment methods are configured, you will be ready to process transactions through AltaPay.
