Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MOL-864 Full Refund with Flow Builder + Refund Manager after partial refund throws error #516

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Components\RefundManager\RefundCalculationHelper;

use Kiener\MolliePayments\Service\Refund\Item\RefundItem;

class RefundCalculationHelper
{
/** @var RefundItem[] */
protected $refundItems;

public function __construct()
{
$this->refundItems = [];
}

/**
* @param RefundItem $refundItem
* @return void
*/
public function addRefundItem(RefundItem $refundItem)
{
$this->refundItems[] = $refundItem;
}

/**
* @param string $orderLineId
* @return int
*/
public function getRefundQuantityForMollieId(string $orderLineId): int
{
$refundQuantity = 0;
foreach ($this->refundItems as $refundItem) {
if ($refundItem->getMollieLineID()===$orderLineId) {
$refundQuantity += $refundItem->getQuantity();
}
}
return $refundQuantity;
}

/**
* @param string $orderLineId
* @return float
*/
public function getRefundAmountForMollieId(string $orderLineId): float
{
$refundAmount = 0;
foreach ($this->refundItems as $refundItem) {
if ($refundItem->getMollieLineID()===$orderLineId) {
$refundAmount += $refundItem->getAmount();
}
}
return $refundAmount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,12 @@ public function toArray(): array
$this->alreadyRefundedQty
);
}

/**
* @return OrderDeliveryEntity
*/
public function getDelivery(): OrderDeliveryEntity
{
return $this->delivery;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,12 @@ private function getProductNumber(): string

return (string)$this->lineItem->getPayload()['productNumber'];
}

/**
* @return OrderLineItemEntity
*/
public function getLineItem(): OrderLineItemEntity
{
return $this->lineItem;
}
}
64 changes: 64 additions & 0 deletions src/Components/RefundManager/RefundData/RefundData.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
namespace Kiener\MolliePayments\Components\RefundManager\RefundData;

use Kiener\MolliePayments\Components\RefundManager\RefundData\OrderItem\AbstractItem;
use Kiener\MolliePayments\Components\RefundManager\RefundData\OrderItem\DeliveryItem;
use Kiener\MolliePayments\Components\RefundManager\RefundData\OrderItem\ProductItem;
use Kiener\MolliePayments\Service\Refund\Item\RefundItem;
use Kiener\MolliePayments\Struct\OrderDeliveryEntity\OrderDeliveryEntityAttributes;
use Kiener\MolliePayments\Struct\OrderLineItemEntity\OrderLineItemEntityAttributes;
use Mollie\Api\Resources\Refund;

class RefundData
Expand Down Expand Up @@ -43,6 +48,7 @@ class RefundData
*/
private $roundingItemTotal;


/**
* @param AbstractItem[] $cartItems
* @param Refund[] $refunds
Expand Down Expand Up @@ -156,4 +162,62 @@ public function toArray()
'refunds' => $refundsArray,
];
}

/**
* @param string $mollieId
* @return int
*/
public function getRefundedQuantity(string $mollieId): int
{
foreach ($this->orderItems as $orderItem) {
if ($orderItem instanceof ProductItem) {
$orderItemAttributes = new OrderLineItemEntityAttributes($orderItem->getLineItem());
}

if ($orderItem instanceof DeliveryItem) {
$orderItemAttributes = new OrderDeliveryEntityAttributes($orderItem->getDelivery());
}

if (empty($orderItemAttributes)) {
continue;
}

if ($mollieId === $orderItemAttributes->getMollieOrderLineID()) {
$refundArray = $orderItem->toArray();
return $refundArray['refunded'];
}
}
return 0;
}

