Skip to content

Commit

Permalink
PAYOSWXP-115: amazon pay: add payment method for additional pay button
Browse files Browse the repository at this point in the history
  • Loading branch information
rommelfreddy committed Feb 19, 2024
1 parent 5ad672f commit d982ae0
Show file tree
Hide file tree
Showing 31 changed files with 374 additions and 94 deletions.
96 changes: 96 additions & 0 deletions src/Components/AmazonPay/ButtonConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);

namespace PayonePayment\Components\AmazonPay;

use PayonePayment\Components\ConfigReader\ConfigReader;
use RuntimeException;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\System\Language\LanguageEntity;
use Shopware\Core\System\SalesChannel\SalesChannelContext;

class ButtonConfiguration
{
private const DEFAULT_PUBLIC_KEY = 'AE5E5B7B2SAERURYEH6DKDAZ';

public function __construct(
private readonly ConfigReader $configReader,
private readonly EntityRepository $languageRepository
) {
}

public function getButtonConfiguration(
SalesChannelContext $context,
string $location,
array $addPayData,
bool $isExpress,
?float $totalAmount = null,
?string $currencyIso = null,
): ArrayStruct {
$config = $this->configReader->read($context->getSalesChannelId());

$payloadJson = $addPayData['payload'];

$payload = json_decode($payloadJson, true);
if ($totalAmount === null) {
$totalAmount = (float)$payload['paymentDetails']['totalOrderAmount']['amount'];
}

if ($currencyIso === null) {
$currencyIso = $payload['paymentDetails']['totalOrderAmount']['currencyCode'];
}

return new ArrayStruct([
'sandbox' => $config->get('transactionMode') === 'test',
'merchantId' => $config->get(sprintf('%sAmazonMerchantId', $isExpress ? 'amazonPayExpress' : 'amazonPay')),
'publicKeyId' => $addPayData['publickeyid'] ?? self::DEFAULT_PUBLIC_KEY,
'ledgerCurrency' => $currencyIso,
'checkoutLanguage' => $this->getLanguageIso($context),
'productType' => 'PayAndShip',
'placement' => $location,
'buttonColor' => $config->get('amazonPayExpressButtonColor' . $location, 'Gold'),
'estimatedOrderAmount' => [
'amount' => $totalAmount,
'currencyCode' => $currencyIso,
],
'createCheckoutSessionConfig' => [
'payloadJSON' => $payloadJson,
'signature' => $addPayData['signature'],
],
]);
}

private function getLanguageIso(SalesChannelContext $context): string
{
$criteria = new Criteria([$context->getLanguageId()]);
$criteria->addAssociation('locale');

/** @var LanguageEntity|null $language */
$language = $this->languageRepository->search($criteria, $context->getContext())->first();

// Amazon does have a region restricted validation of the locale. So we use the currency to match the region
// because the currency is also restricted to the region.
// reference: https://developer.amazon.com/de/docs/amazon-pay-checkout/add-the-amazon-pay-button.html#function-parameters
$currencyCode = $context->getCurrency()->getIsoCode();
if ($currencyCode === 'EUR' || $currencyCode === 'GBP') {
$locale = $language?->getLocale() ? $language->getLocale()->getCode() : throw new RuntimeException('missing language');

return match (explode('-', $locale)[0]) {
'de' => 'de_DE',
'fr' => 'fr_FR',
'it' => 'it_IT',
'es' => 'es_ES',
default => 'en_GB'
};
} elseif ($currencyCode === 'USD') {
return 'en_US';
} elseif ($currencyCode === 'JPY') {
return 'ja_JP';
}

throw new RuntimeException('disallowed currency/region: ' . $currencyCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ protected function handleResponse(
$this->dataHandler->saveTransactionData($paymentTransaction, $salesChannelContext->getContext(), $data);
}

protected function getRedirectResponse(array $request, array $response): RedirectResponse
protected function getRedirectResponse(SalesChannelContext $context, array $request, array $response): RedirectResponse
{
if (strtolower((string) $response['status']) === 'redirect') {
return new RedirectResponse($response['redirecturl']);
Expand Down
10 changes: 10 additions & 0 deletions src/DependencyInjection/controllers.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,15 @@
</call>
</service>

<service id="PayonePayment\Storefront\Controller\AmazonPay\AmazonRedirectController" autowire="true">
<call method="setContainer">
<argument type="service" id="service_container"/>
</call>
<call method="setTwig">
<argument type="service" id="twig"/>
</call>
<tag name="controller.service_arguments" />
</service>

</services>
</container>
3 changes: 2 additions & 1 deletion src/DependencyInjection/handler/payment_handler.xml
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@
</service>

<service id="PayonePayment\PaymentHandler\PayoneAmazonPayPaymentHandler"
parent="PayonePayment\PaymentHandler\AbstractAsynchronousPayonePaymentHandler">
parent="PayonePayment\PaymentHandler\AbstractAsynchronousPayonePaymentHandler"
autowire="true">

<tag name="shopware.payment.method.async" />
</service>
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyInjection/listeners.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@
<argument key="$requestParameterFactory" type="service" id="PayonePayment\Payone\RequestParameter\RequestParameterFactory" />
<argument key="$logger" type="service" id="PayonePayment\Util\Logger" />
<argument key="$configReader" type="service" id="PayonePayment\Components\ConfigReader\ConfigReaderInterface" />
<argument key="$languageRepository" type="service" id="language.repository" />
<argument key="$paymentFilterService" type="service" id="payone.payment_filter_method.amazonpay.express" />
<argument key="$cartExtensionService" type="service" id="PayonePayment\Components\GenericExpressCheckout\CartExtensionService"/>
<argument key="$cartService" type="service" id="Shopware\Core\Checkout\Cart\SalesChannel\CartService"/>
<argument key="$connection" type="service" id="Doctrine\DBAL\Connection"/>
<argument key="$buttonConfiguration" type="service" id="PayonePayment\Components\AmazonPay\ButtonConfiguration"/>
<tag name="kernel.event_subscriber"/>
</service>

Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/requestParameter/builder.xml
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@

<service id="PayonePayment\Payone\RequestParameter\Builder\Amazon\AuthorizeRequestParameterBuilder">
<argument key="$configReader" type="service" id="PayonePayment\Components\ConfigReader\ConfigReaderInterface" />
<argument key="$customerRepository" type="service" id="customer.repository" />
<tag name="payone_request_builder"/>
</service>

Expand Down
4 changes: 4 additions & 0 deletions src/DependencyInjection/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,9 @@
<argument key="$salutationRepository" type="service" id="salutation.repository" />
</service>

<service id="PayonePayment\Components\AmazonPay\ButtonConfiguration" autowire="true">
<argument key="$languageRepository" type="service" id="language.repository" />
</service>

</services>
</container>
69 changes: 14 additions & 55 deletions src/EventListener/CheckoutCartAmazonPayExpressEventListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Doctrine\DBAL\Connection;
use Exception;
use PayonePayment\Components\AmazonPay\ButtonConfiguration;
use PayonePayment\Components\ConfigReader\ConfigReaderInterface;
use PayonePayment\Components\GenericExpressCheckout\CartExtensionService;
use PayonePayment\Components\GenericExpressCheckout\Struct\CreateExpressCheckoutSessionStruct;
Expand All @@ -16,15 +17,11 @@
use PayonePayment\Payone\Client\PayoneClientInterface;
use PayonePayment\Payone\RequestParameter\RequestParameterFactory;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Shopware\Core\Checkout\Cart\Cart;
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
use Shopware\Core\Checkout\Payment\PaymentMethodDefinition;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Struct\ArrayStruct;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\Language\LanguageEntity;
use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelPaymentMethod\SalesChannelPaymentMethodDefinition;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
Expand All @@ -38,11 +35,11 @@ public function __construct(
private readonly PayoneClientInterface $payoneClient,
private readonly LoggerInterface $logger,
private readonly ConfigReaderInterface $configReader,
private readonly EntityRepository $languageRepository,
private readonly DefaultPaymentFilterService $paymentFilterService,
private readonly CartExtensionService $cartExtensionService,
private readonly CartService $cartService,
private readonly Connection $connection
private readonly Connection $connection,
private readonly ButtonConfiguration $buttonConfiguration
) {
}

Expand Down Expand Up @@ -102,24 +99,17 @@ public function onCartLoaded(CheckoutCartPageLoadedEvent|OffcanvasCartPageLoaded
$response['workorderid']
);

$event->getPage()->addExtension('payoneAmazonPayExpressButton', new ArrayStruct([
'sandbox' => $config->get('transactionMode') === 'test',
'merchantId' => $config->get('amazonPayExpressAmazonMerchantId'),
'publicKeyId' => 'AE5E5B7B2SAERURYEH6DKDAZ',
'ledgerCurrency' => $event->getSalesChannelContext()->getCurrency()->getIsoCode(),
'checkoutLanguage' => $this->getLanguageIso($event->getSalesChannelContext()),
'productType' => 'PayAndShip',
'placement' => $location,
'buttonColor' => $config->get('amazonPayExpressButtonColor' . $location, 'Gold'),
'estimatedOrderAmount' => [
'amount' => $event->getPage()->getCart()->getPrice()->getTotalPrice(),
'currencyCode' => $event->getSalesChannelContext()->getCurrency()->getIsoCode(),
],
'createCheckoutSessionConfig' => [
'payloadJSON' => $response['addpaydata']['payload'],
'signature' => $response['addpaydata']['signature'],
],
]));
$event->getPage()->addExtension(
'payoneAmazonPayExpressButton',
$this->buttonConfiguration->getButtonConfiguration(
$event->getSalesChannelContext(),
$location,
$response['addpaydata'],
true,
$event->getPage()->getCart()->getPrice()->getTotalPrice(),
$event->getSalesChannelContext()->getCurrency()->getIsoCode(),
)
);
} else {
$this->logger->error('Payone Amazon Pay Express: Can not initiate checkout-session for AmazonPay Button in cart. Error: ' . $response['errorcode'], [
'response' => $response,
Expand Down Expand Up @@ -155,35 +145,4 @@ private function getInitializedPaymentResponse(Cart $cart, array $requestParamet

return $extension instanceof ArrayStruct ? $extension->get(md5($json)) : null;
}

private function getLanguageIso(SalesChannelContext $context): string
{
$criteria = new Criteria([$context->getLanguageId()]);
$criteria->addAssociation('locale');

/** @var LanguageEntity|null $language */
$language = $this->languageRepository->search($criteria, $context->getContext())->first();

// Amazon does have a region restricted validation of the locale. So we use the currency to match the region
// because the currency is also restricted to the region.
// reference: https://developer.amazon.com/de/docs/amazon-pay-checkout/add-the-amazon-pay-button.html#function-parameters
$currencyCode = $context->getCurrency()->getIsoCode();
if ($currencyCode === 'EUR' || $currencyCode === 'GBP') {
$locale = $language?->getLocale() ? $language->getLocale()->getCode() : throw new RuntimeException('missing language');

return match (explode('-', $locale)[0]) {
'de' => 'de_DE',
'fr' => 'fr_FR',
'it' => 'it_IT',
'es' => 'es_ES',
default => 'en_GB'
};
} elseif ($currencyCode === 'USD') {
return 'en_US';
} elseif ($currencyCode === 'JPY') {
return 'ja_JP';
}

throw new RuntimeException('disallowed currency/region: ' . $currencyCode);
}
}
32 changes: 32 additions & 0 deletions src/Migration/Migration1707149845AmazonPayRedirectTable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace PayonePayment\Migration;

use Doctrine\DBAL\Connection;
use Shopware\Core\Framework\Migration\MigrationStep;

class Migration1707149845AmazonPayRedirectTable extends MigrationStep
{
public function getCreationTimestamp(): int
{
return 1_707_149_845;
}

public function update(Connection $connection): void
{
$connection->executeStatement('
CREATE TABLE `payone_amazon_redirect` (
`id` BINARY(16) NOT NULL,
`pay_data` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB;
');
}

public function updateDestructive(Connection $connection): void
{
// implement update destructive
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public function pay(
$this->deviceFingerprintService->deleteDeviceIdentToken();
}

return $this->getRedirectResponse($request, $response);
return $this->getRedirectResponse($salesChannelContext, $request, $response);
}

public function finalize(
Expand Down Expand Up @@ -147,7 +147,7 @@ protected function handleResponse(
$this->dataHandler->saveTransactionData($paymentTransaction, $salesChannelContext->getContext(), $data);
}

protected function getRedirectResponse(array $request, array $response): RedirectResponse
protected function getRedirectResponse(SalesChannelContext $context, array $request, array $response): RedirectResponse
{
return new RedirectResponse($response['redirecturl']);
}
Expand Down
Loading

0 comments on commit d982ae0

Please sign in to comment.