diff --git a/Model/Client/Orders/Processors/SuccessfulPayment.php b/Model/Client/Orders/Processors/SuccessfulPayment.php index c6f9a16d329..3556fa16eac 100644 --- a/Model/Client/Orders/Processors/SuccessfulPayment.php +++ b/Model/Client/Orders/Processors/SuccessfulPayment.php @@ -24,6 +24,7 @@ use Mollie\Payment\Model\Client\ProcessTransactionResponse; use Mollie\Payment\Model\Client\ProcessTransactionResponseFactory; use Mollie\Payment\Service\Order\OrderCommentHistory; +use Mollie\Payment\Service\Order\ProcessCaptures; use Mollie\Payment\Service\Order\SendOrderEmails; use Mollie\Payment\Service\Order\TransactionProcessor; @@ -78,6 +79,10 @@ class SuccessfulPayment implements OrderProcessorInterface * @var SendOrderEmails */ private $sendOrderEmails; + /** + * @var ProcessCaptures + */ + private $processCaptures; public function __construct( ProcessTransactionResponseFactory $processTransactionResponseFactory, @@ -89,7 +94,8 @@ public function __construct( TransactionProcessor $transactionProcessor, OrderCommentHistory $orderCommentHistory, OrderRepositoryInterface $orderRepository, - SendOrderEmails $sendOrderEmails + SendOrderEmails $sendOrderEmails, + ProcessCaptures $processCaptures ) { $this->processTransactionResponseFactory = $processTransactionResponseFactory; $this->request = $request; @@ -101,6 +107,7 @@ public function __construct( $this->orderCommentHistory = $orderCommentHistory; $this->orderRepository = $orderRepository; $this->sendOrderEmails = $sendOrderEmails; + $this->processCaptures = $processCaptures; } /** @@ -142,6 +149,10 @@ public function process(OrderInterface $order, Order $mollieOrder, string $type, $this->sendOrderEmails($order); } + if ($payment && $mollieOrder->amountCaptured !== null && $mollieOrder->amountCaptured->value != '0.00') { + $this->processCaptures->execute($order, $payment->captures()); + } + $result = ['success' => true, 'status' => $mollieOrder->status, 'order_id' => $orderId, 'type' => $type]; $this->mollieHelper->addTolog('success', $result); $this->checkCheckoutSession($order, $mollieOrder, $type); diff --git a/Model/Client/Payments.php b/Model/Client/Payments.php index 1070a0d5a52..02632f72845 100644 --- a/Model/Client/Payments.php +++ b/Model/Client/Payments.php @@ -30,6 +30,7 @@ use Mollie\Payment\Service\Order\CancelOrder; use Mollie\Payment\Service\Order\OrderCommentHistory; use Mollie\Payment\Service\Order\ExpiredOrderToTransaction; +use Mollie\Payment\Service\Order\ProcessCaptures; use Mollie\Payment\Service\Order\SaveAdditionalInformationDetails; use Mollie\Payment\Service\Order\SendOrderEmails; use Mollie\Payment\Service\Order\Transaction; @@ -143,6 +144,10 @@ class Payments extends AbstractModel * @var MethodCode */ private $methodCode; + /** + * @var ProcessCaptures + */ + private $processCaptures; public function __construct( OrderRepository $orderRepository, @@ -165,7 +170,8 @@ public function __construct( SaveAdditionalInformationDetails $saveAdditionalInformationDetails, ExpiredOrderToTransaction $expiredOrderToTransaction, CanRegisterCaptureNotification $canRegisterCaptureNotification, - MethodCode $methodCode + MethodCode $methodCode, + ProcessCaptures $processCaptures ) { $this->orderRepository = $orderRepository; $this->checkoutSession = $checkoutSession; @@ -188,6 +194,7 @@ public function __construct( $this->expiredOrderToTransaction = $expiredOrderToTransaction; $this->canRegisterCaptureNotification = $canRegisterCaptureNotification; $this->methodCode = $methodCode; + $this->processCaptures = $processCaptures; } /** @@ -423,6 +430,10 @@ public function processTransaction(Order $order, $mollieApi, $type = 'webhook', } } + if ($paymentData->amountCaptured !== null && $paymentData->amountCaptured->value != '0.00') { + $this->processCaptures->execute($order, $paymentData->captures()); + } + if (!$order->getIsVirtual()) { $defaultStatusProcessing = $this->mollieHelper->getStatusProcessing($storeId); if ($defaultStatusProcessing && ($defaultStatusProcessing != $order->getStatus())) { diff --git a/Model/Client/Payments/CapturePayment.php b/Model/Client/Payments/CapturePayment.php index 858158d7150..73b1e354bd7 100644 --- a/Model/Client/Payments/CapturePayment.php +++ b/Model/Client/Payments/CapturePayment.php @@ -1,4 +1,8 @@ mollieApiClient = $mollieApiClient; + $this->usedMollieApi = $usedMollieApi; $this->partialInvoice = $partialInvoice; $this->mollieHelper = $mollieHelper; $this->orderRepository = $orderRepository; @@ -73,22 +91,25 @@ public function __construct( $this->orderCommentHistory = $orderCommentHistory; $this->shouldEmailInvoice = $shouldEmailInvoice; $this->price = $price; + $this->invoiceRepository = $invoiceRepository; } public function execute(InvoiceInterface $invoice): void { + // Otherwise the ID isn't available yet + $this->invoiceRepository->save($invoice); + $order = $invoice->getOrder(); $payment = $order->getPayment(); $order->setState(Order::STATE_PAYMENT_REVIEW); $status = $order->getConfig()->getStateDefaultStatus(Order::STATE_PAYMENT_REVIEW); - $captureAmount = $invoice->getBaseGrandTotal(); + $captureAmount = $invoice->getGrandTotal(); - $mollieTransactionId = $order->getMollieTransactionId(); $mollieApi = $this->mollieApiClient->loadByStore($order->getStoreId()); - $data = []; + $data = ['metadata' => ['invoice_id' => $invoice->getEntityId()]]; if ($captureAmount != $order->getBaseGrandTotal()) { $data['amount'] = $this->mollieHelper->getAmountArray( $order->getOrderCurrencyCode(), @@ -96,7 +117,7 @@ public function execute(InvoiceInterface $invoice): void ); } - $capture = $mollieApi->paymentCaptures->createForId($mollieTransactionId, $data); + $capture = $this->createCapture($mollieApi, $order, $data); $payment->setTransactionId($capture->id); $order->addCommentToStatusHistory( @@ -108,4 +129,19 @@ public function execute(InvoiceInterface $invoice): void $status ); } + + private function createCapture(\Mollie\Api\MollieApiClient $mollieApi, OrderInterface $order, array $data): \Mollie\Api\Resources\Capture + { + $mollieTransactionId = $order->getMollieTransactionId(); + if ($this->usedMollieApi->execute($order) == UsedMollieApi::TYPE_PAYMENTS) { + return $mollieApi->paymentCaptures->createForId($mollieTransactionId, $data); + } + + $mollieOrder = $mollieApi->orders->get($mollieTransactionId); + $payments = $mollieOrder->payments(); + /** @var Payment $last */ + $last = end($payments); + + return $mollieApi->paymentCaptures->createForId($last->id, $data); + } } diff --git a/Model/Client/Payments/Processors/SuccessfulPayment.php b/Model/Client/Payments/Processors/SuccessfulPayment.php index df853ebc5f2..94359c85e5f 100644 --- a/Model/Client/Payments/Processors/SuccessfulPayment.php +++ b/Model/Client/Payments/Processors/SuccessfulPayment.php @@ -19,6 +19,7 @@ use Mollie\Payment\Service\Mollie\Order\CanRegisterCaptureNotification; use Mollie\Payment\Service\Order\OrderAmount; use Mollie\Payment\Service\Order\OrderCommentHistory; +use Mollie\Payment\Service\Order\ProcessCaptures; use Mollie\Payment\Service\Order\SendOrderEmails; use Mollie\Payment\Service\Order\TransactionProcessor; use Mollie\Payment\Service\Order\Uncancel; @@ -69,6 +70,10 @@ class SuccessfulPayment implements PaymentProcessorInterface * @var CanRegisterCaptureNotification */ private $canRegisterCaptureNotification; + /** + * @var ProcessCaptures + */ + private $processCaptures; public function __construct( ProcessTransactionResponseFactory $processTransactionResponseFactory, @@ -79,7 +84,8 @@ public function __construct( General $mollieHelper, OrderRepositoryInterface $orderRepository, SendOrderEmails $sendOrderEmails, - CanRegisterCaptureNotification $canRegisterCaptureNotification + CanRegisterCaptureNotification $canRegisterCaptureNotification, + ProcessCaptures $processCaptures ) { $this->processTransactionResponseFactory = $processTransactionResponseFactory; $this->orderAmount = $orderAmount; @@ -90,6 +96,7 @@ public function __construct( $this->orderRepository = $orderRepository; $this->sendOrderEmails = $sendOrderEmails; $this->canRegisterCaptureNotification = $canRegisterCaptureNotification; + $this->processCaptures = $processCaptures; } public function process( @@ -200,6 +207,10 @@ private function handlePayment(OrderInterface $magentoOrder, Payment $molliePaym } } + if ($molliePayment->amountCaptured !== null && $molliePayment->amountCaptured->value != '0.00') { + $this->processCaptures->execute($magentoOrder, $molliePayment->captures()); + } + if (!$magentoOrder->getIsVirtual()) { $defaultStatusProcessing = $this->mollieHelper->getStatusProcessing($magentoOrder->getStoreId()); if ($defaultStatusProcessing && ($defaultStatusProcessing != $magentoOrder->getStatus())) { diff --git a/Observer/SalesOrderInvoiceRegister/CaptureInvoice.php b/Observer/SalesOrderInvoiceRegister/CaptureInvoice.php index 02a2f778ffa..e7905668c20 100644 --- a/Observer/SalesOrderInvoiceRegister/CaptureInvoice.php +++ b/Observer/SalesOrderInvoiceRegister/CaptureInvoice.php @@ -12,17 +12,11 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Sales\Api\Data\InvoiceInterface; use Magento\Sales\Api\Data\OrderInterface; -use Mollie\Payment\Config; use Mollie\Payment\Model\Client\Payments\CapturePayment; use Mollie\Payment\Service\Mollie\Order\CanUseManualCapture; -use Mollie\Payment\Service\Mollie\Order\UsedMollieApi; class CaptureInvoice implements ObserverInterface { - /** - * @var Config - */ - private $config; /** * @var CapturePayment */ @@ -31,30 +25,20 @@ class CaptureInvoice implements ObserverInterface * @var CanUseManualCapture */ private $canUseManualCapture; - /** - * @var UsedMollieApi - */ - private $usedMollieApi; public function __construct( - Config $config, CapturePayment $capturePayment, - CanUseManualCapture $canUseManualCapture, - UsedMollieApi $usedMollieApi + CanUseManualCapture $canUseManualCapture ) { $this->capturePayment = $capturePayment; - $this->config = $config; $this->canUseManualCapture = $canUseManualCapture; - $this->usedMollieApi = $usedMollieApi; } public function execute(Observer $observer) { /** @var OrderInterface $order */ $order = $observer->getData('order'); - if ($this->usedMollieApi->execute($order) == UsedMollieApi::TYPE_ORDERS || - !$this->canUseManualCapture->execute($order) - ) { + if (!$this->canUseManualCapture->execute($order)) { return; } diff --git a/Observer/SalesOrderShipmentSaveBefore/CreateInvoice.php b/Observer/SalesOrderShipmentSaveBefore/CreateInvoice.php new file mode 100644 index 00000000000..51423a922fa --- /dev/null +++ b/Observer/SalesOrderShipmentSaveBefore/CreateInvoice.php @@ -0,0 +1,103 @@ +config = $config; + $this->usedMollieApi = $usedMollieApi; + $this->partialInvoice = $partialInvoice; + $this->orderRepository = $orderRepository; + $this->shouldEmailInvoice = $shouldEmailInvoice; + $this->invoiceSender = $invoiceSender; + $this->orderCommentHistory = $orderCommentHistory; + } + + public function execute(Observer $observer) + { + /** @var \Magento\Sales\Model\Order\Shipment $shipment */ + $shipment = $observer->getEvent()->getShipment(); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $shipment->getOrder(); + + if ($this->config->getInvoiceMoment($order->getStoreId()) != InvoiceMoment::ON_SHIPMENT || + $this->usedMollieApi->execute($order) != UsedMollieApi::TYPE_PAYMENTS + ) { + return; + } + + $payment = $order->getPayment(); + if ($payment->getMethod() != Creditcard::CODE || $payment->getIsTransactionClosed()) { + return; + } + + $invoice = $this->partialInvoice->createFromShipment($shipment); + + $this->orderRepository->save($order); + + $sendInvoice = $this->shouldEmailInvoice->execute((int)$order->getStoreId(), $payment->getMethod()); + if ($invoice && $invoice->getId() && !$invoice->getEmailSent() && $sendInvoice) { + $this->invoiceSender->send($invoice); + $message = __('Notified customer about invoice #%1', $invoice->getIncrementId()); + $this->orderCommentHistory->add($order, $message, true); + } + } +} diff --git a/Service/Mollie/Order/CreateInvoiceOnShipment.php b/Service/Mollie/Order/CreateInvoiceOnShipment.php index 0cbfa2e431e..ea77c558c8e 100644 --- a/Service/Mollie/Order/CreateInvoiceOnShipment.php +++ b/Service/Mollie/Order/CreateInvoiceOnShipment.php @@ -15,6 +15,7 @@ public function execute(OrderInterface $order): bool $methodCode = $order->getPayment()->getMethod(); if (in_array($methodCode, [ 'mollie_methods_billie', + 'mollie_methods_creditcard', 'mollie_methods_in3', 'mollie_methods_klarna', 'mollie_methods_klarnapaylater', diff --git a/Service/Order/ProcessCaptures.php b/Service/Order/ProcessCaptures.php new file mode 100644 index 00000000000..e7f6e0b145c --- /dev/null +++ b/Service/Order/ProcessCaptures.php @@ -0,0 +1,90 @@ +transactionBuilderFactory = $transactionBuilderFactory; + $this->transactionManager = $transactionManager; + $this->invoiceRepository = $invoiceRepository; + $this->config = $config; + } + + public function execute(OrderInterface $order, CaptureCollection $captures): void + { + if (!$this->config->useManualCapture($order->getStoreId())) { + return; + } + + foreach ($captures as $capture) { + $this->handle($order, $capture); + } + } + + private function handle(OrderInterface $order, Capture $capture): void + { + $id = $capture->id; + + if ($this->transactionManager->isTransactionExists($id, $order->getPayment()->getId(), $order->getId())) { + return; + } + + $this->transactionBuilderFactory->create() + ->setPayment($order->getPayment()) + ->setOrder($order) + ->setTransactionId($id) + ->setAdditionalInformation(['capture_id' => $id]) + ->setFailSafe(true) + ->build(TransactionInterface::TYPE_CAPTURE); + + try { + $invoice = $this->invoiceRepository->get($capture->metadata->invoice_id); + $invoice->setState(Invoice::STATE_PAID); + $this->invoiceRepository->save($invoice); + } catch (NoSuchEntityException $exception) { + // No invoice found + } + + $order->getPayment()->registerCaptureNotification($capture->amount->value, true); + } +} diff --git a/etc/events.xml b/etc/events.xml index 6c9df6b8668..8a4e9cdec61 100644 --- a/etc/events.xml +++ b/etc/events.xml @@ -1,4 +1,9 @@ + + @@ -9,6 +14,7 @@ +