/**
* @param string $mollieId
* @return float
*/
public function getRefundedAmount(string $mollieId):float
{
$totalAmount = 0;

## The amount is being calculated via the refunds because it might have been a custom amount.
/** @var array<mixed> $refund */
foreach ($this->refunds as $refund) {
if (!isset($refund['metadata'])) {
continue;
}

$metadata = $refund['metadata'];
if (!isset($metadata['composition'])) {
continue;
}

$composition = $metadata['composition'];

foreach ($composition as $compositionItem) {
if ($compositionItem['mollieLineId']===$mollieId) {
$totalAmount+=$compositionItem['amount'];
}
}
}
return $totalAmount;
}
}
61 changes: 50 additions & 11 deletions src/Components/RefundManager/RefundManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Kiener\MolliePayments\Compatibility\Bundles\FlowBuilder\FlowBuilderDispatcherAdapterInterface;
use Kiener\MolliePayments\Compatibility\Bundles\FlowBuilder\FlowBuilderEventFactory;
use Kiener\MolliePayments\Compatibility\Bundles\FlowBuilder\FlowBuilderFactory;
use Kiener\MolliePayments\Compatibility\Bundles\FlowBuilder\FlowBuilderFactoryInterface;
use Kiener\MolliePayments\Components\RefundManager\Builder\RefundDataBuilder;
use Kiener\MolliePayments\Components\RefundManager\Integrators\StockManagerInterface;
Expand All @@ -14,19 +13,18 @@
use Kiener\MolliePayments\Components\RefundManager\Request\RefundRequestItemRoundingDiff;
use Kiener\MolliePayments\Exception\CouldNotCreateMollieRefundException;
use Kiener\MolliePayments\Service\MollieApi\Order;
use Kiener\MolliePayments\Service\OrderService;
use Kiener\MolliePayments\Service\OrderServiceInterface;
use Kiener\MolliePayments\Service\Refund\Item\RefundItem;
use Kiener\MolliePayments\Service\Refund\RefundService;
use Kiener\MolliePayments\Service\Refund\RefundServiceInterface;
use Kiener\MolliePayments\Service\Stock\StockManager;
use Kiener\MolliePayments\Struct\MollieApi\OrderLineMetaDataStruct;
use Kiener\MolliePayments\Struct\Order\OrderAttributes;
use Kiener\MolliePayments\Struct\OrderDeliveryEntity\OrderDeliveryEntityAttributes;
use Kiener\MolliePayments\Struct\OrderLineItemEntity\OrderLineItemEntityAttributes;
use Mollie\Api\Resources\OrderLine;
use Mollie\Api\Resources\Refund;
use Psr\Log\LoggerInterface;
use Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryCollection;
use Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryEntity;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemCollection;
use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
use Shopware\Core\Checkout\Order\OrderEntity;
Expand Down Expand Up @@ -155,7 +153,7 @@ public function refund(OrderEntity $order, RefundRequest $request, Context $cont
# we have a full refund, but only with amount
# and no items. to make sure that we have clean data
# we have to extract all items, so that they will be added to the metadata
$requestItems = $this->buildRequestItemsFromOrder($order);
$requestItems = $this->buildRequestItemsFromOrder($order, $context);
$request->setItems($requestItems);
$this->appendRoundingItemFromMollieOrder($request, $mollieOrder);

Expand Down Expand Up @@ -213,7 +211,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());
}
Expand Down Expand Up @@ -298,27 +296,41 @@ private function getOrderItem(OrderEntity $orderEntity, string $lineID): ?OrderL
* @param OrderEntity $order
* @return array<mixed>
*/
private function buildRequestItemsFromOrder(OrderEntity $order)
private function buildRequestItemsFromOrder(OrderEntity $order, Context $context)
{
$items = [];

$refundData = $this->builderData->buildRefundData($order, $context);

if ($order->getLineItems() instanceof OrderLineItemCollection) {
/** @var OrderLineItemEntity $lineItem */
foreach ($order->getLineItems() as $lineItem) {
$orderLineItemAttributes = new OrderLineItemEntityAttributes($lineItem);

$alreadyRefundedQuantity = $refundData->getRefundedQuantity($orderLineItemAttributes->getMollieOrderLineID());
$alreadyRefundedAmount = $refundData->getRefundedAmount($orderLineItemAttributes->getMollieOrderLineID());

$items[] = new RefundRequestItem(
$lineItem->getId(),
$lineItem->getTotalPrice(),
$lineItem->getQuantity(),
$lineItem->getTotalPrice() - $alreadyRefundedAmount,
$lineItem->getQuantity() - $alreadyRefundedQuantity,
0
);
}
}

if ($order->getDeliveries() instanceof OrderDeliveryCollection) {
/** @var OrderDeliveryEntity $delivery */
foreach ($order->getDeliveries() as $delivery) {
$orderLineItemAttributes = new OrderDeliveryEntityAttributes($delivery);

$alreadyRefundedQuantity = $refundData->getRefundedQuantity($orderLineItemAttributes->getMollieOrderLineID());
$alreadyRefundedAmount = $refundData->getRefundedAmount($orderLineItemAttributes->getMollieOrderLineID());

$items[] = new RefundRequestItem(
$delivery->getId(),
$delivery->getShippingCosts()->getTotalPrice(),
$delivery->getShippingCosts()->getQuantity(),
$delivery->getShippingCosts()->getTotalPrice() - $alreadyRefundedAmount,
$delivery->getShippingCosts()->getQuantity() - $alreadyRefundedQuantity,
0
);
}
Expand Down Expand Up @@ -426,4 +438,31 @@ private function convertToRefundItems(RefundRequest $request, OrderEntity $order

return $serviceItems;
}


/**
* Get the orderLineId from both OrderDeliveryEntity and OrderLineItemEntity
* @param OrderDeliveryEntity|OrderLineItemEntity $lineItem
* @return string
*/
public function getOrderLineId($lineItem): string
smemoict marked this conversation as resolved.
Show resolved Hide resolved
{
$customFields = $lineItem->getCustomFields();

if (!isset($customFields)) {
return "";
}

if (!isset($customFields['mollie_payments'])) {
return "";
}

$molliePayments = $customFields['mollie_payments'];

if (!isset($molliePayments['order_line_id'])) {
return "";
}

return $molliePayments['order_line_id'];
}
}
1 change: 1 addition & 0 deletions src/Resources/config/services/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@

<service id="Kiener\MolliePayments\Service\Order\UpdateOrderLineItems">
<argument type="service" id="order_line_item.repository"/>
<argument type="service" id="order_delivery.repository"/>
</service>


Expand Down
19 changes: 13 additions & 6 deletions src/Service/Order/UpdateOrderLineItems.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@ class UpdateOrderLineItems
*/
private $orderLineRepository;

/**
* @var EntityRepositoryInterface
*/
private $orderDeliveryRepository;


/**
* @param EntityRepositoryInterface $orderLineRepository
*/
public function __construct(EntityRepositoryInterface $orderLineRepository)
public function __construct(EntityRepositoryInterface $orderLineRepository, EntityRepositoryInterface $orderDeliveryRepository)
{
$this->orderLineRepository = $orderLineRepository;
$this->orderDeliveryRepository = $orderDeliveryRepository;
}

/**
Expand All @@ -34,10 +40,7 @@ public function updateOrderLineItems(Order $mollieOrder, SalesChannelContext $sa
{
/** @var OrderLine $orderLine */
foreach ($mollieOrder->lines() as $orderLine) {
if ($orderLine->type === OrderLineType::TYPE_SHIPPING_FEE) {
continue;
}

##Contrary to the name, this can also be an order_delivery id since these are also kind of line items
$shopwareLineItemId = (string)$orderLine->metadata->orderLineItemId;

if (empty($shopwareLineItemId)) {
Expand All @@ -53,7 +56,11 @@ public function updateOrderLineItems(Order $mollieOrder, SalesChannelContext $sa
]
];

$this->orderLineRepository->update([$data], $salesChannelContext->getContext());
if ($orderLine->type === OrderLineType::TYPE_SHIPPING_FEE) {
$this->orderDeliveryRepository->update([$data], $salesChannelContext->getContext());
} else {
$this->orderLineRepository->update([$data], $salesChannelContext->getContext());
}
}
}
}
16 changes: 16 additions & 0 deletions src/Struct/OrderDeliveryEntity/OrderDeliveryEntityAttributes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);

namespace Kiener\MolliePayments\Struct\OrderDeliveryEntity;

use Kiener\MolliePayments\Struct\OrderXEntityAttributes;
use Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryEntity;
use Shopware\Core\Framework\DataAbstractionLayer\Entity;

class OrderDeliveryEntityAttributes extends OrderXEntityAttributes
{
public function __construct(OrderDeliveryEntity $entity)
{
parent::__construct($entity);
}
}
Loading