Skip to content

Commit

Permalink
Make it possible to initialize an Apple Pay payment session via API (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
lchrusciel authored Oct 22, 2024
2 parents 7915c43 + 6cb2d14 commit 690f433
Show file tree
Hide file tree
Showing 32 changed files with 615 additions and 87 deletions.
27 changes: 27 additions & 0 deletions config/api_resources/order.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,33 @@
- 'commerce_weavers_sylius_tpay:shop:order:pay'
openapi_context:
summary: 'Pay for the order'
shop_initialize_apple_pay_session:
method: 'POST'
path: '/shop/orders/{tokenValue}/apple-pay-session'
messenger: 'input'
input: 'CommerceWeavers\SyliusTpayPlugin\Api\Command\InitializeApplePaySession'
status: 201
denormalization_context:
groups:
- 'commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session'
normalization_context:
groups:
- 'commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session_result'
validation_groups:
- 'commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session'
openapi_context:
summary: 'Initialize Apple Pay payment session'
parameters:
- name: tokenValue
in: path
required: true
schema:
type: string
- name: paymentId
in: path
required: true
schema:
type: integer
shop_cancel_last_payment:
method: 'PATCH'
path: '/shop/orders/{tokenValue}/cancel-last-payment'
Expand Down
4 changes: 3 additions & 1 deletion config/config/api_platform.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use CommerceWeavers\SyliusTpayPlugin\Api\Command\Exception\OrderCannotBeFoundException;
use CommerceWeavers\SyliusTpayPlugin\Api\Factory\Exception\UnresolvableNextCommandException;
use CommerceWeavers\SyliusTpayPlugin\Payment\Exception\PaymentCannotBeCancelledException;

return function(ContainerConfigurator $configurator): void {
$configurator->extension('api_platform', [
'exception_to_status' => [
UnresolvableNextCommandException::class => 400,
OrderCannotBeFoundException::class => 404,
PaymentCannotBeCancelledException::class => 400,
UnresolvableNextCommandException::class => 400,
],
'mapping' => [
'paths' => [
Expand Down
18 changes: 18 additions & 0 deletions config/serialization/InitializeApplePaySession.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" ?>

<serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
>
<class name="CommerceWeavers\SyliusTpayPlugin\Api\Command\InitializeApplePaySession">
<attribute name="domainName">
<group>commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session</group>
</attribute>
<attribute name="displayName">
<group>commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session</group>
</attribute>
<attribute name="validationUrl">
<group>commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session</group>
</attribute>
</class>
</serializer>
15 changes: 15 additions & 0 deletions config/serialization/InitializeApplePaySessionResult.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" ?>

<serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
>
<class name="CommerceWeavers\SyliusTpayPlugin\Api\Command\InitializeApplePaySessionResult">
<attribute name="result">
<group>commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session_result</group>
</attribute>
<attribute name="session">
<group>commerce_weavers_sylius_tpay:shop:order:payment:initialize_apple_pay_session_result</group>
</attribute>
</class>
</serializer>
9 changes: 9 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Payum\Core\Gateway;

return function(ContainerConfigurator $container): void {
$container->import('services/**/*.php');

$services = $container->services();

$services->set('commerce_weavers_sylius_tpay.gateway', Gateway::class)
->factory([service('payum'), 'getGateway'])
->args(['tpay'])
;
};
12 changes: 11 additions & 1 deletion config/services/api/command.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use CommerceWeavers\SyliusTpayPlugin\Api\Command\AbstractPayByHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\InitializeApplePaySessionHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByApplePayHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByBlikHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByCardHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByLinkHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByGooglePayHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByLinkHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByRedirectHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayByVisaMobileHandler;
use CommerceWeavers\SyliusTpayPlugin\Api\Command\PayHandler;
Expand Down Expand Up @@ -45,6 +46,15 @@
])
;

$services->set('commerce_weavers_sylius_tpay.api.command.initialize_apple_pay_session_handler', InitializeApplePaySessionHandler::class)
->args([
service('sylius.repository.order'),
service('commerce_weavers_sylius_tpay.gateway'),
service('commerce_weavers_sylius_tpay.payum.factory.initialize_apple_pay_payment'),
])
->tag('messenger.message_handler')
;

$services->set('commerce_weavers_sylius_tpay.api.command.pay_by_apple_pay_handler', PayByApplePayHandler::class)
->parent('commerce_weavers_sylius_tpay.api.command.abstract_pay_by_handler')
->tag('messenger.message_handler')
Expand Down
2 changes: 0 additions & 2 deletions config/services/api/context_builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use CommerceWeavers\SyliusTpayPlugin\Api\Serializer\ContextBuilder\OrderTokenAwareContextBuilder;
use CommerceWeavers\SyliusTpayPlugin\Api\Serializer\ContextBuilder\OrderTokenAwareContextBuilderInterface;

return function(ContainerConfigurator $container): void {
$services = $container->services();
Expand All @@ -15,6 +14,5 @@
->args([
service('.inner'),
])
->alias(OrderTokenAwareContextBuilderInterface::class, 'commerce_weavers_sylius_tpay.api.serializer.context_builder.order_token_aware.inner')
;
};
7 changes: 7 additions & 0 deletions config/services/api/doctrine.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@

use CommerceWeavers\SyliusTpayPlugin\Api\Doctrine\QueryItemExtension\OrderShopUserItemExtension;
use CommerceWeavers\SyliusTpayPlugin\Api\Doctrine\QueryItemExtension\OrderVisitorItemExtension;
use CommerceWeavers\SyliusTpayPlugin\Api\Doctrine\QueryItemExtension\Provider\AllowedOrderOperationsProvider;
use CommerceWeavers\SyliusTpayPlugin\Api\Doctrine\QueryItemExtension\Provider\AllowedOrderOperationsProviderInterface;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;

return function(ContainerConfigurator $container): void {
$services = $container->services();
$services->set('commerce_weavers_sylius_tpay.api.doctrine.query_item_extension.provider.allowed_order_operations', AllowedOrderOperationsProvider::class)
->alias(AllowedOrderOperationsProviderInterface::class, 'commerce_weavers_sylius_tpay.api.doctrine.query_item_extension.provider.allowed_order_operations')
;

$services->set('commerce_weavers_sylius_tpay.api.doctrine.query_item_extension.order_shop_user', OrderShopUserItemExtension::class)
->decorate(\Sylius\Bundle\ApiBundle\Doctrine\QueryItemExtension\OrderShopUserItemExtension::class)
->args([
service('.inner'),
service(UserContextInterface::class),
service('commerce_weavers_sylius_tpay.api.doctrine.query_item_extension.provider.allowed_order_operations'),
])
;

Expand All @@ -24,6 +30,7 @@
->args([
service('.inner'),
service(UserContextInterface::class),
service('commerce_weavers_sylius_tpay.api.doctrine.query_item_extension.provider.allowed_order_operations'),
])
;
};
6 changes: 6 additions & 0 deletions config/services/payum/factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\CreateTransactionFactory;
use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\CreateTransactionFactoryInterface;
use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\InitializeApplePayPaymentFactory;
use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\InitializeApplePayPaymentFactoryInterface;
use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\NotifyDataFactory;
use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\NotifyDataFactoryInterface;
use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\NotifyFactory;
Expand Down Expand Up @@ -33,6 +35,10 @@
->alias(CreateTransactionFactoryInterface::class, 'commerce_weavers_sylius_tpay.payum.factory.create_transaction')
;

$services->set('commerce_weavers_sylius_tpay.payum.factory.initialize_apple_pay_payment', InitializeApplePayPaymentFactory::class)
->alias(InitializeApplePayPaymentFactoryInterface::class, 'commerce_weavers_sylius_tpay.payum.factory.initialize_apple_pay_payment')
;

$services->set('commerce_weavers_sylius_tpay.payum.factory.notify_data', NotifyDataFactory::class)
->alias(NotifyDataFactoryInterface::class, 'commerce_weavers_sylius_tpay.payum.factory.notify_data')
;
Expand Down
10 changes: 10 additions & 0 deletions src/Api/Command/Contract/PaymentIdAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Api\Command\Contract;

interface PaymentIdAwareInterface
{
public static function getPaymentIdPropertyName(): string;
}
9 changes: 9 additions & 0 deletions src/Api/Command/Exception/OrderCannotBeFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Api\Command\Exception;

class OrderCannotBeFoundException extends \RuntimeException
{
}
23 changes: 23 additions & 0 deletions src/Api/Command/InitializeApplePaySession.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Api\Command;

use CommerceWeavers\SyliusTpayPlugin\Api\Command\Contract\OrderTokenAwareInterface;

final class InitializeApplePaySession implements OrderTokenAwareInterface
{
public function __construct(
public readonly string $orderToken,
public readonly string $domainName,
public readonly string $displayName,
public readonly string $validationUrl,
) {
}

public static function getOrderTokenPropertyName(): string
{
return 'orderToken';
}
}
57 changes: 57 additions & 0 deletions src/Api/Command/InitializeApplePaySessionHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Api\Command;

use CommerceWeavers\SyliusTpayPlugin\Api\Command\Exception\OrderCannotBeFoundException;
use CommerceWeavers\SyliusTpayPlugin\Payum\Factory\InitializeApplePayPaymentFactoryInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\GatewayInterface;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Webmozart\Assert\Assert;

#[AsMessageHandler]
final class InitializeApplePaySessionHandler
{
public function __construct(
private readonly OrderRepositoryInterface $orderRepository,
private readonly GatewayInterface $gateway,
private readonly InitializeApplePayPaymentFactoryInterface $initializeApplePayPaymentFactory,
) {
}

public function __invoke(InitializeApplePaySession $command): InitializeApplePaySessionResult
{
$this->verifyOrderExist($command->orderToken);

$this->gateway->execute(
$this->initializeApplePayPaymentFactory->createNewWithModelAndOutput(
new ArrayObject([
'domainName' => $command->domainName,
'displayName' => $command->displayName,
'validationUrl' => $command->validationUrl,
]),
$output = new ArrayObject(),
),
);

Assert::string($output['result']);
Assert::string($output['session']);

return new InitializeApplePaySessionResult(
$output['result'],
$output['session'],
);
}

private function verifyOrderExist(string $orderToken): void
{
$order = $this->orderRepository->findOneByTokenValue($orderToken);

if (null === $order) {
throw new OrderCannotBeFoundException(sprintf('Order with token "%s" cannot be found.', $orderToken));
}
}
}
14 changes: 14 additions & 0 deletions src/Api/Command/InitializeApplePaySessionResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace CommerceWeavers\SyliusTpayPlugin\Api\Command;

final class InitializeApplePaySessionResult
{
public function __construct(
public readonly string $result,
public readonly string $session,
) {
}
}
16 changes: 3 additions & 13 deletions src/Api/Doctrine/QueryItemExtension/OrderShopUserItemExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface as LegacyQueryNameGeneratorInterface;
use CommerceWeavers\SyliusTpayPlugin\Api\Doctrine\QueryItemExtension\Provider\AllowedOrderOperationsProviderInterface;
use Doctrine\ORM\QueryBuilder;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\ShopUserInterface;

final class OrderShopUserItemExtension implements QueryItemExtensionInterface
{
public const SHOP_PAY_OPERATION = 'shop_pay';

public const SHOP_CANCEL_LAST_PAYMENT_OPERATION = 'shop_cancel_last_payment';

public function __construct(
private readonly QueryItemExtensionInterface $decorated,
private readonly UserContextInterface $userContext,
private readonly AllowedOrderOperationsProviderInterface $allowedOrderOperationsProvider,
) {
}

Expand All @@ -35,7 +33,7 @@ public function applyToItem(
return;
}

if (!in_array($operationName, $this->getAllowedOperations(), true)) {
if (!in_array($operationName, $this->allowedOrderOperationsProvider->provide(), true)) {
$this->decorated->applyToItem($queryBuilder, $queryNameGenerator, $resourceClass, $identifiers, $operationName, $context);

return;
Expand All @@ -61,12 +59,4 @@ public function applyToItem(
->setParameter($customerParameterName, $customer->getId())
;
}

/**
* @return array<string>
*/
private function getAllowedOperations(): array
{
return [self::SHOP_PAY_OPERATION, self::SHOP_CANCEL_LAST_PAYMENT_OPERATION];
}
}
Loading

0 comments on commit 690f433

Please sign in to comment.