Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ sylius_mollie_shop:
requirements:
_locale: ^[A-Za-z]{2,4}(_([A-Za-z]{4}|[0-9]{3}))?(_([A-Za-z]{2}|[0-9]{3}))?$

sylius_mollie_api_shop:
prefix: "/%sylius.security.api_shop_route%"
resource: "routes/api_shop.yaml"

mollie_refund_integration:
resource: "integration/refund-plugin/routes.php"
prefix: /%sylius_admin.path_name%
17 changes: 17 additions & 0 deletions config/routes/api_shop.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
sylius_mollie_api_shop_order_mollie_methods:
path: orders/{tokenValue}/mollie-methods
methods: ['GET']
defaults:
_controller: sylius_mollie.api.controller.get_mollie_methods

sylius_mollie_api_shop_order_mollie_select_method:
path: orders/{tokenValue}/mollie-methods
methods: ['POST']
defaults:
_controller: sylius_mollie.api.controller.select_mollie_method

sylius_mollie_api_shop_order_mollie_payment_status:
path: orders/{tokenValue}/mollie-status
methods: ['GET']
defaults:
_controller: sylius_mollie.api.controller.get_mollie_status
9 changes: 0 additions & 9 deletions config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,6 @@
</imports>

<services>
<service
id="sylius_mollie.api.payment_configuration_provider.mollie"
class="Sylius\MolliePlugin\Api\MolliePaymentConfigurationProvider"
>
<argument type="service" id="router" />

<tag name="sylius.api.payment_method_handler" />
</service>

<service id="sylius_mollie.refund.guard.mollie_payment_refund" class="Sylius\MolliePlugin\Refund\Guard\PaymentRefundGuard" public="true" >
<argument>%kernel.bundles%</argument>
</service>
Expand Down
68 changes: 68 additions & 0 deletions config/services/api.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8" ?>

<!--

This file is part of the Sylius Mollie Plugin package.

(c) Sylius Sp. z o.o.

For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.

-->

<container
xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
>
<services>
<service
id="sylius_mollie.api.payment_configuration_provider.mollie"
class="Sylius\MolliePlugin\Api\MolliePaymentConfigurationProvider"
>
<argument type="service" id="router" />

<tag name="sylius.api.payment_method_handler" />
</service>

<service id="sylius_mollie.api.controller.get_mollie_methods" class="Sylius\MolliePlugin\Api\Controller\GetMollieMethodsAction" public="true">
<argument type="service" id="sylius_mollie.repository.query.order.by_token_for_available_methods" />
<argument type="service" id="sylius_mollie.payum.checker.mollie_gateway_factory" />
<argument type="service" id="sylius_mollie.resolver.payment_methods" />
<argument type="service" id="liip_imagine.cache.manager" />
</service>

<service id="sylius_mollie.api.controller.select_mollie_method" class="Sylius\MolliePlugin\Api\Controller\SelectMollieMethodAction" public="true">
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="doctrine.orm.entity_manager" />
<argument type="service" id="sylius_mollie.converter.int_to_string" />
<argument type="service" id="router" />
<argument type="service" id="sylius_mollie.resolver.mollie_api_client_key" />
<argument type="service" id="sylius_mollie.payum.checker.mollie_gateway_factory" />
<argument type="service" id="sylius_mollie.provider.payment_description" />
<argument type="service" id="sylius_mollie.resolver.payment_locale" />
<argument type="service" id="sylius_mollie.provider.divisor" />
<argument type="service" id="sylius_mollie.repository.mollie_gateway_config" />
<argument type="service" id="sylius_mollie.repository.mollie_customer" />
<argument type="service" id="sylius_mollie.custom_factory.mollie_subscription" />
<argument type="service" id="sylius_mollie.repository.mollie_subscription" />
<argument type="service" id="sylius_mollie.logger.mollie_logger_action" />
<argument type="service" id="sylius_mollie.converter.order" />
</service>

