diff --git a/src/Controller/StoreApi/Config/ConfigControllerBase.php b/src/Controller/StoreApi/Config/ConfigControllerBase.php
new file mode 100644
index 000000000..d7335c766
--- /dev/null
+++ b/src/Controller/StoreApi/Config/ConfigControllerBase.php
@@ -0,0 +1,94 @@
+settingsService = $settingsService;
+ $this->configService = $configService;
+ $this->salesChannelLocale = $salesChannelLocale;
+ $this->logger = $logger;
+ }
+
+
+ /**
+ * @Route("/store-api/mollie/config", name="store-api.mollie.config", methods={"GET"})
+ *
+ * @param SalesChannelContext $context
+ * @throws \Exception
+ * @return StoreApiResponse
+ */
+ public function getConfig(SalesChannelContext $context): StoreApiResponse
+ {
+ try {
+ $scId = $context->getSalesChannelId();
+
+ $settings = $this->settingsService->getSettings($scId);
+
+ $profileId = (string)$settings->getProfileId();
+ $locale = $this->salesChannelLocale->getLocale($context);
+
+ if (empty($profileId)) {
+ # if its somehow not yet loaded (plugin config in admin when clicking save)
+ # then load it right now
+ $this->configService->fetchProfileId($scId);
+
+ $settings = $this->settingsService->getSettings($scId);
+ $profileId = (string)$settings->getProfileId();
+ }
+
+ return new ConfigResponse(
+ $profileId,
+ $settings->isTestMode(),
+ $locale
+ );
+ } catch (\Exception $e) {
+ $this->logger->error(
+ 'Error when fetching config in Store API: ' . $e->getMessage(),
+ [
+ 'error' => $e,
+ ]
+ );
+
+ throw $e;
+ }
+ }
+}
diff --git a/src/Controller/StoreApi/Config/Response/ConfigResponse.php b/src/Controller/StoreApi/Config/Response/ConfigResponse.php
new file mode 100644
index 000000000..37565db8a
--- /dev/null
+++ b/src/Controller/StoreApi/Config/Response/ConfigResponse.php
@@ -0,0 +1,34 @@
+
+ */
+ protected $object;
+
+
+ /**
+ * @param string $profileId
+ * @param bool $isTestMode
+ * @param string $defaultLocale
+ */
+ public function __construct(string $profileId, bool $isTestMode, string $defaultLocale)
+ {
+ $this->object = new ArrayStruct(
+ [
+ 'profileId' => $profileId,
+ 'testMode' => $isTestMode,
+ 'locale' => $defaultLocale,
+ ],
+ 'mollie_payments_config'
+ );
+
+ parent::__construct($this->object);
+ }
+}
diff --git a/src/Controller/StoreApi/Config/Sw6/ConfigController.php b/src/Controller/StoreApi/Config/Sw6/ConfigController.php
new file mode 100644
index 000000000..bdc470999
--- /dev/null
+++ b/src/Controller/StoreApi/Config/Sw6/ConfigController.php
@@ -0,0 +1,14 @@
+languageRepository->search($criteria, $context);
}
+
+ /**
+ * @param string $languageId
+ * @param Context $context
+ * @return null|LanguageEntity
+ */
+ public function findById(string $languageId, Context $context): ?LanguageEntity
+ {
+ $languageCriteria = new Criteria();
+ $languageCriteria->addAssociation('locale');
+ $languageCriteria->addFilter(new EqualsFilter('id', $languageId));
+
+ $languagesResult = $this->search($languageCriteria, $context);
+
+ return $languagesResult->first();
+ }
}
diff --git a/src/Repository/Language/LanguageRepositoryInterface.php b/src/Repository/Language/LanguageRepositoryInterface.php
index af18d99f0..d772d82c3 100644
--- a/src/Repository/Language/LanguageRepositoryInterface.php
+++ b/src/Repository/Language/LanguageRepositoryInterface.php
@@ -6,6 +6,7 @@
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
+use Shopware\Core\System\Language\LanguageEntity;
interface LanguageRepositoryInterface
{
@@ -15,4 +16,11 @@ interface LanguageRepositoryInterface
* @return EntitySearchResult
*/
public function search(Criteria $criteria, Context $context): EntitySearchResult;
+
+ /**
+ * @param string $languageId
+ * @param Context $context
+ * @return null|LanguageEntity
+ */
+ public function findById(string $languageId, Context $context): ?LanguageEntity;
}
diff --git a/src/Resources/config/compatibility/controller.xml b/src/Resources/config/compatibility/controller.xml
index 60e9ee634..c07eed50c 100644
--- a/src/Resources/config/compatibility/controller.xml
+++ b/src/Resources/config/compatibility/controller.xml
@@ -185,6 +185,13 @@
+
+
+
+
+
+
+
diff --git a/src/Resources/config/compatibility/controller_6.5.xml b/src/Resources/config/compatibility/controller_6.5.xml
index ef39bd795..933fd6fe1 100644
--- a/src/Resources/config/compatibility/controller_6.5.xml
+++ b/src/Resources/config/compatibility/controller_6.5.xml
@@ -153,14 +153,16 @@
-
+
-
+
@@ -176,7 +178,8 @@
-
+
@@ -190,7 +193,15 @@
-
+
+
+
+
+
+
+
+
@@ -207,7 +218,8 @@
-
+
diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml
index c15ad23e6..da475d575 100644
--- a/src/Resources/config/services.xml
+++ b/src/Resources/config/services.xml
@@ -148,9 +148,9 @@
-
+
diff --git a/src/Resources/config/services/services.xml b/src/Resources/config/services/services.xml
index 4c32a5a86..0a77f60ad 100644
--- a/src/Resources/config/services/services.xml
+++ b/src/Resources/config/services/services.xml
@@ -147,6 +147,10 @@
+
+
+
+
diff --git a/src/Service/ConfigService.php b/src/Service/ConfigService.php
index 30396b3ee..1fa104f88 100644
--- a/src/Service/ConfigService.php
+++ b/src/Service/ConfigService.php
@@ -3,6 +3,7 @@
namespace Kiener\MolliePayments\Service;
use Kiener\MolliePayments\Gateway\MollieGatewayInterface;
+use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
class ConfigService
diff --git a/src/Service/SalesChannel/SalesChannelLocale.php b/src/Service/SalesChannel/SalesChannelLocale.php
new file mode 100644
index 000000000..172d63b40
--- /dev/null
+++ b/src/Service/SalesChannel/SalesChannelLocale.php
@@ -0,0 +1,79 @@
+repoLanguages = $repoLanguages;
+ }
+
+
+ /**
+ * @param SalesChannelContext $salesChannelContext
+ * @return string
+ */
+ public function getLocale(SalesChannelContext $salesChannelContext): string
+ {
+ # Get the language object from the sales channel context.
+ $locale = '';
+
+ $salesChannel = $salesChannelContext->getSalesChannel();
+ $languageId = $salesChannel->getLanguageId();
+
+ $language = $this->repoLanguages->findById($languageId, $salesChannelContext->getContext());
+
+ if ($language !== null && $language->getLocale() !== null) {
+ $locale = $language->getLocale()->getCode();
+ }
+
+ # Set the locale based on the current storefront.
+ if ($locale !== null && $locale !== '') {
+ $locale = str_replace('-', '_', $locale);
+ }
+
+ # Check if the shop locale is available.
+ if ($locale === '' || !in_array($locale, self::AVAILABLE_LOCALES, true)) {
+ $locale = 'en_GB';
+ }
+
+ return $locale;
+ }
+}
diff --git a/src/Subscriber/CheckoutConfirmPageSubscriber.php b/src/Subscriber/CheckoutConfirmPageSubscriber.php
index 9c62e8db9..2a2755fb6 100644
--- a/src/Subscriber/CheckoutConfirmPageSubscriber.php
+++ b/src/Subscriber/CheckoutConfirmPageSubscriber.php
@@ -12,6 +12,7 @@
use Kiener\MolliePayments\Service\CustomerService;
use Kiener\MolliePayments\Service\CustomFieldService;
use Kiener\MolliePayments\Service\MandateServiceInterface;
+use Kiener\MolliePayments\Service\SalesChannel\SalesChannelLocale;
use Kiener\MolliePayments\Service\SettingsService;
use Kiener\MolliePayments\Setting\MollieSettingStruct;
use Kiener\MolliePayments\Struct\PaymentMethod\PaymentMethodAttributes;
@@ -52,10 +53,9 @@ class CheckoutConfirmPageSubscriber implements EventSubscriberInterface
private $settings;
/**
- * @var LanguageRepositoryInterface
+ * @var SalesChannelLocale
*/
- private $repoLanguages;
-
+ private $salesChannelLocale;
/**
* @var MandateServiceInterface
@@ -88,17 +88,17 @@ public static function getSubscribedEvents(): array
/**
* @param MollieApiFactory $apiFactory
* @param SettingsService $settingsService
- * @param LanguageRepositoryInterface $languageRepositoryInterface
* @param MandateServiceInterface $mandateService
* @param MollieGatewayInterface $mollieGateway
+ * @param SalesChannelLocale $salesChannelLocale
*/
- public function __construct(MollieApiFactory $apiFactory, SettingsService $settingsService, LanguageRepositoryInterface $languageRepositoryInterface, MandateServiceInterface $mandateService, MollieGatewayInterface $mollieGateway)
+ public function __construct(MollieApiFactory $apiFactory, SettingsService $settingsService, MandateServiceInterface $mandateService, MollieGatewayInterface $mollieGateway, SalesChannelLocale $salesChannelLocale)
{
$this->apiFactory = $apiFactory;
$this->settingsService = $settingsService;
- $this->repoLanguages = $languageRepositoryInterface;
$this->mandateService = $mandateService;
$this->mollieGateway = $mollieGateway;
+ $this->salesChannelLocale = $salesChannelLocale;
}
@@ -114,7 +114,7 @@ public function addDataToPage($args): void
$mollieAttributes = new PaymentMethodAttributes($currentSelectedPaymentMethod);
# load additional data only for mollie payment methods
- if (! $mollieAttributes->isMolliePayment()) {
+ if (!$mollieAttributes->isMolliePayment()) {
return;
}
@@ -144,75 +144,9 @@ public function addDataToPage($args): void
*/
private function addMollieLocaleVariableToPage($args): void
{
- /**
- * Build an array of available locales.
- */
- $availableLocales = [
- 'en_US',
- 'en_GB',
- 'nl_NL',
- 'fr_FR',
- 'it_IT',
- 'de_DE',
- 'de_AT',
- 'de_CH',
- 'es_ES',
- 'ca_ES',
- 'nb_NO',
- 'pt_PT',
- 'sv_SE',
- 'fi_FI',
- 'da_DK',
- 'is_IS',
- 'hu_HU',
- 'pl_PL',
- 'lv_LV',
- 'lt_LT'
- ];
-
- /**
- * Get the language object from the sales channel context.
- */
- $locale = '';
-
$salesChannelContext = $args->getSalesChannelContext();
-
- $salesChannel = $salesChannelContext->getSalesChannel();
- if ($salesChannel !== null) {
- $languageId = $salesChannel->getLanguageId();
- if ($languageId !== null) {
- $languageCriteria = new Criteria();
- $languageCriteria->addAssociation('locale');
- $languageCriteria->addFilter(new EqualsFilter('id', $languageId));
-
- $languagesResult = $this->repoLanguages->search($languageCriteria, $args->getContext());
- /** @var LanguageEntity $language */
- $language = $languagesResult->first();
-
- if ($language !== null && $language->getLocale() !== null) {
- $locale = $language->getLocale()->getCode();
- }
- }
- }
-
-
- /**
- * Set the locale based on the current storefront.
- */
-
-
- if ($locale !== null && $locale !== '') {
- $locale = str_replace('-', '_', $locale);
- }
-
- /**
- * Check if the shop locale is available.
- */
- if ($locale === '' || !in_array($locale, $availableLocales, true)) {
- $locale = 'en_GB';
- }
-
+ $locale = $this->salesChannelLocale->getLocale($salesChannelContext);
$args->getPage()->assign([
'mollie_locale' => $locale,
diff --git a/tests/Cypress/cypress/e2e/store-api/config.cy.js b/tests/Cypress/cypress/e2e/store-api/config.cy.js
new file mode 100644
index 000000000..ec78ef665
--- /dev/null
+++ b/tests/Cypress/cypress/e2e/store-api/config.cy.js
@@ -0,0 +1,30 @@
+import StoreAPIClient from "Services/shopware/StoreAPIClient";
+import Shopware from "Services/shopware/Shopware"
+
+const shopware = new Shopware();
+
+const client = new StoreAPIClient(shopware.getStoreApiToken());
+
+
+it('C2040032: Mollie Config can be retrieved using Store-API', () => {
+
+ const request = new Promise((resolve) => {
+ client.get('/mollie/config').then(response => {
+ resolve({'data': response.data});
+ });
+ })
+
+ cy.wrap(request).its('data').then(response => {
+ cy.wrap(response).its('apiAlias').should('eq', 'mollie_payments_config')
+
+ cy.wrap(response).its('profileId').should('exist');
+ cy.wrap(response).its('profileId').should('not.eql', '');
+
+ cy.wrap(response).its('testMode').should('exist');
+ cy.wrap(response).its('testMode').should('not.eql', '');
+
+ cy.wrap(response).its('locale').should('exist');
+ cy.wrap(response).its('locale').should('not.eql', '');
+ });
+})
+
diff --git a/tests/PHPUnit/Fakes/Repositories/FakeLanguageRepository.php b/tests/PHPUnit/Fakes/Repositories/FakeLanguageRepository.php
new file mode 100644
index 000000000..32c45567e
--- /dev/null
+++ b/tests/PHPUnit/Fakes/Repositories/FakeLanguageRepository.php
@@ -0,0 +1,49 @@
+foundLanguage = $foundLanguage;
+ }
+
+
+ /**
+ * @param Criteria $criteria
+ * @param Context $context
+ * @return EntitySearchResult
+ */
+ public function search(Criteria $criteria, Context $context): EntitySearchResult
+ {
+ // TODO: Implement search() method.
+ }
+
+ /**
+ * @param string $languageId
+ * @param Context $context
+ * @return LanguageEntity|null
+ */
+ public function findById(string $languageId, Context $context): ?LanguageEntity
+ {
+ return $this->foundLanguage;
+ }
+
+}
diff --git a/tests/PHPUnit/Service/SalesChannel/SalesChannelLocaleTest.php b/tests/PHPUnit/Service/SalesChannel/SalesChannelLocaleTest.php
new file mode 100644
index 000000000..a2a287fb3
--- /dev/null
+++ b/tests/PHPUnit/Service/SalesChannel/SalesChannelLocaleTest.php
@@ -0,0 +1,158 @@
+fakeSalesChannelContext = $this->getMockBuilder(SalesChannelContext::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+
+ /**
+ * This test verifies that the available locales are correct.
+ * This is a list of possible values that Mollie allows.
+ *
+ * @return void
+ */
+ public function testAvailableLocales(): void
+ {
+ # our data provider has no flat list of values, but we still want to reuse it.
+ # so lets just extract the first internal value of each item to get a flat list
+ # of expected locales.
+ $expected = array_map(function ($list) {
+ return $list[0];
+ }, $this->getAvailableLocales());
+
+ $this->assertEquals($expected, SalesChannelLocale::AVAILABLE_LOCALES);
+ }
+
+
+ /**
+ * @return string[]
+ */
+ public function getAvailableLocales(): array
+ {
+ return [
+ ['en_US'],
+ ['en_GB'],
+ ['nl_NL'],
+ ['fr_FR'],
+ ['it_IT'],
+ ['de_DE'],
+ ['de_AT'],
+ ['de_CH'],
+ ['es_ES'],
+ ['ca_ES'],
+ ['nb_NO'],
+ ['pt_PT'],
+ ['sv_SE'],
+ ['fi_FI'],
+ ['da_DK'],
+ ['is_IS'],
+ ['hu_HU'],
+ ['pl_PL'],
+ ['lv_LV'],
+ ['lt_LT']
+ ];
+ }
+
+ /**
+ * This test verifies that a locale is correctly returned from a sales channel if available.
+ * We fake the repository that returns us a given locale for our sales channel.
+ * That locale is in the list of available locales and should therefore be correctly returned in our function.
+ *
+ * @dataProvider getAvailableLocales
+ *
+ * @param string $locale
+ * @return void
+ */
+ public function testAvailableLocalesAreFound(string $locale): void
+ {
+ $scLanguage = $this->buildSalesChannelLanguage($locale);
+
+ $repoLanguages = new FakeLanguageRepository($scLanguage);
+
+ $service = new SalesChannelLocale($repoLanguages);
+
+ $detectedLocale = $service->getLocale($this->fakeSalesChannelContext);
+
+ $this->assertEquals($locale, $detectedLocale);
+ }
+
+ /**
+ * This test verifies that an invalid locale leads to our default locale which
+ * is en_GB as result.
+ */
+ public function testInvalidLocaleLeadsToEnglishDefault(): void
+ {
+ $scLanguage = $this->buildSalesChannelLanguage('zz_ZZ');
+
+ $repoLanguages = new FakeLanguageRepository($scLanguage);
+
+ $service = new SalesChannelLocale($repoLanguages);
+
+ $detectedLocale = $service->getLocale($this->fakeSalesChannelContext);
+
+ $this->assertEquals('en_GB', $detectedLocale);
+ }
+
+ /**
+ * This test verifies that we get en_GB as default if our sales channel
+ * does not have a locale or language set.
+ *
+ * @return void
+ */
+ public function testSalesChannelWithoutLocale(): void
+ {
+ $repoLanguages = new FakeLanguageRepository(null);
+
+ $service = new SalesChannelLocale($repoLanguages);
+
+ $detectedLocale = $service->getLocale($this->fakeSalesChannelContext);
+
+ $this->assertEquals('en_GB', $detectedLocale);
+ }
+
+ /**
+ * @param string $locale
+ * @return LanguageEntity
+ */
+ private function buildSalesChannelLanguage(string $locale): LanguageEntity
+ {
+ # we always need to make sure to use this pattern nl-NL
+ # this is how it looks like in Shopware
+ $locale = str_replace('_', '-', $locale);
+
+ $foundLocale = new LocaleEntity();
+ $foundLocale->setCode($locale);
+
+ $scLanguage = new LanguageEntity();
+ $scLanguage->setLocale($foundLocale);
+
+ return $scLanguage;
+ }
+
+}
diff --git a/tests/Swagger/mollie-headless.yaml b/tests/Swagger/mollie-headless.yaml
index 3b36ae125..bf27c1471 100644
--- a/tests/Swagger/mollie-headless.yaml
+++ b/tests/Swagger/mollie-headless.yaml
@@ -142,6 +142,18 @@ paths:
"200":
description: "successful operation"
+ /store-api/mollie/config:
+ get:
+ tags:
+ - "Mollie Config"
+ summary: "Gets the basic Mollie configuration like Profile IDs and more for component integration."
+ security:
+ - AccessKey: [ ]
+ - AccessToken: [ ]
+ responses:
+ "200":
+ description: "successful operation"
+
/store-api/mollie/creditcard/store-token/{customerId}/{cardToken}:
post:
tags: