diff --git a/src/Controller/Api/RefundController.php b/src/Controller/Api/RefundController.php
index ce051e802..b7f6b7218 100644
--- a/src/Controller/Api/RefundController.php
+++ b/src/Controller/Api/RefundController.php
@@ -2,387 +2,291 @@
namespace Kiener\MolliePayments\Controller\Api;
-use Exception;
-use Kiener\MolliePayments\Factory\MollieApiFactory;
-use Kiener\MolliePayments\Service\CustomFieldService;
+use Kiener\MolliePayments\Exception\CouldNotCancelMollieRefundException;
+use Kiener\MolliePayments\Exception\CouldNotCreateMollieRefundException;
+use Kiener\MolliePayments\Exception\CouldNotExtractMollieOrderIdException;
+use Kiener\MolliePayments\Exception\CouldNotFetchMollieOrderException;
+use Kiener\MolliePayments\Exception\CouldNotFetchMollieRefundsException;
+use Kiener\MolliePayments\Exception\PaymentNotFoundException;
use Kiener\MolliePayments\Service\OrderService;
+use Kiener\MolliePayments\Service\RefundService;
use Kiener\MolliePayments\Service\SettingsService;
-use Kiener\MolliePayments\Setting\MollieSettingStruct;
-use Mollie\Api\Exceptions\ApiException;
-use Mollie\Api\Exceptions\IncompatiblePlatform;
-use Mollie\Api\MollieApiClient;
-use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
+use Psr\Log\LoggerInterface;
use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStateHandler;
use Shopware\Core\Checkout\Order\OrderEntity;
+use Shopware\Core\Checkout\Payment\Exception\InvalidOrderException;
use Shopware\Core\Framework\Context;
-use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
-use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
-use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
+use Shopware\Core\Framework\ShopwareHttpException;
+use Shopware\Core\Framework\Uuid\Exception\InvalidUuidException;
+use Shopware\Core\Framework\Uuid\Uuid;
+use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
-use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class RefundController extends AbstractController
{
- public const CUSTOM_FIELDS_KEY_REFUNDED_QUANTITY = 'refundedQuantity';
- public const CUSTOM_FIELDS_KEY_CREATE_CREDIT_ITEM = 'createCredit';
-
- private const CUSTOM_FIELDS_KEY_ORDER_ID = 'order_id';
- private const CUSTOM_FIELDS_KEY_ORDER_LINE_ID = 'order_line_id';
- private const CUSTOM_FIELDS_KEY_REFUND_ID = 'refund_id';
- private const CUSTOM_FIELDS_KEY_REFUNDS = 'refunds';
- private const CUSTOM_FIELDS_KEY_QUANTITY = 'quantity';
-
- private const REFUND_DATA_KEY_ID = 'id';
- private const REFUND_DATA_KEY_LINES = 'lines';
- private const REFUND_DATA_KEY_QUANTITY = self::CUSTOM_FIELDS_KEY_QUANTITY;
- private const REFUND_DATA_KEY_TEST_MODE = 'testmode';
-
- private const REQUEST_KEY_ORDER_LINE_ITEM_ID = 'itemId';
- private const REQUEST_KEY_ORDER_LINE_QUANTITY = self::CUSTOM_FIELDS_KEY_QUANTITY;
- private const REQUEST_KEY_ORDER_LINE_ITEM_VERSION_ID = 'versionId';
-
- private const RESPONSE_KEY_AMOUNT = 'amount';
- private const RESPONSE_KEY_ITEMS = 'items';
- private const RESPONSE_KEY_SUCCESS = 'success';
-
- /** @var MollieApiFactory */
- private $apiFactory;
-
- /** @var EntityRepositoryInterface */
- private $orderLineItemRepository;
+ /** @var LoggerInterface */
+ private $logger;
/** @var OrderService */
private $orderService;
- /** @var OrderTransactionStateHandler */
- private $orderTransactionStateHandler;
-
- /** @var SettingsService */
- private $settingsService;
+ /** @var RefundService */
+ private $refundService;
/**
* Creates a new instance of the onboarding controller.
*
- * @param MollieApiFactory $apiFactory
- * @param EntityRepositoryInterface $orderLineItemRepository
+ * @param LoggerInterface $logger
* @param OrderService $orderService
- * @param OrderTransactionStateHandler $orderTransactionStateHandler
- * @param SettingsService $settingsService
+ * @param RefundService $refundService
*/
public function __construct(
- MollieApiFactory $apiFactory,
- EntityRepositoryInterface $orderLineItemRepository,
+ LoggerInterface $logger,
OrderService $orderService,
- OrderTransactionStateHandler $orderTransactionStateHandler,
- SettingsService $settingsService
+ RefundService $refundService
)
{
- $this->apiFactory = $apiFactory;
- $this->orderLineItemRepository = $orderLineItemRepository;
+ $this->logger = $logger;
$this->orderService = $orderService;
- $this->orderTransactionStateHandler = $orderTransactionStateHandler;
- $this->settingsService = $settingsService;
+ $this->refundService = $refundService;
}
/**
* @RouteScope(scopes={"api"})
- * @Route("/api/v{version}/_action/mollie/refund",
+ * @Route("/api/_action/mollie/refund",
* defaults={"auth_enabled"=true}, name="api.action.mollie.refund", methods={"POST"})
*
- * @param Request $request
- *
+ * @param RequestDataBag $data
+ * @param Context $context
* @return JsonResponse
- * @throws ApiException
- * @throws IncompatiblePlatform
*/
- public function refund(Request $request): JsonResponse
+ public function refund(RequestDataBag $data, Context $context): JsonResponse
{
- return $this->getRefundResponse($request);
+ return $this->refundResponse($data->getAlnum('orderId'), $data->get('amount', 0.0), $context);
}
/**
- * refund action for Shopware versions >=6.4
- *
* @RouteScope(scopes={"api"})
- * @Route("/api/mollie/refund",
- * defaults={"auth_enabled"=true}, name="api.action.mollie.refund-64", methods={"POST"})
- *
- * @param Request $request
+ * @Route("/api/v{version}/_action/mollie/refund",
+ * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.legacy", methods={"POST"})
*
+ * @param RequestDataBag $data
+ * @param Context $context
* @return JsonResponse
- * @throws ApiException
- * @throws IncompatiblePlatform
*/
- public function refund64(Request $request): JsonResponse
+ public function refundLegacy(RequestDataBag $data, Context $context): JsonResponse
{
- return $this->getRefundResponse($request);
+ return $this->refundResponse($data->getAlnum('orderId'), $data->get('amount', 0.0), $context);
}
- private function getRefundResponse(Request $request): JsonResponse
+ /**
+ * @RouteScope(scopes={"api"})
+ * @Route("/api/_action/mollie/refund/cancel",
+ * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.cancel", methods={"POST"})
+ *
+ * @param RequestDataBag $data
+ * @param Context $context
+ * @return JsonResponse
+ */
+ public function cancel(RequestDataBag $data, Context $context): JsonResponse
{
- /** @var MollieApiClient|null $apiClient */
- $apiClient = null;
-
- /** @var array|null $customFields */
- $customFields = null;
-
- /** @var string|null $orderId */
- $orderId = null;
-
- /** @var string|null $orderLineId */
- $orderLineId = null;
-
- /** @var OrderLineItemEntity $orderLineItem */
- $orderLineItem = null;
-
- /** @var bool $success */
- $success = false;
-
- /** @var int $quantity */
- $quantity = 0;
-
- if (
- (string)$request->get(self::REQUEST_KEY_ORDER_LINE_ITEM_ID) !== ''
- && (string)$request->get(self::REQUEST_KEY_ORDER_LINE_ITEM_VERSION_ID) !== ''
- ) {
- $orderLineItem = $this->getOrderLineItemById(
- $request->get(self::REQUEST_KEY_ORDER_LINE_ITEM_ID),
- $request->get(self::REQUEST_KEY_ORDER_LINE_ITEM_VERSION_ID)
- );
- }
-
- if ((int)$request->get(self::REQUEST_KEY_ORDER_LINE_QUANTITY) > 0) {
- $quantity = (int)$request->get(self::REQUEST_KEY_ORDER_LINE_QUANTITY);
- }
-
- if (
- $orderLineItem !== null
- && !empty($orderLineItem->getCustomFields())
- ) {
- $customFields = $orderLineItem->getCustomFields();
- }
-
- if (
- $orderLineItem !== null
- && !empty($customFields)
- && isset($customFields[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_ORDER_LINE_ID])
- ) {
- $orderLineId = $customFields[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_ORDER_LINE_ID];
- }
-
- if (
- $orderLineItem !== null
- && $orderLineItem->getOrder() !== null
- && !empty($orderLineItem->getOrder()->getCustomFields())
- && isset($orderLineItem->getOrder()->getCustomFields()[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_ORDER_ID])
- ) {
- $orderId = $orderLineItem->getOrder()->getCustomFields()[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_ORDER_ID];
- }
-
- if ($orderLineItem->getOrder() !== null) {
- $transactions = $orderLineItem->getOrder()->getTransactions();
-
- if ($transactions !== null && $transactions->count()) {
- foreach ($transactions as $transaction) {
- try {
- $this->orderTransactionStateHandler->refundPartially(
- $transaction->getId(),
- Context::createDefaultContext()
- );
- } catch (Exception $e) {
- // @todo Maybe handle this exception in debug mode?
- }
- }
- }
- }
-
- if (
- (string)$orderId !== ''
- && (string)$orderLineId !== ''
- && $quantity > 0
- ) {
- $apiClient = $this->apiFactory->createClient(
- $orderLineItem->getOrder()->getSalesChannelId()
- );
- }
-
- if ($apiClient !== null) {
- /** @var MollieSettingStruct $settings */
- $settings = $this->settingsService->getSettings(
- $orderLineItem->getOrder()->getSalesChannelId()
- );
-
- /** @var array $orderParameters */
- $orderParameters = [];
-
- if ($settings->isTestMode() && $apiClient->usesOAuth()) {
- $orderParameters = [
- self::REFUND_DATA_KEY_TEST_MODE => true
- ];
- }
-
- try {
- $order = $apiClient->orders->get($orderId, $orderParameters);
- } catch (ApiException $e) {
- //
- }
-
- if (isset($order, $order->id)) {
- $refundData = [
- self::REFUND_DATA_KEY_LINES => [
- [
- self::REFUND_DATA_KEY_ID => $orderLineId,
- self::REFUND_DATA_KEY_QUANTITY => $quantity,
- ],
- ],
- ];
-
- if ($settings->isTestMode() && $apiClient->usesOAuth()) {
- $refundData[self::REFUND_DATA_KEY_TEST_MODE] = true;
- }
-
- try {
- $refund = $apiClient->orderRefunds->createFor($order, $refundData);
- } catch (ApiException $e) {
- //
- }
-
- if (isset($refund, $refund->id)) {
- $success = true;
-
- if (!isset($customFields[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_REFUNDS])) {
- $customFields[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_REFUNDS] = [];
- }
-
- if (!is_array($customFields[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_REFUNDS])) {
- $customFields[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_REFUNDS] = [];
- }
-
- $customFields[CustomFieldService::CUSTOM_FIELDS_KEY_MOLLIE_PAYMENTS][self::CUSTOM_FIELDS_KEY_REFUNDS][] = [
- self::CUSTOM_FIELDS_KEY_REFUND_ID => $refund->id,
- self::CUSTOM_FIELDS_KEY_QUANTITY => $quantity,
- ];
-
- if (isset($customFields[self::CUSTOM_FIELDS_KEY_REFUNDED_QUANTITY])) {
- $customFields[self::CUSTOM_FIELDS_KEY_REFUNDED_QUANTITY] += $quantity;
- } else {
- $customFields[self::CUSTOM_FIELDS_KEY_REFUNDED_QUANTITY] = $quantity;
- }
- }
- }
-
- // Update the custom fields of the order line item
- $this->orderLineItemRepository->update([
- [
- self::REFUND_DATA_KEY_ID => $orderLineItem->getId(),
- CustomFieldService::CUSTOM_FIELDS_KEY => $customFields,
- ]
- ], Context::createDefaultContext());
- }
-
- return new JsonResponse([
- self::RESPONSE_KEY_SUCCESS => $success,
- ]);
+ return $this->cancelResponse($data->getAlnum('orderId'), $data->get('refundId'), $context);
}
/**
* @RouteScope(scopes={"api"})
- * @Route("/api/v{version}/_action/mollie/refund/total",
- * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.total", methods={"POST"})
+ * @Route("/api/v{version}/_action/mollie/refund/cancel",
+ * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.cancel.legacy", methods={"POST"})
*
- * @param Request $request
+ * @param RequestDataBag $data
+ * @param Context $context
+ * @return JsonResponse
+ */
+ public function cancelLegacy(RequestDataBag $data, Context $context): JsonResponse
+ {
+ return $this->cancelResponse($data->getAlnum('orderId'), $data->get('refundId'), $context);
+ }
+
+ /**
+ * @RouteScope(scopes={"api"})
+ * @Route("/api/_action/mollie/refund/list",
+ * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.list", methods={"POST"})
*
+ * @param RequestDataBag $data
+ * @param Context $context
* @return JsonResponse
*/
- public function total(Request $request): JsonResponse
+ public function list(RequestDataBag $data, Context $context): JsonResponse
{
- /** @var string|null $orderId */
- $orderId = $request->get('orderId');
+ return $this->listResponse($data->getAlnum('orderId'), $context);
+ }
- return $this->getTotalResponse($orderId);
+ /**
+ * @RouteScope(scopes={"api"})
+ * @Route("/api/v{version}/_action/mollie/refund/list",
+ * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.list.legacy", methods={"POST"})
+ *
+ * @param RequestDataBag $data
+ * @param Context $context
+ * @return JsonResponse
+ */
+ public function listLegacy(RequestDataBag $data, Context $context): JsonResponse
+ {
+ return $this->listResponse($data->getAlnum('orderId'), $context);
}
/**
* @RouteScope(scopes={"api"})
* @Route("/api/_action/mollie/refund/total",
- * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.total-64", methods={"POST"})
- *
- * @param Request $request
+ * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.total", methods={"POST"})
*
+ * @param RequestDataBag $data
+ * @param Context $context
* @return JsonResponse
*/
- public function total64(Request $request): JsonResponse
+ public function total(RequestDataBag $data, Context $context): JsonResponse
{
- /** @var string|null $orderId */
- $orderId = $request->get('orderId');
-
- return $this->getTotalResponse($orderId);
+ return $this->totalResponse($data->getAlnum('orderId'), $context);
}
- private function getTotalResponse(?string $orderId): JsonResponse
+ /**
+ * @RouteScope(scopes={"api"})
+ * @Route("/api/v{version}/_action/mollie/refund/total",
+ * defaults={"auth_enabled"=true}, name="api.action.mollie.refund.total.legacy", methods={"POST"})
+ *
+ * @param RequestDataBag $data
+ * @param Context $context
+ * @return JsonResponse
+ */
+ public function totalLegacy(RequestDataBag $data, Context $context): JsonResponse
{
- /** @var float $amount */
- $amount = 0.0;
+ return $this->totalResponse($data->getAlnum('orderId'), $context);
+ }
- /** @var int $items */
- $items = 0;
+ /**
+ * @param string $orderId
+ * @param float $amount
+ * @param Context $context
+ * @return JsonResponse
+ */
+ private function refundResponse(string $orderId, float $amount, Context $context): JsonResponse
+ {
+ try {
+ $order = $this->getValidOrder($orderId, $context);
+
+ $success = $this->refundService->refund($order, $amount, null, $context);
+ } catch (ShopwareHttpException $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], $e->getStatusCode());
+ } catch (\Throwable $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], 500);
+ }
- /** @var OrderEntity $order */
- $order = null;
+ return $this->json([
+ 'success' => $success
+ ]);
+ }
- if (!empty($orderId)) {
- $order = $this->orderService->getOrder($orderId, Context::createDefaultContext());
+ /**
+ * @param string $orderId
+ * @param string|null $refundId
+ * @param Context $context
+ * @return JsonResponse
+ */
+ private function cancelResponse(string $orderId, ?string $refundId, Context $context): JsonResponse
+ {
+ try {
+ $order = $this->getValidOrder($orderId, $context);
+
+ $success = $this->refundService->cancel($order, $refundId, $context);
+ } catch (ShopwareHttpException $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], $e->getStatusCode());
+ } catch (\Throwable $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], 500);
}
- if ($order !== null) {
- foreach ($order->getLineItems() as $lineItem) {
- if (
- !empty($lineItem->getCustomFields())
- && isset($lineItem->getCustomFields()[self::CUSTOM_FIELDS_KEY_REFUNDED_QUANTITY])
- ) {
- $amount += ($lineItem->getUnitPrice() * (int)$lineItem->getCustomFields()[self::CUSTOM_FIELDS_KEY_REFUNDED_QUANTITY]);
- $items += (int)$lineItem->getCustomFields()[self::CUSTOM_FIELDS_KEY_REFUNDED_QUANTITY];
- }
- }
+ return $this->json([
+ 'success' => $success
+ ]);
+ }
+
+ /**
+ * @param string $orderId
+ * @param Context $context
+ * @return JsonResponse
+ */
+ private function listResponse(string $orderId, Context $context): JsonResponse
+ {
+ try {
+ $order = $this->getValidOrder($orderId, $context);
+
+ $refunds = $this->refundService->getRefunds($order, $context);
+ } catch (ShopwareHttpException $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], $e->getStatusCode());
+ } catch (PaymentNotFoundException $e) {
+ // This indicates there is no completed payment for this order, so there are no refunds yet.
+ $refunds = [];
+ } catch (\Throwable $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], 500);
}
- return new JsonResponse([
- self::RESPONSE_KEY_AMOUNT => $amount,
- self::RESPONSE_KEY_ITEMS => $items,
- ]);
+ return $this->json($refunds ?? []);
}
/**
- * Returns an order line item by id.
- *
- * @param $lineItemId
- * @param null $versionId
- * @param Context|null $context
- *
- * @return OrderLineItemEntity|null
+ * @param string $orderId
+ * @param Context $context
+ * @return JsonResponse
*/
- public function getOrderLineItemById(
- $lineItemId,
- $versionId = null,
- Context $context = null
- ): ?OrderLineItemEntity
+ private function totalResponse(string $orderId, Context $context): JsonResponse
{
- $orderLineCriteria = new Criteria([$lineItemId]);
+ try {
+ $order = $this->getValidOrder($orderId, $context);
+
+ $remaining = $this->refundService->getRemainingAmount($order, $context);
+ $refunded = $this->refundService->getRefundedAmount($order, $context);
+ } catch (ShopwareHttpException $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], $e->getStatusCode());
+ } catch (PaymentNotFoundException $e) {
+ // This indicates there is no completed payment for this order, so there are no refunds yet.
+ $remaining = 0;
+ $refunded = 0;
+ } catch (\Throwable $e) {
+ $this->logger->error($e->getMessage());
+ return $this->json(['message' => $e->getMessage()], 500);
+ }
- if ($versionId !== null) {
- $orderLineCriteria->addFilter(new EqualsFilter('versionId', $versionId));
+ return $this->json(compact('remaining', 'refunded'));
+ }
+
+ /**
+ * @param string $orderId
+ * @param Context $context
+ * @return OrderEntity
+ * @throws InvalidUuidException
+ * @throws InvalidOrderException
+ */
+ private function getValidOrder(string $orderId, Context $context): OrderEntity
+ {
+ if (!Uuid::isValid($orderId)) {
+ throw new InvalidUuidException($orderId);
}
- $orderLineCriteria->addAssociation('order');
- $orderLineCriteria->addAssociation('order.salesChannel');
- $orderLineCriteria->addAssociation('order.transactions');
+ $order = $this->orderService->getOrder($orderId, $context);
+
+ if (!($order instanceof OrderEntity)) {
+ throw new InvalidOrderException($orderId);
+ }
- return $this->orderLineItemRepository->search(
- $orderLineCriteria,
- $context ?? Context::createDefaultContext()
- )->get($lineItemId);
+ return $order;
}
}
diff --git a/src/Exception/CouldNotCancelMollieRefundException.php b/src/Exception/CouldNotCancelMollieRefundException.php
new file mode 100644
index 000000000..e91017d2f
--- /dev/null
+++ b/src/Exception/CouldNotCancelMollieRefundException.php
@@ -0,0 +1,22 @@
+transactionService = $transactionService;
- $this->mollieOrderService = $mollieOrderService;
- $this->apiFactory = $apiFactory;
+ $this->refundService = $refundService;
}
/**
@@ -59,41 +51,21 @@ public function setRefunded(string $orderTransactionId, Context $context): void
);
}
- $customFields = $order->getCustomFields() ?? [];
-
- $mollieOrderId = $customFields['mollie_payments']['order_id'] ?? '';
+ $refunded = $this->refundService->getRefundedAmount($order, $context);
+ $toRefund = $order->getAmountTotal() - $refunded;
- if (empty($mollieOrderId)) {
- throw new CouldNotSetRefundAtMollieException(
- sprintf('Could not find a mollie order id in order %s for transaction %s ',
- $order->getOrderNumber(),
- $transaction->getId()
- )
- );
+ if ($toRefund <= 0.0) {
+ return;
}
- $salesChannel = $order->getSalesChannel();
-
- if (!$salesChannel instanceof SalesChannelEntity) {
- throw new MissingSalesChannelInOrder($order->getOrderNumber() ?? $order->getId());
- }
-
- $apiClient = $this->apiFactory->getClient($salesChannel->getId(), $context);
-
- try {
- $mollieOrder = $apiClient->orders->get($mollieOrderId);
- $mollieOrder->refundAll();
- } catch (ApiException $e) {
- throw new CouldNotSetRefundAtMollieException(
- sprintf('Could not refund at mollie for transaction %s with mollieOrderId %s',
- $orderTransactionId,
- $mollieOrderId
- ),
- 0,
- $e
- );
- }
+ $this->refundService->refund(
+ $order,
+ $toRefund,
+ sprintf(
+ "Refunded entire order through Shopware Administration. Order number %s",
+ $order->getOrderNumber()
+ ),
+ $context
+ );
}
-
-
}
diff --git a/src/Hydrator/RefundHydrator.php b/src/Hydrator/RefundHydrator.php
new file mode 100644
index 000000000..57475feee
--- /dev/null
+++ b/src/Hydrator/RefundHydrator.php
@@ -0,0 +1,47 @@
+
+ */
+ public function hydrate(Refund $refund): array
+ {
+ $amount = null;
+ if ($refund->amount instanceof \stdClass) {
+ $amount = [
+ 'value' => $refund->amount->value,
+ 'currency' => $refund->amount->currency,
+ ];
+ }
+
+ $settlementAmount = null;
+ if ($refund->settlementAmount instanceof \stdClass) {
+ $settlementAmount = [
+ 'value' => $refund->settlementAmount->value,
+ 'currency' => $refund->settlementAmount->currency,
+ ];
+ }
+
+ return [
+ 'id' => $refund->id,
+ 'orderId' => $refund->orderId,
+ 'paymentId' => $refund->paymentId,
+ 'amount' => $amount,
+ 'settlementAmount' => $settlementAmount,
+ 'description' => $refund->description,
+ 'createdAt' => $refund->createdAt,
+ 'status' => $refund->status,
+ 'isFailed' => $refund->isFailed(),
+ 'isPending' => $refund->isPending(),
+ 'isProcessing' => $refund->isProcessing(),
+ 'isQueued' => $refund->isQueued(),
+ 'isTransferred' => $refund->isTransferred(),
+ ];
+ }
+}
diff --git a/src/Resources/app/administration/src/core/service/api/mollie-payments-refund.service.js b/src/Resources/app/administration/src/core/service/api/mollie-payments-refund.service.js
index a42651a38..33b404be1 100644
--- a/src/Resources/app/administration/src/core/service/api/mollie-payments-refund.service.js
+++ b/src/Resources/app/administration/src/core/service/api/mollie-payments-refund.service.js
@@ -5,15 +5,13 @@ class MolliePaymentsRefundService extends ApiService {
super(httpClient, loginService, apiEndpoint);
}
- refund(data = {itemId: null, versionId: null, quantity: null, createCredit: null}) {
- const headers = this.getBasicHeaders();
-
+ __post(endpoint = '', data = {}, headers = {}) {
return this.httpClient
.post(
- `_action/${this.getApiBasePath()}/refund`,
+ `_action/${this.getApiBasePath()}/refund${endpoint}`,
JSON.stringify(data),
{
- headers: headers
+ headers: this.getBasicHeaders(headers)
}
)
.then((response) => {
@@ -21,21 +19,21 @@ class MolliePaymentsRefundService extends ApiService {
});
}
- total(data = {orderId: null}) {
- const headers = this.getBasicHeaders();
+ refund(data = {orderId: null, amount: null}) {
+ return this.__post('', data);
+ }
- return this.httpClient
- .post(
- `_action/${this.getApiBasePath()}/refund/total`,
- JSON.stringify(data),
- {
- headers: headers
- }
- )
- .then((response) => {
- return ApiService.handleResponse(response);
- });
+ cancel(data = {orderId: null, refundId: null}) {
+ return this.__post('/cancel', data);
+ }
+
+ list(data = {orderId: null}) {
+ return this.__post('/list', data);
+ }
+
+ total(data = {orderId: null}) {
+ return this.__post('/total', data);
}
}
-export default MolliePaymentsRefundService;
\ No newline at end of file
+export default MolliePaymentsRefundService;
diff --git a/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/index.js b/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/index.js
index 980a64df8..30756ede0 100644
--- a/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/index.js
+++ b/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/index.js
@@ -1,15 +1,34 @@
import template from './sw-order-line-items-grid.html.twig';
-const { Component, Service } = Shopware;
+const {Component, Mixin} = Shopware;
Component.override('sw-order-line-items-grid', {
template,
+ mixins: [
+ Mixin.getByName('notification')
+ ],
+
inject: [
'MolliePaymentsRefundService',
'MolliePaymentsShippingService',
],
+ props: {
+ remainingAmount: {
+ type: Number,
+ required: true
+ },
+ refundedAmount: {
+ type: Number,
+ required: true
+ },
+ refunds: {
+ type: Array,
+ required: true
+ },
+ },
+
data() {
return {
isLoading: false,
@@ -17,9 +36,8 @@ Component.override('sw-order-line-items-grid', {
showRefundModal: false,
showShippingModal: false,
createCredit: false,
- quantityToRefund: 1,
quantityToShip: 1,
- refundQuantity: 0,
+ refundAmount: 0.0,
shippingQuantity: 0
};
},
@@ -28,17 +46,6 @@ Component.override('sw-order-line-items-grid', {
getLineItemColumns() {
const columnDefinitions = this.$super('getLineItemColumns');
- columnDefinitions.push(
- {
- property: 'customFields.refundedQuantity',
- label: this.$tc('sw-order.detailExtended.columnRefunded'),
- allowResize: false,
- align: 'right',
- inlineEdit: false,
- width: '100px'
- }
- );
-
columnDefinitions.push(
{
property: 'customFields.shippedQuantity',
@@ -51,32 +58,125 @@ Component.override('sw-order-line-items-grid', {
);
return columnDefinitions;
- }
+ },
+
+ getRefundListColumns() {
+ return [
+ {
+ property: 'amount.value',
+ label: this.$tc('mollie-payments.modals.refund.list.column.amount')
+ },
+ {
+ property: 'status',
+ label: this.$tc('mollie-payments.modals.refund.list.column.status')
+ },
+ {
+ property: 'createdAt',
+ label: this.$tc('mollie-payments.modals.refund.list.column.date'),
+ width: '100px'
+ },
+ ];
+ },
+
+ isMollieOrder() {
+ return (this.order.customFields !== null && 'mollie_payments' in this.order.customFields);
+ },
+
+ canOpenRefundModal() {
+ return this.remainingAmount > 0 || this.refunds.length > 0;
+ },
+ },
+
+ created() {
+ this.createdComponent();
},
methods: {
- onRefundItem(item) {
- this.showRefundModal = item.id;
+ createdComponent() {
+ },
+
+ onOpenRefundModal() {
+ this.showRefundModal = true;
},
onCloseRefundModal() {
this.showRefundModal = false;
},
- onConfirmRefund(item) {
- this.showRefundModal = false;
+ onConfirmRefund() {
+ if(this.refundAmount === 0.0) {
+ this.createNotificationWarning({
+ message: this.$tc('mollie-payments.modals.refund.warning.low-amount')
+ });
- if (this.quantityToRefund > 0) {
- this.MolliePaymentsRefundService.refund({
- itemId: item.id,
- versionId: item.versionId,
- quantity: this.quantityToRefund,
- createCredit: this.createCredit
- })
- .then(document.location.reload());
+ return;
}
- this.quantityToRefund = 0;
+ this.MolliePaymentsRefundService
+ .refund({
+ orderId: this.order.id,
+ amount: this.refundAmount,
+ })
+ .then((response) => {
+ if (response.success) {
+ this.createNotificationSuccess({
+ message: this.$tc('mollie-payments.modals.refund.success')
+ });
+ this.showRefundModal = false;
+ } else {
+ this.createNotificationError({
+ message: this.$tc('mollie-payments.modals.refund.error')
+ });
+ }
+ })
+ .then(() => {
+ this.$emit('refund-success');
+ })
+ .catch((response) => {
+ this.createNotificationError({
+ message: response.message
+ });
+ });
+ },
+
+ isRefundCancelable(item) {
+ return item.isPending || item.isQueued;
+ },
+
+ cancelRefund(item) {
+ this.MolliePaymentsRefundService
+ .cancel({
+ orderId: this.order.id,
+ refundId: item.id
+ })
+ .then((response) => {
+ if (response.success) {
+ this.createNotificationSuccess({
+ message: this.$tc('mollie-payments.modals.refund.success')
+ });
+ this.showRefundModal = false;
+ } else {
+ this.createNotificationError({
+ message: this.$tc('mollie-payments.modals.refund.error')
+ });
+ }
+ })
+ .then(() => {
+ this.$emit('refund-cancelled');
+ })
+ .catch((response) => {
+ this.createNotificationError({
+ message: response.message
+ });
+ });
+ },
+
+ getStatus(status) {
+ return this.$tc('mollie-payments.modals.refund.list.status.' + status);
+ },
+
+ getStatusDescription(status) {
+ return this.$tc('mollie-payments.modals.refund.list.status-description.' + status);
},
onShipItem(item) {
@@ -102,30 +202,6 @@ Component.override('sw-order-line-items-grid', {
this.quantityToShip = 0;
},
- isRefundable(item) {
- let refundable = false;
-
- if (
- item.type === 'product'
- && (
- item.customFields !== undefined
- && item.customFields !== null
- && item.customFields.mollie_payments !== undefined
- && item.customFields.mollie_payments !== null
- && item.customFields.mollie_payments.order_line_id !== undefined
- && item.customFields.mollie_payments.order_line_id !== null
- )
- && (
- item.customFields.refundedQuantity === undefined
- || parseInt(item.customFields.refundedQuantity, 10) < item.quantity
- )
- ) {
- refundable = true;
- }
-
- return refundable;
- },
-
isShippable(item) {
let shippable = false;
@@ -150,17 +226,6 @@ Component.override('sw-order-line-items-grid', {
return shippable;
},
- refundableQuantity(item) {
- if (
- item.customFields !== undefined
- && item.customFields.refundedQuantity !== undefined
- ) {
- return item.quantity - parseInt(item.customFields.refundedQuantity, 10);
- }
-
- return item.quantity;
- },
-
shippableQuantity(item) {
if (
item.customFields !== undefined
@@ -181,4 +246,4 @@ Component.override('sw-order-line-items-grid', {
return item.quantity;
},
}
-});
\ No newline at end of file
+});
diff --git a/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/sw-order-line-items-grid.html.twig b/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/sw-order-line-items-grid.html.twig
index d7e09cf16..6ddb08d30 100644
--- a/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/sw-order-line-items-grid.html.twig
+++ b/src/Resources/app/administration/src/module/mollie-payments/extension/sw-order/component/sw-order-line-items-grid/sw-order-line-items-grid.html.twig
@@ -1,83 +1,166 @@
-{% block sw_order_line_items_grid_grid_actions %}
+{% block sw_order_line_items_grid_actions %}
{% parent %}
-
-
- {{ $tc('mollie-payments.modals.refund.content', 0, { quantity: item.quantity, refundableQuantity: refundableQuantity(item) }) }}
-
- {{ $tc('mollie-payments.modals.shipping.content', 0, { quantity: item.quantity, shippableQuantity: shippableQuantity(item) }) }}
-
+ {{ $tc('mollie-payments.modals.shipping.content', 0, {
+ quantity: item.quantity,
+ shippableQuantity: shippableQuantity(item)
+ }) }}
+
+ {% block sw_order_line_items_grid_refund_summary_amount_refunded %}
+
+
+