<service id="sylius_mollie.api.controller.get_mollie_status" class="Sylius\MolliePlugin\Api\Controller\GetMollieStatusAction" public="true">
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="doctrine.orm.entity_manager" />
<argument type="service" id="sylius_mollie.resolver.mollie_api_client_key" />
<argument type="service" id="sylius_abstraction.state_machine" />
<argument type="service" id="sylius_mollie.logger.mollie_logger_action" />
</service>

<service id="sylius_mollie.api.open_api.mollie_documentation_modifier" class="Sylius\MolliePlugin\Api\OpenApi\MollieDocumentationModifier">
<argument>%sylius.security.api_shop_route%</argument>

<tag name="sylius.open_api.modifier" />
</service>
</services>
</container>
5 changes: 5 additions & 0 deletions config/services/repository.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,10 @@
<argument type="service" id="sylius.repository.payment_method" />
</service>
<service id="Sylius\MolliePlugin\Repository\Query\MollieBasedPaymentMethodQueryInterface" alias="sylius_mollie.repository.query.payment_method.mollie_based" />

<service id="sylius_mollie.repository.query.order.by_token_for_available_methods" class="Sylius\MolliePlugin\Repository\Query\OrderByTokenForAvailableMethodsQuery">
<argument type="service" id="sylius.repository.order" />
</service>
<service id="Sylius\MolliePlugin\Repository\Query\OrderByTokenForAvailableMethodsQueryInterface" alias="sylius_mollie.repository.query.order.by_token_for_available_methods" />
</services>
</container>
111 changes: 111 additions & 0 deletions src/Api/Controller/GetMollieMethodsAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

/*
* This file is part of the Sylius Mollie Plugin package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\MolliePlugin\Api\Controller;

use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Sylius\Component\Core\Model\PaymentInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\MolliePlugin\Entity\GatewayConfigInterface;
use Sylius\MolliePlugin\Entity\PaymentSurchargeFeeInterface;
use Sylius\MolliePlugin\Payum\Checker\MollieGatewayFactoryCheckerInterface;
use Sylius\MolliePlugin\Repository\Query\OrderByTokenForAvailableMethodsQueryInterface;
use Sylius\MolliePlugin\Resolver\MolliePaymentsMethodResolver;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

final class GetMollieMethodsAction
{
public function __construct(
private readonly OrderByTokenForAvailableMethodsQueryInterface $orderByTokenForAvailableMethodsQuery,
private readonly MollieGatewayFactoryCheckerInterface $mollieGatewayFactoryChecker,
private readonly MolliePaymentsMethodResolver $molliePaymentsMethodResolver,
private readonly CacheManager $imagineCacheManager,
) {
}

public function __invoke(string $tokenValue): JsonResponse
{
$order = $this->orderByTokenForAvailableMethodsQuery->getOrder($tokenValue);
if (null === $order) {
throw new NotFoundHttpException(sprintf('Order with token "%s" not found', $tokenValue));
}

$payment = $order->getLastPayment();
if (!$payment instanceof PaymentInterface) {
throw new NotFoundHttpException('No payment found');
}

$paymentMethod = $payment->getMethod();
if (!$paymentMethod instanceof PaymentMethodInterface) {
throw new NotFoundHttpException('No payment method found');
}

$gatewayConfig = $paymentMethod->getGatewayConfig();
if (!$gatewayConfig instanceof GatewayConfigInterface) {
throw new NotFoundHttpException('No gateway config found');
}
if (!$this->mollieGatewayFactoryChecker->isMollieGateway($gatewayConfig)) {
throw new BadRequestException('The payment method is not using Mollie');
}

$availableMethods = $this->molliePaymentsMethodResolver->resolve();

$data = $availableMethods['data'];
$images = $availableMethods['image'];
$paymentFees = $availableMethods['paymentFee'];
$result = [];
foreach ($data as $id => $label) {
$result[] = [
'id' => $id,
'label' => $label,
'image' => $this->normalizeImage($images[$id] ?? null),
'paymentFee' => $this->normalizePaymentFee($paymentFees[$id] ?? null),
];
}

return new JsonResponse($result);
}

/**
* @return array{
* type: string|null,
* fixedAmount: float|null,
* percentage: float|null,
* surchargeLimit: float|null,
* }|null
*/
private function normalizePaymentFee(mixed $fee): ?array
{
if ($fee instanceof PaymentSurchargeFeeInterface) {
return [
'type' => $fee->getType(),
'fixedAmount' => $fee->getFixedAmount(),
'percentage' => $fee->getPercentage(),
'surchargeLimit' => $fee->getSurchargeLimit(),
];
}

return null;
}

