diff --git a/src/Components/RefundManager/Builder/RefundDataBuilder.php b/src/Components/RefundManager/Builder/RefundDataBuilder.php index 841c6e00b..e31a60041 100644 --- a/src/Components/RefundManager/Builder/RefundDataBuilder.php +++ b/src/Components/RefundManager/Builder/RefundDataBuilder.php @@ -76,6 +76,13 @@ public function buildRefundData(OrderEntity $order, Context $context): RefundDat try { + + # ********************************************************************************** + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # + # ATTENTION, this will load the refunds from Mollie, but also from the database + # we will add our database data to the Mollie metadata.composition and therefore "fake" a response of Mollie, + # so that we can reuse the old code from below, even though Mollie does not really have a metadata.composition. $refunds = $this->refundService->getRefunds($order, $context); } catch (PaymentNotFoundException $ex) { # if we dont have a payment, then theres also no refunds diff --git a/src/Components/RefundManager/DAL/Refund/RefundDefinition.php b/src/Components/RefundManager/DAL/Refund/RefundDefinition.php index 019de024f..ad697ffe4 100644 --- a/src/Components/RefundManager/DAL/Refund/RefundDefinition.php +++ b/src/Components/RefundManager/DAL/Refund/RefundDefinition.php @@ -7,6 +7,7 @@ use Shopware\Core\Checkout\Order\OrderDefinition; use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition; use Shopware\Core\Framework\DataAbstractionLayer\Field\FkField; +use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\ApiAware; use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\PrimaryKey; use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Required; use Shopware\Core\Framework\DataAbstractionLayer\Field\IdField; @@ -59,6 +60,8 @@ protected function defineFields(): FieldCollection (new StringField('mollie_refund_id', 'mollieRefundId')), + (new StringField('type', 'type')), + new LongTextField('public_description', 'publicDescription'), new LongTextField('internal_description', 'internalDescription'), new OneToManyAssociationField('refundItems', RefundItemDefinition::class, 'refund_id') diff --git a/src/Components/RefundManager/DAL/Refund/RefundEntity.php b/src/Components/RefundManager/DAL/Refund/RefundEntity.php index a81ddccbc..7503bda97 100644 --- a/src/Components/RefundManager/DAL/Refund/RefundEntity.php +++ b/src/Components/RefundManager/DAL/Refund/RefundEntity.php @@ -27,6 +27,11 @@ class RefundEntity extends Entity */ protected $mollieRefundId; + /** + * @var null|string + */ + protected $type; + /** * @var null|string */ @@ -42,6 +47,10 @@ class RefundEntity extends Entity */ protected $refundItems; + + /** + * + */ public function __construct() { $this->refundItems = new RefundItemCollection(); @@ -99,6 +108,16 @@ public function setMollieRefundId(?string $mollieRefundId): void $this->mollieRefundId = $mollieRefundId; } + public function getType(): ?string + { + return $this->type; + } + + public function setType(?string $type): void + { + $this->type = $type; + } + /** * @return null|string */ diff --git a/src/Components/RefundManager/DAL/RefundItem/RefundItemDefinition.php b/src/Components/RefundManager/DAL/RefundItem/RefundItemDefinition.php index 4ccbc7132..51ca44e0a 100644 --- a/src/Components/RefundManager/DAL/RefundItem/RefundItemDefinition.php +++ b/src/Components/RefundManager/DAL/RefundItem/RefundItemDefinition.php @@ -43,7 +43,6 @@ protected function defineFields(): FieldCollection { return new FieldCollection([ (new IdField('id', 'id'))->addFlags(new Required(), new PrimaryKey(), new ApiAware()), - (new StringField('type', 'type'))->addFlags(new Required(), new ApiAware()), (new FkField('refund_id', 'refundId', RefundDefinition::class))->addFlags(new ApiAware()), (new ManyToOneAssociationField('refund', 'refund_id', RefundDefinition::class))->addFlags(new ApiAware()), (new IntField('quantity', 'quantity'))->addFlags(new Required(), new ApiAware()), diff --git a/src/Components/RefundManager/DAL/RefundItem/RefundItemEntity.php b/src/Components/RefundManager/DAL/RefundItem/RefundItemEntity.php index 50f8fb98c..cbf9ac211 100644 --- a/src/Components/RefundManager/DAL/RefundItem/RefundItemEntity.php +++ b/src/Components/RefundManager/DAL/RefundItem/RefundItemEntity.php @@ -12,11 +12,6 @@ final class RefundItemEntity extends Entity { use EntityIdTrait; - /** - * @var string - */ - protected $type; - /** * @var string */ @@ -62,21 +57,6 @@ final class RefundItemEntity extends Entity */ protected $orderLineItem; - /** - * @return string - */ - public function getType(): string - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType(string $type): void - { - $this->type = $type; - } /** * @return string @@ -223,7 +203,6 @@ public function setOrderLineItemVersionId(?string $orderLineItemVersionId): void } /** - * @param string $type * @param string $mollieLineId * @param string $label * @param int $quantity @@ -233,22 +212,21 @@ public function setOrderLineItemVersionId(?string $orderLineItemVersionId): void * @param null|string $refundId * @return array */ - public static function createEntryArray(string $type, string $mollieLineId, string $label, int $quantity, float $amount, ?string $oderLineItemId, ?string $oderLineItemVersionId, ?string $refundId): array + public static function createArray(string $mollieLineId, string $label, int $quantity, float $amount, ?string $oderLineItemId, ?string $oderLineItemVersionId, ?string $refundId): array { - $row = [ - 'type' => $type, + $row = [ 'mollieLineId' => $mollieLineId, 'label' => $label, 'quantity' => $quantity, 'amount' => $amount, - 'oderLineItemId' => $oderLineItemId, - 'oderLineItemVersionId' => $oderLineItemVersionId, + 'orderLineItemId' => $oderLineItemId, + 'orderLineItemVersionId' => $oderLineItemVersionId, ]; /** * refundId is not given when we create a new entry because the id is created by shopware dal */ - if ($refundId !== null) { + if ($refundId !== null && $refundId !== '') { $row['refundId'] = $refundId; } diff --git a/src/Components/RefundManager/DAL/Repository/RefundRepository.php b/src/Components/RefundManager/DAL/Repository/RefundRepository.php index ec05d8693..68fb1f56a 100644 --- a/src/Components/RefundManager/DAL/Repository/RefundRepository.php +++ b/src/Components/RefundManager/DAL/Repository/RefundRepository.php @@ -8,6 +8,7 @@ use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult; +use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult; class RefundRepository implements RefundRepositoryInterface { @@ -43,4 +44,24 @@ public function search(Criteria $criteria, Context $context): EntitySearchResult { return $this->mollieRefundRepository->search($criteria, $context); } + + /** + * @param Criteria $criteria + * @param Context $context + * @return IdSearchResult + */ + public function searchIds(Criteria $criteria, Context $context): IdSearchResult + { + return $this->mollieRefundRepository->searchIds($criteria, $context); + } + + /** + * @param array $ids + * @param Context $context + * @return EntityWrittenContainerEvent + */ + public function delete(array $ids, Context $context): EntityWrittenContainerEvent + { + return $this->mollieRefundRepository->delete($ids, $context); + } } diff --git a/src/Components/RefundManager/DAL/Repository/RefundRepositoryInterface.php b/src/Components/RefundManager/DAL/Repository/RefundRepositoryInterface.php index b000539fb..538f161b8 100644 --- a/src/Components/RefundManager/DAL/Repository/RefundRepositoryInterface.php +++ b/src/Components/RefundManager/DAL/Repository/RefundRepositoryInterface.php @@ -7,6 +7,7 @@ use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult; +use Shopware\Core\Framework\DataAbstractionLayer\Search\IdSearchResult; interface RefundRepositoryInterface { @@ -23,4 +24,18 @@ public function create(array $data, Context $context): EntityWrittenContainerEve * @return EntitySearchResult */ public function search(Criteria $criteria, Context $context): EntitySearchResult; + + /** + * @param Criteria $criteria + * @param Context $context + * @return IdSearchResult + */ + public function searchIds(Criteria $criteria, Context $context): IdSearchResult; + + /** + * @param array $ids + * @param Context $context + * @return EntityWrittenContainerEvent + */ + public function delete(array $ids, Context $context): EntityWrittenContainerEvent; } diff --git a/src/Components/RefundManager/RefundManager.php b/src/Components/RefundManager/RefundManager.php index f3df010e9..d3a091b55 100644 --- a/src/Components/RefundManager/RefundManager.php +++ b/src/Components/RefundManager/RefundManager.php @@ -6,6 +6,9 @@ use Kiener\MolliePayments\Compatibility\Bundles\FlowBuilder\FlowBuilderEventFactory; use Kiener\MolliePayments\Compatibility\Bundles\FlowBuilder\FlowBuilderFactoryInterface; use Kiener\MolliePayments\Components\RefundManager\Builder\RefundDataBuilder; +use Kiener\MolliePayments\Components\RefundManager\DAL\Order\OrderExtension; +use Kiener\MolliePayments\Components\RefundManager\DAL\Refund\RefundCollection; +use Kiener\MolliePayments\Components\RefundManager\DAL\Refund\RefundEntity; use Kiener\MolliePayments\Components\RefundManager\DAL\RefundItem\RefundItemEntity; use Kiener\MolliePayments\Components\RefundManager\DAL\Repository\RefundRepositoryInterface; use Kiener\MolliePayments\Components\RefundManager\Integrators\StockManagerInterface; @@ -32,6 +35,8 @@ use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity; use Shopware\Core\Checkout\Order\OrderEntity; use Shopware\Core\Framework\Context; +use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; +use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter; class RefundManager implements RefundManagerInterface { @@ -100,9 +105,8 @@ public function __construct(RefundDataBuilder $refundDataBuilder, OrderServiceIn $this->refundService = $refundService; $this->stockManager = $stockUpdater; $this->refundRepository = $refundRepository; - $this->logger = $logger; - $this->flowBuilderEventFactory = $flowBuilderEventFactory; + $this->logger = $logger; $this->flowBuilderDispatcher = $flowBuilderFactory->createDispatcher(); } @@ -171,6 +175,7 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont if ($orderAttributes->isTypeSubscription()) { $refundType = RefundItemType::PARTIAL; + # we only have a transaction in the case of a subscription $refund = $this->refundService->refundPartial( $order, @@ -182,6 +187,7 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont ); } else { $refundType = RefundItemType::FULL; + $refund = $this->refundService->refundFull( $order, $request->getDescription(), @@ -192,8 +198,11 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont } } elseif ($request->isFullRefundWithItems($order)) { $this->appendRoundingItemFromMollieOrder($request, $mollieOrder); + $serviceItems = $this->convertToRefundItems($request, $order, $mollieOrder); + $refundType = RefundItemType::FULL; + $refund = $this->refundService->refundFull( $order, $request->getDescription(), @@ -203,6 +212,7 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont ); } elseif ($request->isPartialAmountOnly()) { $refundType = RefundItemType::PARTIAL; + $refund = $this->refundService->refundPartial( $order, $request->getDescription(), @@ -213,6 +223,7 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont ); } elseif ($request->isPartialAmountWithItems($order)) { $refundType = RefundItemType::PARTIAL; + $refund = $this->refundService->refundPartial( $order, $request->getDescription(), @@ -223,7 +234,7 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont ); } - if (! $refund instanceof Refund) { + if (!$refund instanceof Refund) { # a problem happened, lets finish with an exception throw new CouldNotCreateMollieRefundException('', (string)$order->getOrderNumber()); } @@ -231,19 +242,20 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont $refundAmount = (float)$refund->amount->value; - $refundData = [ 'orderId' => $order->getId(), 'orderVersionId' => $order->getVersionId(), 'mollieRefundId' => $refund->id, + 'type' => $refundType, 'publicDescription' => $request->getDescription(), 'internalDescription' => $request->getInternalDescription(), - ]; + $refundItems = $this->convertToRepositoryArray($serviceItems, $refundType); if (count($refundItems) > 0) { $refundData['refundItems'] = $refundItems; } + # SAVE LOCAL REFUND # --------------------------------------------------------------------------------------------- $this->refundRepository->create([$refundData], $context); @@ -297,7 +309,33 @@ public function cancelRefund(string $orderId, string $refundId, Context $context ] ); - return $this->refundService->cancel($order, $refundId); + # first try to cancel on the mollie side + $success = $this->refundService->cancel($order, $refundId); + + if (!$success) { + return false; + } + + + # if mollie worked, also delete our entry from the database + $criteria = new Criteria(); + $criteria->addFilter(new EqualsFilter('mollieRefundId', $refundId)); + + $foundSwRefunds = $this->refundRepository->searchIds($criteria, $context); + + if ($foundSwRefunds->getTotal() === 0) { + return true; + } + + $swRefundId = $foundSwRefunds->firstId(); + + $this->refundRepository->delete([ + [ + 'id' => $swRefundId + ], + ], $context); + + return true; } /** @@ -463,12 +501,13 @@ private function convertToRefundItems(RefundRequest $request, OrderEntity $order private function convertToRepositoryArray(array $serviceItems, string $type): array { $data = []; + foreach ($serviceItems as $item) { if ($item->getQuantity() <= 0) { continue; } - $row = RefundItemEntity::createEntryArray( - $type, + + $row = RefundItemEntity::createArray( $item->getMollieLineID(), $item->getShopwareReference(), $item->getQuantity(), @@ -480,6 +519,7 @@ private function convertToRepositoryArray(array $serviceItems, string $type): ar $data[] = $row; } + return $data; } } diff --git a/src/Controller/Api/Order/RefundControllerBase.php b/src/Controller/Api/Order/RefundControllerBase.php index d8a69c6fd..28db68e53 100644 --- a/src/Controller/Api/Order/RefundControllerBase.php +++ b/src/Controller/Api/Order/RefundControllerBase.php @@ -2,6 +2,7 @@ namespace Kiener\MolliePayments\Controller\Api\Order; +use Kiener\MolliePayments\Components\RefundManager\RefundData\RefundData; use Kiener\MolliePayments\Components\RefundManager\RefundManagerInterface; use Kiener\MolliePayments\Components\RefundManager\Request\RefundRequest; use Kiener\MolliePayments\Components\RefundManager\Request\RefundRequestItem; @@ -116,11 +117,16 @@ public function refundManagerData(RequestDataBag $data, Context $context): JsonR $order = $this->orderService->getOrder($orderId, $context); - $data = $this->refundManager->getData($order, $context); + $refundData = $this->refundManager->getData($order, $context); - return $this->json($data->toArray()); + return $this->json($refundData->toArray()); } catch (\Throwable $e) { - $this->logger->error($e->getMessage()); + $this->logger->error( + $e->getMessage(), + [ + 'error' => $e, + ] + ); return $this->buildErrorResponse($e->getMessage()); } } diff --git a/src/Hydrator/RefundHydrator.php b/src/Hydrator/RefundHydrator.php index d5f3ae6f4..10eb7566d 100644 --- a/src/Hydrator/RefundHydrator.php +++ b/src/Hydrator/RefundHydrator.php @@ -65,7 +65,8 @@ public function hydrate(Refund $refund, OrderEntity $order): array $metaData->composition = []; /** @var RefundItemEntity $refundLineItem */ foreach ($refundLineItems as $refundLineItem) { - $metaData->type = $refundLineItem->getType(); + $metaData->type = $shopwareRefund->getType(); + $metaData->composition[]=[ 'swLineId' => (string)$refundLineItem->getOrderLineItemId(), 'swLineVersionId' => (string)$refundLineItem->getOrderLineItemVersionId(), diff --git a/src/Migration/Migration1695822535RefundMoveType.php b/src/Migration/Migration1695822535RefundMoveType.php new file mode 100644 index 000000000..fbfeb1aa8 --- /dev/null +++ b/src/Migration/Migration1695822535RefundMoveType.php @@ -0,0 +1,47 @@ +createColumn( + 'mollie_refund', + 'type', + 'VARCHAR(255)', + 'NULL', + 'mollie_refund_id' + ); + + $utils->deleteColumn('mollie_refund_item', 'type'); + } + + /** + * @param Connection $connection + * @return void + */ + public function updateDestructive(Connection $connection): void + { + // implement update destructive + } +} diff --git a/src/Migration/MigrationUtils.php b/src/Migration/MigrationUtils.php index b12c1eebd..f7808e73b 100644 --- a/src/Migration/MigrationUtils.php +++ b/src/Migration/MigrationUtils.php @@ -49,6 +49,23 @@ public function createColumn(string $table, string $column, string $type, string } } + /** + * @param string $table + * @param string $column + * @throws Exception + * @return void + */ + public function deleteColumn(string $table, string $column): void + { + $colQuery = $this->connection->executeQuery("SHOW COLUMNS FROM " . $table . " LIKE '" . $column . "'")->fetch(); + + # only delete if existing + if ($colQuery !== false) { + $sql = "ALTER TABLE " . $table . " DROP " . $column; + $this->connection->exec($sql); + } + } + /** * @param string $table * @param string $keyName diff --git a/src/Service/Refund/CompositionMigrationService.php b/src/Service/Refund/CompositionMigrationService.php index fc83579eb..5706cc2b8 100644 --- a/src/Service/Refund/CompositionMigrationService.php +++ b/src/Service/Refund/CompositionMigrationService.php @@ -34,12 +34,12 @@ public function updateRefundItems(Refund $refund, OrderEntity $order, Context $c { /** @var \stdClass|string $oldMetadata */ $oldMetadata = $refund->metadata; - if (! is_string($oldMetadata)) { + if (!is_string($oldMetadata)) { return $order; } $oldMetadata = json_decode($oldMetadata); - if (! property_exists($oldMetadata, 'composition') && ! is_array($oldMetadata->composition)) { + if (!property_exists($oldMetadata, 'composition') || !is_array($oldMetadata->composition)) { return $order; } @@ -93,8 +93,7 @@ public function updateRefundItems(Refund $refund, OrderEntity $order, Context $c $orderLineItemVersionId = $orderLineItem->getVersionId(); } - $row = RefundItemEntity::createEntryArray( - $oldMetadata->type, + $row = RefundItemEntity::createArray( $composition->mollieLineId, $label, $composition->quantity, @@ -130,22 +129,23 @@ private function createEntitiesByEvent(EntityWrittenContainerEvent $event): Refu $results = $writtenEvent->getWriteResults(); foreach ($results as $result) { - $entity = new RefundItemEntity(); - $entity->setId($result->getProperty('id')); - $entity->setUniqueIdentifier($result->getProperty('id')); - $entity->setQuantity($result->getProperty('quantity')); - $entity->setLabel($result->getProperty('label')); - $entity->setAmount($result->getProperty('amount')); - $entity->setRefundId($result->getProperty('refundId')); - $entity->setMollieLineId($result->getProperty('mollieLineId')); + $swRefundItem = new RefundItemEntity(); + $swRefundItem->setId($result->getProperty('id')); + $swRefundItem->setUniqueIdentifier($result->getProperty('id')); + $swRefundItem->setQuantity($result->getProperty('quantity')); + $swRefundItem->setLabel($result->getProperty('label')); + $swRefundItem->setAmount($result->getProperty('amount')); + $swRefundItem->setRefundId($result->getProperty('refundId')); + $swRefundItem->setMollieLineId($result->getProperty('mollieLineId')); + if ($result->getProperty('orderLineItemId') !== null && $result->getProperty('orderLineItemVersionId') !== null) { - $entity->setOrderLineItemId($result->getProperty('orderLineItemId')); - $entity->setOrderLineItemVersionId($result->getProperty('orderLineItemVersionId')); + $swRefundItem->setOrderLineItemId($result->getProperty('orderLineItemId')); + $swRefundItem->setOrderLineItemVersionId($result->getProperty('orderLineItemVersionId')); } - $entity->setType($result->getProperty('type')); - $entity->setCreatedAt($result->getProperty('createdAt')); - $collection->add($entity); + $swRefundItem->setCreatedAt($result->getProperty('createdAt')); + + $collection->add($swRefundItem); } return $collection; } @@ -159,7 +159,7 @@ private function filterByMollieId(OrderLineItemCollection $lineItems, string $mo if ($customFields === null) { continue; } - if (! isset($customFields['mollie_payments']['order_line_id'])) { + if (!isset($customFields['mollie_payments']['order_line_id'])) { continue; } if ($customFields['mollie_payments']['order_line_id'] === $mollieLineId) { diff --git a/src/Service/Refund/Mollie/RefundMetadata.php b/src/Service/Refund/Mollie/RefundMetadata.php index 857ce1a10..07b3eda54 100644 --- a/src/Service/Refund/Mollie/RefundMetadata.php +++ b/src/Service/Refund/Mollie/RefundMetadata.php @@ -18,7 +18,6 @@ class RefundMetadata private $items; - /** * @param string $type * @param RefundItem[] $items @@ -69,4 +68,18 @@ public function getComposition(): array { return $this->items; } + + /** + * Used as storage payload inside the Mollie API database. + * + * @return string + */ + public function toMolliePayload(): string + { + $data = [ + 'type' => $this->type, + ]; + + return (string)json_encode($data); + } } diff --git a/src/Service/Refund/RefundService.php b/src/Service/Refund/RefundService.php index c13f9f4ce..ddf675d6a 100644 --- a/src/Service/Refund/RefundService.php +++ b/src/Service/Refund/RefundService.php @@ -83,9 +83,11 @@ public function refundFull(OrderEntity $order, string $description, string $inte $mollieOrderId = $this->orders->getMollieOrderId($order); $mollieOrder = $this->mollie->getMollieOrder($mollieOrderId, $order->getSalesChannelId()); + $metadata = new RefundMetadata(RefundItemType::FULL, $refundItems); $params = [ 'description' => $description, + 'metadata' => $metadata->toMolliePayload(), ]; @@ -130,6 +132,8 @@ public function refundFull(OrderEntity $order, string $description, string $inte */ public function refundPartial(OrderEntity $order, string $description, string $internalDescription, float $amount, array $lineItems, Context $context): Refund { + $metadata = new RefundMetadata(RefundItemType::PARTIAL, $lineItems); + $payment = $this->getPayment($order); $refund = $payment->refund([ @@ -137,7 +141,8 @@ public function refundPartial(OrderEntity $order, string $description, string $i 'value' => number_format($amount, 2, '.', ''), 'currency' => ($order->getCurrency() instanceof CurrencyEntity) ? $order->getCurrency()->getIsoCode() : '', ], - 'description' => $description + 'description' => $description, + 'metadata' => $metadata->toMolliePayload(), ]); if (!$refund instanceof Refund) { @@ -150,10 +155,10 @@ public function refundPartial(OrderEntity $order, string $description, string $i /** * @param OrderEntity $order * @param string $refundId - * @throws CouldNotExtractMollieOrderIdException * @throws CouldNotFetchMollieOrderException * @throws PaymentNotFoundException * @throws CouldNotCancelMollieRefundException + * @throws CouldNotExtractMollieOrderIdException * @return bool */ public function cancel(OrderEntity $order, string $refundId): bool @@ -188,13 +193,13 @@ public function cancel(OrderEntity $order, string $refundId): bool /** * @param OrderEntity $order - * @throws CouldNotFetchMollieOrderException * @throws CouldNotFetchMollieRefundsException * @throws PaymentNotFoundException * @throws CouldNotExtractMollieOrderIdException + * @throws CouldNotFetchMollieOrderException * @return array */ - public function getRefunds(OrderEntity $order, Context $context): array + public function getRefunds(OrderEntity $order, Context $context): array { $orderAttributes = new OrderAttributes($order); @@ -212,6 +217,9 @@ public function getRefunds(OrderEntity $order, Context $context): array if ($refund->status === 'canceled') { continue; } + + # if we have a metadata entry, then make sure to + # migrate those compositions (if existing) to our database storage (for legacy refunds) if (property_exists($refund, 'metadata')) { /** @var \stdClass|string $metadata */ $metadata = $refund->metadata; @@ -231,9 +239,9 @@ public function getRefunds(OrderEntity $order, Context $context): array /** * @param OrderEntity $order - * @throws PaymentNotFoundException * @throws CouldNotExtractMollieOrderIdException * @throws CouldNotFetchMollieOrderException + * @throws PaymentNotFoundException * @return float */ public function getRemainingAmount(OrderEntity $order): float @@ -271,9 +279,9 @@ public function getVoucherPaidAmount(OrderEntity $order): float /** * @param OrderEntity $order - * @throws PaymentNotFoundException * @throws CouldNotExtractMollieOrderIdException * @throws CouldNotFetchMollieOrderException + * @throws PaymentNotFoundException * @return float */ public function getRefundedAmount(OrderEntity $order): float diff --git a/tests/PHPUnit/Components/RefundManager/DAL/RefundItem/RefundItemTest.php b/tests/PHPUnit/Components/RefundManager/DAL/RefundItem/RefundItemTest.php new file mode 100644 index 000000000..fd410983c --- /dev/null +++ b/tests/PHPUnit/Components/RefundManager/DAL/RefundItem/RefundItemTest.php @@ -0,0 +1,80 @@ + 'mol-1', + 'label' => 'T-Shirt', + 'quantity' => 2, + 'amount' => 2.49, + 'orderLineItemId' => 'ord-id-1', + 'orderLineItemVersionId' => 'ord-id-version-1', + ]; + + $this->assertEquals($expected, $payload); + } + + /** + * This test verifies that our DAL payload is correct. + * It covers the case where we also provide an additional refundId as foreign key. + * @return void + */ + public function testDalPayloadWithRefundId(): void + { + $payload = RefundItemEntity::createArray( + 'mol-1', + 'T-Shirt', + 2, + 2.49, + 'ord-id-1', + 'ord-id-version-1', + 'refund-1' + ); + + $this->assertEquals('refund-1', $payload['refundId']); + } + + /** + * This test verifies that our DAL payload is correct. + * It covers the case where we provide an empty string as refund ID and it should not be added in that case. + * @return void + */ + public function testDALPayloadNoRefundIfEmpty(): void + { + $payload = RefundItemEntity::createArray( + 'mol-1', + 'T-Shirt', + 2, + 2.49, + 'ord-id-1', + 'ord-id-version-1', + '' + ); + + $this->assertArrayNotHasKey('refundId', $payload); + } + +}