diff --git a/Components/Order/OrderUpdater.php b/Components/Order/OrderUpdater.php
index 74f14a99..77accfb8 100644
--- a/Components/Order/OrderUpdater.php
+++ b/Components/Order/OrderUpdater.php
@@ -6,6 +6,7 @@
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use MollieShopware\Components\Config;
+use MollieShopware\Components\Constants\PaymentStatus;
use MollieShopware\Components\StatusConverter\OrderStatusConverter;
use MollieShopware\Components\StatusConverter\PaymentStatusConverter;
use MollieShopware\Components\Validator\PaymentStatusMailValidator;
@@ -15,12 +16,15 @@
use Psr\Log\LoggerInterface;
use Shopware\Components\ContainerAwareEventManager;
use Shopware\Components\Model\ModelManager;
+use Shopware\Models\Article\Detail;
+use Shopware\Models\Order\DetailStatus;
use Shopware\Models\Order\History;
use Shopware\Models\Order\Order;
use sOrder;
class OrderUpdater
{
+ const ORDER_DETAIL_STATUS_CANCELLED = 2;
/**
* @var LoggerInterface
@@ -408,6 +412,23 @@ private function updateOrderStatus(Order $order, $mollieStatus, $sendMail)
);
}
+ if ($mollieStatus === PaymentStatus::MOLLIE_PAYMENT_CANCELED) {
+ $this->cancelOrderPositions($order);
+ }
+
return true;
}
+
+ private function cancelOrderPositions(Order $order)
+ {
+ /** @var DetailStatus $cancelledStatus */
+ $cancelledStatus = $this->modelManager->find(DetailStatus::class, self::ORDER_DETAIL_STATUS_CANCELLED);
+
+ /** @var Detail $detail */
+ foreach ($order->getDetails() as $detail) {
+ $detail->setStatus($cancelledStatus);
+ }
+
+ $this->modelManager->flush();
+ }
}
diff --git a/Components/Services/StockService.php b/Components/Services/StockService.php
index 68348379..f3fae078 100644
--- a/Components/Services/StockService.php
+++ b/Components/Services/StockService.php
@@ -4,7 +4,10 @@
use Enlight_Components_Db_Adapter_Pdo_Mysql;
use MollieShopware\Components\Config;
+use MollieShopware\Services\IsMolliePaymentValidator;
use Psr\Log\LoggerInterface;
+use Shopware\Models\Payment\Payment;
+use function sprintf;
class StockService
{
@@ -31,18 +34,25 @@ class StockService
*/
private $config;
+ /**
+ * @var IsMolliePaymentValidator
+ */
+ private $isMolliePaymentValidator;
+
/**
* @param OrderService $orderService
* @param Enlight_Components_Db_Adapter_Pdo_Mysql $db
* @param LoggerInterface $logger
- * @param mixed $config
+ * @param Config $config
+ * @param IsMolliePaymentValidator $isMolliePaymentValidator
*/
- public function __construct($orderService, $config, $db, $logger)
+ public function __construct($orderService, $config, $db, $logger, $isMolliePaymentValidator)
{
$this->orderService = $orderService;
$this->db = $db;
$this->logger = $logger;
$this->config = $config;
+ $this->isMolliePaymentValidator = $isMolliePaymentValidator;
}
@@ -59,6 +69,14 @@ public function updateOrderStocks($orderId, $reset = true)
}
$order = $this->orderService->getOrderById($orderId);
+ /** @var Payment $payment */
+ $payment = $order->getPayment();
+ if (!$this->isMolliePaymentValidator->validate($payment)) {
+ $this->logger->debug(sprintf('payment "%s" is not a mollie payment', $payment->getName()));
+
+ return;
+ }
+
$this->logger->debug('Start to reset the stocks for order', ['orderId' => $orderId]);
foreach ($order->getDetails() as $orderDetail) {
diff --git a/Resources/services/components/mixed.xml b/Resources/services/components/mixed.xml
index 3313066a..d99c16bf 100644
--- a/Resources/services/components/mixed.xml
+++ b/Resources/services/components/mixed.xml
@@ -206,7 +206,8 @@
+
-
\ No newline at end of file
+
diff --git a/Resources/services/services.xml b/Resources/services/services.xml
index 935182a9..25edaf62 100644
--- a/Resources/services/services.xml
+++ b/Resources/services/services.xml
@@ -16,6 +16,10 @@
+
+ %mollie_shopware.plugin_name%
+
-
\ No newline at end of file
+
diff --git a/Services/IsMolliePaymentValidator.php b/Services/IsMolliePaymentValidator.php
new file mode 100644
index 00000000..6b46430b
--- /dev/null
+++ b/Services/IsMolliePaymentValidator.php
@@ -0,0 +1,36 @@
+pluginName = $pluginName;
+ }
+
+ /**
+ * @param Payment $payment
+ * @return bool
+ */
+ public function validate(Payment $payment)
+ {
+ /** @var null|Plugin $plugin */
+ $plugin = $payment->getPlugin();
+
+ if (!($plugin instanceof Plugin)) {
+ return false;
+ }
+
+ return $plugin->getName() === $this->pluginName;
+ }
+}
diff --git a/Subscriber/StockSubscriber.php b/Subscriber/StockSubscriber.php
index b7eb8811..bd56a485 100644
--- a/Subscriber/StockSubscriber.php
+++ b/Subscriber/StockSubscriber.php
@@ -4,7 +4,7 @@
use Enlight\Event\SubscriberInterface;
use Enlight_Event_EventArgs;
-use Enlight_Hook_HookArgs;
+use function in_array;
use MollieShopware\Components\Services\StockService;
use Shopware\Components\Model\ModelManager;
use Shopware\Models\Order\Order;
@@ -12,6 +12,11 @@
class StockSubscriber implements SubscriberInterface
{
+ const PAYMENT_STATE_FOR_STOCK_INCREASE = [
+ Status::PAYMENT_STATE_COMPLETELY_PAID,
+ Status::PAYMENT_STATE_THE_PAYMENT_HAS_BEEN_ORDERED,
+ ];
+
/**
* @var StockService
*/
@@ -42,7 +47,7 @@ public function increaseStocks(Enlight_Event_EventArgs $eventArgs)
$orderId = (int)$eventArgs->get('orderId');
$paymentStatusId = (int)$eventArgs->get('paymentStatusId');
- if ($paymentStatusId !== Status::PAYMENT_STATE_COMPLETELY_PAID) {
+ if (!in_array($paymentStatusId, self::PAYMENT_STATE_FOR_STOCK_INCREASE, true)) {
return;
}
@@ -74,7 +79,13 @@ public function entityEvent(Enlight_Event_EventArgs $eventArgs)
if ($oldId === $newId) {
return;
}
- if ($newId !== Status::PAYMENT_STATE_COMPLETELY_PAID) {
+
+ if ($oldId === Status::PAYMENT_STATE_THE_PAYMENT_HAS_BEEN_ORDERED) {
+ // stock was already updated so we may not update it again
+ return;
+ }
+
+ if (!in_array($newId, self::PAYMENT_STATE_FOR_STOCK_INCREASE, true)) {
return;
}
diff --git a/Tests/PHPUnit/Services/IsMolliePaymentValidatorTest.php b/Tests/PHPUnit/Services/IsMolliePaymentValidatorTest.php
new file mode 100644
index 00000000..972113cc
--- /dev/null
+++ b/Tests/PHPUnit/Services/IsMolliePaymentValidatorTest.php
@@ -0,0 +1,57 @@
+isMolliePaymentValidator = new IsMolliePaymentValidator('MollieShopware');
+ }
+
+ /**
+ * @dataProvider validateDataProvider
+ */
+ public function testValidate(Payment $payment, bool $expected)
+ {
+ $this->assertSame($expected, $this->isMolliePaymentValidator->validate($payment));
+ }
+
+ public static function validateDataProvider()
+ {
+ $molliePlugin = new Plugin();
+ $molliePlugin->setName('MollieShopware');
+
+ $prepayment = new Payment();
+ $prepayment->setName('prepayment');
+
+ $invoice = new Payment();
+ $invoice->setName('invoice');
+
+ $creditCard = new Payment();
+ $creditCard->setName(MollieShopware::PAYMENT_PREFIX . 'credit_card');
+ $creditCard->setPlugin($molliePlugin);
+
+ $klarnaPayNow = new Payment();
+ $klarnaPayNow->setName(MollieShopware::PAYMENT_PREFIX . 'klarna_pay_now');
+ $klarnaPayNow->setPlugin($molliePlugin);
+
+ return [
+ [$prepayment, false],
+ [$invoice, false],
+ [$creditCard, true],
+ [$klarnaPayNow, true],
+ ];
+ }
+}
diff --git a/Tests/PHPUnit/Subscriber/StockSubscriberTest.php b/Tests/PHPUnit/Subscriber/StockSubscriberTest.php
new file mode 100644
index 00000000..231d6ce2
--- /dev/null
+++ b/Tests/PHPUnit/Subscriber/StockSubscriberTest.php
@@ -0,0 +1,209 @@
+assertSame($expected, StockSubscriber::PAYMENT_STATE_FOR_STOCK_INCREASE);
+ }
+
+ public function testGetSubscribedEvents()
+ {
+ $expected = [
+ 'Shopware_Modules_Order_SaveOrder_OrderCreated' => 'resetStocks',
+ 'sOrder::setPaymentStatus::after' => 'increaseStocks',
+ 'Shopware\Models\Order\Order::postUpdate' => 'entityEvent',
+ ];
+
+ $this->assertSame($expected, StockSubscriber::getSubscribedEvents());
+ }
+
+ public function testResetStocks()
+ {
+ $orderId = 123;
+
+ $stockServiceMock = $this->createMock(StockService::class);
+ $stockServiceMock->expects(self::once())->method('updateOrderStocks')->with($orderId, true);
+
+ $event = new Enlight_Event_EventArgs([
+ 'orderId' => $orderId,
+ ]);
+
+ $stockSubscriber = new StockSubscriber($stockServiceMock);
+ $stockSubscriber->resetStocks($event);
+ }
+
+ /**
+ * @dataProvider increaseStocksDataProvider
+ * @param mixed $paymentStatusId
+ * @param mixed $methodIsExpectedToBeCalled
+ */
+ public function testIncreaseStocks($paymentStatusId, $methodIsExpectedToBeCalled)
+ {
+ $orderId = 123;
+
+ $expectedExecutionCount = $methodIsExpectedToBeCalled ? self::once() : self::never();
+
+ $stockServiceMock = $this->createMock(StockService::class);
+ $stockServiceMock->expects($expectedExecutionCount)->method('updateOrderStocks')->with($orderId, false);
+
+ $event = new Enlight_Event_EventArgs([
+ 'orderId' => $orderId,
+ 'paymentStatusId' => $paymentStatusId,
+ ]);
+
+ $stockSubscriber = new StockSubscriber($stockServiceMock);
+ $stockSubscriber->increaseStocks($event);
+ }
+
+ public static function increaseStocksDataProvider()
+ {
+ return [
+ [Status::PAYMENT_STATE_PARTIALLY_INVOICED, false],
+ [Status::PAYMENT_STATE_COMPLETELY_INVOICED, false],
+ [Status::PAYMENT_STATE_PARTIALLY_PAID, false],
+ [Status::PAYMENT_STATE_COMPLETELY_PAID, true],
+ [Status::PAYMENT_STATE_1ST_REMINDER, false],
+ [Status::PAYMENT_STATE_2ND_REMINDER, false],
+ [Status::PAYMENT_STATE_3RD_REMINDER, false],
+ [Status::PAYMENT_STATE_ENCASHMENT, false],
+ [Status::PAYMENT_STATE_OPEN, false],
+ [Status::PAYMENT_STATE_RESERVED, false],
+ [Status::PAYMENT_STATE_DELAYED, false],
+ [Status::PAYMENT_STATE_RE_CREDITING, false],
+ [Status::PAYMENT_STATE_REVIEW_NECESSARY, false],
+ [Status::PAYMENT_STATE_NO_CREDIT_APPROVED, false],
+ [Status::PAYMENT_STATE_THE_CREDIT_HAS_BEEN_PRELIMINARILY_ACCEPTED, false],
+ [Status::PAYMENT_STATE_THE_CREDIT_HAS_BEEN_ACCEPTED, false],
+ [Status::PAYMENT_STATE_THE_PAYMENT_HAS_BEEN_ORDERED, true],
+ [Status::PAYMENT_STATE_A_TIME_EXTENSION_HAS_BEEN_REGISTERED, false],
+ [Status::PAYMENT_STATE_THE_PROCESS_HAS_BEEN_CANCELLED, false],
+ ];
+ }
+
+ public function testEntityEventPaymentStatusHasntChanged()
+ {
+ $stockServiceMock = $this->createMock(StockService::class);
+ $stockServiceMock->expects(self::never())->method('updateOrderStocks');
+
+ $unitOfWorkMock = $this->createMock(UnitOfWork::class);
+ $unitOfWorkMock->method('getEntityChangeSet')->willReturn([
+ 'foo' => 'bar',
+ ]);
+
+ $entityManagerMock = $this->createMock(EntityManagerInterface::class);
+ $entityManagerMock->method('getUnitOfWork')->willReturn($unitOfWorkMock);
+
+ $event = new Enlight_Event_EventArgs([
+ 'entityManager' => $entityManagerMock,
+ 'entity' => new Order(),
+ ]);
+
+ $stockSubscriber = new StockSubscriber($stockServiceMock);
+ $stockSubscriber->entityEvent($event);
+ }
+
+ /**
+ * @dataProvider entityEventDataProvider
+ * @param mixed $methodIsExpectedToBeCalled
+ */
+ public function testEntityEventOldPaymentStatusIsNewPaymentStatus(array $changeSet, $methodIsExpectedToBeCalled)
+ {
+ $orderId = 123;
+ $expectedExecutionCount = $methodIsExpectedToBeCalled ? self::once() : self::never();
+
+ $stockServiceMock = $this->createMock(StockService::class);
+ $stockServiceMock->expects($expectedExecutionCount)->method('updateOrderStocks')->with($orderId, false);
+
+ $unitOfWorkMock = $this->createMock(UnitOfWork::class);
+ $unitOfWorkMock->method('getEntityChangeSet')->willReturn($changeSet);
+
+ $entityManagerMock = $this->createMock(EntityManagerInterface::class);
+ $entityManagerMock->method('getUnitOfWork')->willReturn($unitOfWorkMock);
+
+ $order = new Order();
+ $reflection = new ReflectionObject($order);
+ $reflectionProperty = $reflection->getProperty('id');
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($order, $orderId);
+
+ $event = new Enlight_Event_EventArgs([
+ 'entityManager' => $entityManagerMock,
+ 'entity' => $order,
+ ]);
+
+ $stockSubscriber = new StockSubscriber($stockServiceMock);
+ $stockSubscriber->entityEvent($event);
+ }
+
+ public static function entityEventDataProvider()
+ {
+ return [
+ 'emptyChangeSet' => [
+ [],
+ false,
+ ],
+ 'old id is new id' => [
+ [
+ 'paymentStatus' => [
+ self::getPaymentStatus(Status::PAYMENT_STATE_COMPLETELY_PAID),
+ self::getPaymentStatus(Status::PAYMENT_STATE_COMPLETELY_PAID),
+ ],
+ ],
+ false,
+ ],
+ 'old status is payment has been ordered' => [
+ [
+ 'paymentStatus' => [
+ self::getPaymentStatus(Status::PAYMENT_STATE_THE_PAYMENT_HAS_BEEN_ORDERED),
+ self::getPaymentStatus(Status::PAYMENT_STATE_COMPLETELY_PAID),
+ ],
+ ],
+ false,
+ ],
+ 'new status is not completely paid' => [
+ [
+ 'paymentStatus' => [
+ self::getPaymentStatus(Status::PAYMENT_STATE_OPEN),
+ self::getPaymentStatus(Status::PAYMENT_STATE_PARTIALLY_PAID),
+ ],
+ ],
+ false,
+ ],
+ 'completely paid, update stocks' => [
+ [
+ 'paymentStatus' => [
+ self::getPaymentStatus(Status::PAYMENT_STATE_OPEN),
+ self::getPaymentStatus(Status::PAYMENT_STATE_COMPLETELY_PAID),
+ ],
+ ],
+ true,
+ ],
+ ];
+ }
+
+ private static function getPaymentStatus($paymentStatusId)
+ {
+ $paymentStatus = new Status();
+ $paymentStatus->setId($paymentStatusId);
+
+ return $paymentStatus;
+ }
+}