private function normalizeImage(?string $image): ?string
{
if (null === $image || str_starts_with($image, 'https://') && str_contains($image, 'mollie.com')) {
return $image;
}

return $this->imagineCacheManager->getBrowserPath($image, 'sylius_original');
}
}
97 changes: 97 additions & 0 deletions src/Api/Controller/GetMollieStatusAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

/*
* This file is part of the Sylius Mollie Plugin package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\MolliePlugin\Api\Controller;

use Doctrine\ORM\EntityManagerInterface;
use Mollie\Api\Types\PaymentStatus as MolliePaymentStatus;
use Sylius\Abstraction\StateMachine\StateMachineInterface;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Sylius\Component\Payment\PaymentTransitions;
use Sylius\MolliePlugin\Entity\OrderInterface;
use Sylius\MolliePlugin\Logger\MollieLoggerActionInterface;
use Sylius\MolliePlugin\Resolver\MollieApiClientKeyResolverInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

final class GetMollieStatusAction
{
public function __construct(
private readonly OrderRepositoryInterface $orderRepository,
private readonly EntityManagerInterface $entityManager,
private readonly MollieApiClientKeyResolverInterface $apiKeyResolver,
private readonly StateMachineInterface $stateMachine,
private readonly MollieLoggerActionInterface $logger,
) {
}

public function __invoke(string $tokenValue): JsonResponse
{
$order = $this->orderRepository->findOneByTokenValue($tokenValue);
if (!$order instanceof OrderInterface) {
throw new NotFoundHttpException(sprintf('Order with token "%s" not found', $tokenValue));
}

$payment = $order->getLastPayment();
if (null === $payment) {
throw new NotFoundHttpException('No payment found for this order');
}

$details = $payment->getDetails();
$molliePaymentId = $details['payment_mollie_id'] ?? null;
if (null === $molliePaymentId) {
$this->logger->addNegativeLog(sprintf(
'No Mollie payment ID found in payment details of order with token: %s',
$tokenValue,
));

throw new NotFoundHttpException('No payment found for this order');
}

try {
$mollieApiClient = $this->apiKeyResolver->getClientWithKey($order);
$molliePayment = $mollieApiClient->payments->get($molliePaymentId);
$mollieStatus = $molliePayment->status;
} catch (\Exception $exception) {
$this->logger->addNegativeLog(sprintf('Error fetching Mollie payment status: %s', $exception->getMessage()));

return new JsonResponse([
'error' => 'Could not retrieve Mollie payment status',
], Response::HTTP_INTERNAL_SERVER_ERROR);
}

$transition = $this->mapMolliePaymentStatusToTransition($mollieStatus);

if (null !== $transition && $this->stateMachine->can($payment, PaymentTransitions::GRAPH, $transition)) {
$this->stateMachine->apply($payment, PaymentTransitions::GRAPH, $transition);
$this->entityManager->flush();
}

return new JsonResponse([
'paymentState' => $payment->getState(),
]);
}

private function mapMolliePaymentStatusToTransition(string $status): ?string
{
return match ($status) {
MolliePaymentStatus::STATUS_PENDING, MolliePaymentStatus::STATUS_OPEN => PaymentTransitions::TRANSITION_PROCESS,
MolliePaymentStatus::STATUS_AUTHORIZED => PaymentTransitions::TRANSITION_AUTHORIZE,
MolliePaymentStatus::STATUS_PAID => PaymentTransitions::TRANSITION_COMPLETE,
MolliePaymentStatus::STATUS_CANCELED => PaymentTransitions::TRANSITION_CANCEL,
MolliePaymentStatus::STATUS_EXPIRED, MolliePaymentStatus::STATUS_FAILED => PaymentTransitions::TRANSITION_FAIL,
default => null,
};
}
}
Loading